1 /*
2 payload_type.c
3 Copyright (C) 2017 Belledonne Communications SARL
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include <string.h>
21 #include <ortp/payloadtype.h>
22 #include "linphone/payload_type.h"
23 #include "private.h"
24
25 struct _LinphonePayloadType {
26 belle_sip_object_t base;
27 OrtpPayloadType *pt;
28 LinphoneCore *lc;
29 };
30
31 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePayloadType);
32 BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePayloadType);
33
linphone_payload_type_new(LinphoneCore * lc,OrtpPayloadType * ortp_pt)34 LinphonePayloadType *linphone_payload_type_new(LinphoneCore *lc, OrtpPayloadType *ortp_pt) {
35 LinphonePayloadType *pt;
36 if (ortp_pt == NULL) return NULL;
37 pt = belle_sip_object_new(LinphonePayloadType);
38 pt->pt = ortp_pt;
39 pt->lc = lc;
40 return pt;
41 }
42
linphone_payload_type_ref(LinphonePayloadType * pt)43 LinphonePayloadType *linphone_payload_type_ref(LinphonePayloadType *pt) {
44 return (LinphonePayloadType *)belle_sip_object_ref(pt);
45 }
46
linphone_payload_type_unref(LinphonePayloadType * pt)47 void linphone_payload_type_unref(LinphonePayloadType *pt) {
48 belle_sip_object_unref(pt);
49 }
50
linphone_payload_type_get_type(const LinphonePayloadType * pt)51 int linphone_payload_type_get_type(const LinphonePayloadType *pt) {
52 return pt->pt->type;
53 }
54
_payload_type_is_in_core(const OrtpPayloadType * pt,const LinphoneCore * lc)55 static bool_t _payload_type_is_in_core(const OrtpPayloadType *pt, const LinphoneCore *lc) {
56 return (bctbx_list_find(lc->codecs_conf.audio_codecs, pt) != NULL)
57 || (bctbx_list_find(lc->codecs_conf.video_codecs, pt) != NULL)
58 || (bctbx_list_find(lc->codecs_conf.text_codecs, pt) != NULL);
59 }
60
_payload_type_get_description(const OrtpPayloadType * pt)61 static char *_payload_type_get_description(const OrtpPayloadType *pt) {
62 return bctbx_strdup_printf("%s/%d/%d", pt->mime_type, pt->clock_rate, pt->channels);
63 }
64
_linphone_core_enable_payload_type(LinphoneCore * lc,OrtpPayloadType * pt,bool_t enabled)65 static int _linphone_core_enable_payload_type(LinphoneCore *lc, OrtpPayloadType *pt, bool_t enabled) {
66 payload_type_set_enable(pt,enabled);
67 _linphone_core_codec_config_write(lc);
68 linphone_core_update_allocated_audio_bandwidth(lc);
69 return 0;
70 }
71
linphone_core_enable_payload_type(LinphoneCore * lc,OrtpPayloadType * pt,bool_t enabled)72 LinphoneStatus linphone_core_enable_payload_type(LinphoneCore *lc, OrtpPayloadType *pt, bool_t enabled){
73 if (!_payload_type_is_in_core(pt, lc)) {
74 char *desc = _payload_type_get_description(pt);
75 ms_error("cannot enable '%s' payload type: not in the core", desc);
76 bctbx_free(desc);
77 return -1;
78 }
79 return _linphone_core_enable_payload_type(lc, pt, enabled);
80 }
81
linphone_payload_type_enable(LinphonePayloadType * pt,bool_t enabled)82 int linphone_payload_type_enable(LinphonePayloadType *pt, bool_t enabled) {
83 if (pt->lc == NULL) {
84 char *desc = linphone_payload_type_get_description(pt);
85 ms_error("cannot enable '%s' payload type: no core associated", desc);
86 bctbx_free(desc);
87 return -1;
88 }
89 return _linphone_core_enable_payload_type(pt->lc, pt->pt, enabled);
90 }
91
linphone_core_payload_type_enabled(const LinphoneCore * lc,const OrtpPayloadType * pt)92 bool_t linphone_core_payload_type_enabled(const LinphoneCore *lc, const OrtpPayloadType *pt){
93 return payload_type_enabled(pt);
94 }
95
linphone_payload_type_enabled(const LinphonePayloadType * pt)96 bool_t linphone_payload_type_enabled(const LinphonePayloadType *pt) {
97 return payload_type_enabled(pt->pt);
98 }
99
linphone_payload_type_get_description(const LinphonePayloadType * pt)100 char *linphone_payload_type_get_description(const LinphonePayloadType *pt) {
101 return _payload_type_get_description(pt->pt);
102 }
103
_linphone_core_get_payload_type_codec_description(const LinphoneCore * lc,const OrtpPayloadType * pt)104 static const char *_linphone_core_get_payload_type_codec_description(const LinphoneCore *lc, const OrtpPayloadType *pt) {
105 if (ms_factory_codec_supported(lc->factory, pt->mime_type)){
106 MSFilterDesc *desc=ms_factory_get_encoder(lc->factory, pt->mime_type);
107 #ifdef ENABLE_NLS
108 return dgettext("mediastreamer",desc->text);
109 #else
110 return desc->text;
111 #endif
112 }
113 return NULL;
114 }
115
linphone_core_get_payload_type_description(LinphoneCore * lc,const OrtpPayloadType * pt)116 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, const OrtpPayloadType *pt){
117 if (!_payload_type_is_in_core(pt, lc)) {
118 char *desc = _payload_type_get_description(pt);
119 ms_error("cannot get codec description for '%s' payload type: not in the core", desc);
120 bctbx_free(desc);
121 return NULL;
122 }
123 return _linphone_core_get_payload_type_codec_description(lc, pt);
124 }
125
linphone_payload_type_get_encoder_description(const LinphonePayloadType * pt)126 const char *linphone_payload_type_get_encoder_description(const LinphonePayloadType *pt) {
127 if (pt->lc == NULL) {
128 char *desc = linphone_payload_type_get_description(pt);
129 ms_error("cannot get codec description for '%s' payload type: no associated core", desc);
130 bctbx_free(desc);
131 return NULL;
132 }
133 return _linphone_core_get_payload_type_codec_description(pt->lc, pt->pt);
134 }
135
_linphone_core_get_payload_type_normal_bitrate(const LinphoneCore * lc,const OrtpPayloadType * pt)136 static int _linphone_core_get_payload_type_normal_bitrate(const LinphoneCore *lc, const OrtpPayloadType *pt) {
137 int maxbw = get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
138 linphone_core_get_upload_bandwidth(lc));
139 if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED){
140 return get_audio_payload_bandwidth(lc, pt, maxbw);
141 }else if (pt->type==PAYLOAD_VIDEO){
142 int video_bw;
143 if (maxbw<=0) {
144 video_bw=1500; /*default bitrate for video stream when no bandwidth limit is set, around 1.5 Mbit/s*/
145 }else{
146 video_bw=get_remaining_bandwidth_for_video(maxbw,lc->audio_bw);
147 }
148 return video_bw;
149 }
150 return 0;
151 }
152
linphone_core_get_payload_type_bitrate(LinphoneCore * lc,const OrtpPayloadType * pt)153 int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const OrtpPayloadType *pt){
154 if (_payload_type_is_in_core(pt, lc)) {
155 return _linphone_core_get_payload_type_normal_bitrate(lc, pt);
156 } else {
157 char *desc = _payload_type_get_description(pt);
158 ms_error("cannot get normal bitrate of payload type '%s': not in the core", desc);
159 bctbx_free(desc);
160 return -1;
161 }
162 }
163
linphone_payload_type_get_normal_bitrate(const LinphonePayloadType * pt)164 int linphone_payload_type_get_normal_bitrate(const LinphonePayloadType *pt) {
165 if (pt->lc == NULL) {
166 char *desc = linphone_payload_type_get_description(pt);
167 ms_error("cannot get normal bitrate of codec '%s': no associated core", desc);
168 bctbx_free(desc);
169 return -1;
170 }
171 return _linphone_core_get_payload_type_normal_bitrate(pt->lc, pt->pt);
172 }
173
_linphone_core_set_payload_type_normal_bitrate(LinphoneCore * lc,OrtpPayloadType * pt,int bitrate)174 static void _linphone_core_set_payload_type_normal_bitrate(LinphoneCore *lc, OrtpPayloadType *pt, int bitrate) {
175 if (pt->type==PAYLOAD_VIDEO || pt->flags & PAYLOAD_TYPE_IS_VBR){
176 pt->normal_bitrate=bitrate*1000;
177 pt->flags|=PAYLOAD_TYPE_BITRATE_OVERRIDE;
178 linphone_core_update_allocated_audio_bandwidth(lc);
179 }else{
180 char *desc = _payload_type_get_description(pt);
181 ms_error("Cannot set an explicit bitrate for codec '%s', because it is not VBR.",desc);
182 bctbx_free(desc);
183 }
184 }
185
linphone_core_set_payload_type_bitrate(LinphoneCore * lc,OrtpPayloadType * pt,int bitrate)186 void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, OrtpPayloadType *pt, int bitrate) {
187 if (_payload_type_is_in_core(pt, lc)) {
188 _linphone_core_set_payload_type_normal_bitrate(lc, pt, bitrate);
189 } else {
190 char *desc = _payload_type_get_description(pt);
191 ms_error("cannot set normal bitrate of codec '%s': not in the core", desc);
192 bctbx_free(desc);
193 }
194 }
195
linphone_payload_type_set_normal_bitrate(LinphonePayloadType * pt,int bitrate)196 void linphone_payload_type_set_normal_bitrate(LinphonePayloadType *pt, int bitrate) {
197 if (pt->lc == NULL) {
198 ms_error("cannot set bitrate of codec %s/%d: no associated core", pt->pt->mime_type, pt->pt->clock_rate);
199 return;
200 }
201 _linphone_core_set_payload_type_normal_bitrate(pt->lc, pt->pt, bitrate);
202 }
203
linphone_payload_type_get_mime_type(const LinphonePayloadType * pt)204 const char *linphone_payload_type_get_mime_type(const LinphonePayloadType *pt) {
205 return pt->pt->mime_type;
206 }
207
linphone_payload_type_get_channels(const LinphonePayloadType * pt)208 int linphone_payload_type_get_channels(const LinphonePayloadType *pt) {
209 return pt->pt->channels;
210 }
211
linphone_core_get_payload_type_number(LinphoneCore * lc,const OrtpPayloadType * pt)212 int linphone_core_get_payload_type_number(LinphoneCore *lc, const OrtpPayloadType *pt) {
213 return payload_type_get_number(pt);
214 }
215
linphone_payload_type_get_number(const LinphonePayloadType * pt)216 int linphone_payload_type_get_number(const LinphonePayloadType *pt) {
217 return payload_type_get_number(pt->pt);
218 }
219
linphone_core_set_payload_type_number(LinphoneCore * lc,OrtpPayloadType * pt,int number)220 void linphone_core_set_payload_type_number(LinphoneCore *lc, OrtpPayloadType *pt, int number) {
221 payload_type_set_number(pt, number);
222 }
223
linphone_payload_type_set_number(LinphonePayloadType * pt,int number)224 void linphone_payload_type_set_number(LinphonePayloadType *pt, int number) {
225 payload_type_set_number(pt->pt, number);
226 }
227
linphone_payload_type_get_recv_fmtp(const LinphonePayloadType * pt)228 const char *linphone_payload_type_get_recv_fmtp(const LinphonePayloadType *pt) {
229 return pt->pt->recv_fmtp;
230 }
231
linphone_payload_type_set_recv_fmtp(LinphonePayloadType * pt,const char * recv_fmtp)232 void linphone_payload_type_set_recv_fmtp(LinphonePayloadType *pt, const char *recv_fmtp) {
233 if (pt->pt->recv_fmtp != NULL) bctbx_free(pt->pt->recv_fmtp);
234 if (recv_fmtp != NULL) pt->pt->recv_fmtp = bctbx_strdup(recv_fmtp);
235 else recv_fmtp = NULL;
236 }
237
linphone_payload_type_get_send_fmtp(const LinphonePayloadType * pt)238 const char *linphone_payload_type_get_send_fmtp(const LinphonePayloadType *pt) {
239 return pt->pt->send_fmtp;
240 }
241
linphone_payload_type_set_send_fmtp(LinphonePayloadType * pt,const char * send_fmtp)242 void linphone_payload_type_set_send_fmtp(LinphonePayloadType *pt, const char *send_fmtp) {
243 if (pt->pt->send_fmtp != NULL) bctbx_free(pt->pt->send_fmtp);
244 if (send_fmtp != NULL) pt->pt->recv_fmtp = bctbx_strdup(send_fmtp);
245 else send_fmtp = NULL;
246 }
247
linphone_payload_type_get_clock_rate(const LinphonePayloadType * pt)248 int linphone_payload_type_get_clock_rate(const LinphonePayloadType *pt) {
249 return pt->pt->clock_rate;
250 }
251
linphone_core_payload_type_is_vbr(const LinphoneCore * lc,const OrtpPayloadType * pt)252 bool_t linphone_core_payload_type_is_vbr(const LinphoneCore *lc, const OrtpPayloadType *pt) {
253 return payload_type_is_vbr(pt);
254 }
255
linphone_payload_type_is_vbr(const LinphonePayloadType * pt)256 bool_t linphone_payload_type_is_vbr(const LinphonePayloadType *pt) {
257 return payload_type_is_vbr(pt->pt);
258 }
259
_linphone_core_check_payload_type_usability(const LinphoneCore * lc,const OrtpPayloadType * pt)260 bool_t _linphone_core_check_payload_type_usability(const LinphoneCore *lc, const OrtpPayloadType *pt) {
261 int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
262 linphone_core_get_upload_bandwidth(lc));
263 return linphone_core_is_payload_type_usable_for_bandwidth(lc, pt, maxbw);
264 }
265
linphone_core_check_payload_type_usability(LinphoneCore * lc,const OrtpPayloadType * pt)266 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const OrtpPayloadType *pt) {
267 if (!_payload_type_is_in_core(pt, lc)) {
268 char *desc = _payload_type_get_description(pt);
269 ms_error("cannot check usability of '%s' payload type: not in the core", desc);
270 bctbx_free(desc);
271 return FALSE;
272 }
273 return _linphone_core_check_payload_type_usability(lc, pt);
274 }
275
linphone_payload_type_is_usable(const LinphonePayloadType * pt)276 bool_t linphone_payload_type_is_usable(const LinphonePayloadType *pt) {
277 if (pt->lc == NULL) {
278 char *desc = linphone_payload_type_get_description(pt);
279 ms_error("cannot check usability of '%s' payload type: no associated core", desc);
280 bctbx_free(desc);
281 return FALSE;
282 }
283 return _linphone_core_check_payload_type_usability(pt->lc, pt->pt);
284 }
285
linphone_payload_type_get_ortp_pt(const LinphonePayloadType * pt)286 OrtpPayloadType *linphone_payload_type_get_ortp_pt(const LinphonePayloadType *pt) {
287 return pt->pt;
288 }
289
290 BELLE_SIP_INSTANCIATE_VPTR(LinphonePayloadType, belle_sip_object_t,
291 NULL, // uninit
292 NULL, // clone
293 NULL, // marshale
294 TRUE // unown
295 );
296