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