1 /*
2  * The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) implementation with additional features.
3  * Copyright (C) 2017 Belledonne Communications SARL
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #include <ortp/telephonyevents.h>
21 #include "utils.h"
22 #include "rtpsession_priv.h"
23 #include <ortp/ortp.h>
24 #include <bctoolbox/port.h>
25 
26 PayloadType	payload_type_telephone_event={
27 	PAYLOAD_AUDIO_PACKETIZED, /*type */
28 	8000,	/*clock rate */
29 	0,		/* bytes per sample N/A */
30 	NULL,	/* zero pattern N/A*/
31 	0,		/*pattern_length N/A */
32 	0,		/*	normal_bitrate */
33 	"telephone-event",	/* MIME subtype */
34 	1,		/* Audio Channels */
35 	0		/*flags */
36 };
37 
38 /**
39  * Tells whether telephony events payload type is supported within the
40  * context of the rtp session.
41  * @param session a rtp session
42  *
43  * @return the payload type number used for telephony events if found, -1 if not found.
44 **/
rtp_session_telephone_events_supported(RtpSession * session)45 int rtp_session_telephone_events_supported(RtpSession *session)
46 {
47 	/* search for a telephony event payload in the current profile */
48 	return rtp_profile_get_payload_number_from_mime(session->snd.profile,"telephone-event");
49 }
50 
rtp_profile_is_telephone_event(const RtpProfile * prof,int pt_num)51 bool_t rtp_profile_is_telephone_event(const RtpProfile *prof, int pt_num){
52 	PayloadType *pt=rtp_profile_get_payload(prof, pt_num);
53 	return pt && strcasecmp(pt->mime_type,"telephone-event")==0;
54 }
55 
56 
57 /**
58  * Tells whether telephone event payload type is supported for send within the
59  * context of the rtp session.
60  * @param session a rtp session
61  *
62  * @return the payload type number used for telephony events if found, -1 if not found.
63 **/
rtp_session_send_telephone_events_supported(RtpSession * session)64 int rtp_session_send_telephone_events_supported(RtpSession *session)
65 {
66 	/* search for a telephony event payload in the current profile */
67 	return rtp_profile_get_payload_number_from_mime(session->snd.profile,"telephone-event");
68 }
69 
70 /**
71  * Tells whether telephone event payload type is supported for receiving within the
72  * context of the rtp session.
73  * @param session a rtp session
74  *
75  * @return the payload type number used for telephony events if found, -1 if not found.
rtp_session_recv_telephone_events_supported(RtpSession * session)76 **/int rtp_session_recv_telephone_events_supported(RtpSession *session)
77 {
78 	/* search for a telephony event payload in the current profile */
79 	return rtp_profile_get_payload_number_from_mime(session->rcv.profile,"telephone-event");
80 }
81 
82 
83 /**
84  *	Allocates a new rtp packet to be used to add named telephony events. The application can use
85  *	then rtp_session_add_telephone_event() to add named events to the packet.
86  *	Finally the packet has to be sent with rtp_session_sendm_with_ts().
87  *
88  * @param session a rtp session.
89  * @param start boolean to indicate if the marker bit should be set.
90  *
91  * @return a message block containing the rtp packet if successfull, NULL if the rtp session
92  * cannot support telephony event (because the rtp profile it is bound to does not include
93  * a telephony event payload type).
94 **/
rtp_session_create_telephone_event_packet(RtpSession * session,int start)95 mblk_t	*rtp_session_create_telephone_event_packet(RtpSession *session, int start)
96 {
97 	mblk_t *mp;
98 	rtp_header_t *rtp;
99 	PayloadType *cur_pt=rtp_profile_get_payload(session->snd.profile, rtp_session_get_send_payload_type(session));
100 	int tev_pt = session->tev_send_pt;
101 
102 	if (tev_pt != -1){
103 		PayloadType *cur_tev_pt=rtp_profile_get_payload(session->snd.profile, tev_pt);
104 		if (!cur_tev_pt){
105 			ortp_error("Undefined telephone-event payload type %i choosen for sending telephone event", tev_pt);
106 			tev_pt = -1;
107 		}else if (cur_pt && cur_tev_pt->clock_rate != cur_pt->clock_rate){
108 			ortp_warning("Telephone-event payload type %i has clockrate %i while main audio codec has clockrate %i: this is not permitted.",
109 				tev_pt, cur_tev_pt->clock_rate, cur_pt->clock_rate);
110 		}
111 	}
112 
113 	if (tev_pt == -1){
114 		tev_pt = rtp_profile_find_payload_number(session->snd.profile, "telephone-event", cur_pt ? cur_pt->clock_rate : 8000, 1);
115 	}
116 	return_val_if_fail(tev_pt!=-1,NULL);
117 
118 	mp=allocb(RTP_FIXED_HEADER_SIZE+TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED);
119 	if (mp==NULL) return NULL;
120 	rtp=(rtp_header_t*)mp->b_rptr;
121 	rtp->version = 2;
122 	rtp->markbit=start;
123 	rtp->padbit = 0;
124 	rtp->extbit = 0;
125 	rtp->cc = 0;
126 	rtp->ssrc = session->snd.ssrc;
127 	/* timestamp set later, when packet is sended */
128 	/*seq number set later, when packet is sended */
129 
130 	/*set the payload type */
131 	rtp->paytype=tev_pt;
132 
133 	/*copy the payload */
134 	mp->b_wptr+=RTP_FIXED_HEADER_SIZE;
135 	return mp;
136 }
137 
138 
139 /**
140  *@param session a rtp session.
141  *@param packet a rtp packet as a mblk_t
142  *@param event the event type as described in rfc2833, ie one of the TEV_* macros.
143  *@param end a boolean to indicate if the end bit should be set. (end of tone)
144  *@param volume the volume of the telephony tone, as described in rfc2833
145  *@param duration the duration of the telephony tone, in timestamp unit.
146  *
147  * Adds a named telephony event to a rtp packet previously allocated using
148  * rtp_session_create_telephone_event_packet().
149  *
150  *@return 0 on success.
151 **/
rtp_session_add_telephone_event(RtpSession * session,mblk_t * packet,uint8_t event,int end,uint8_t volume,uint16_t duration)152 int rtp_session_add_telephone_event(RtpSession *session,
153 			mblk_t *packet, uint8_t event, int end, uint8_t volume, uint16_t duration)
154 {
155 	mblk_t *mp=packet;
156 	telephone_event_t *event_hdr;
157 
158 
159 	/* find the place where to add the new telephony event to the packet */
160 	while(mp->b_cont!=NULL) mp=mp->b_cont;
161 	/* see if we need to allocate a new mblk_t */
162 	if ( ( mp->b_wptr) >= (mp->b_datap->db_lim)){
163 		mblk_t *newm=allocb(TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED);
164 		mp->b_cont=newm;
165 		mp=mp->b_cont;
166 	}
167 	if (mp==NULL) return -1;
168 	event_hdr=(telephone_event_t*)mp->b_wptr;
169 	event_hdr->event=event;
170 	event_hdr->R=0;
171 	event_hdr->E=end;
172 	event_hdr->volume=volume;
173 	event_hdr->duration=htons(duration);
174 	mp->b_wptr+=sizeof(telephone_event_t);
175 	return 0;
176 }
177 /**
178  *	This functions creates telephony events packets for dtmf and sends them.
179  *	It uses rtp_session_create_telephone_event_packet() and
180  *	rtp_session_add_telephone_event() to create them and finally
181  *	rtp_session_sendm_with_ts() to send them.
182  *
183  * @param session a rtp session
184  * @param dtmf a character meaning the dtmf (ex: '1', '#' , '9' ...)
185  * @param userts the timestamp
186  * @return 0 if successfull, -1 if the session cannot support telephony events or if the dtmf given as argument is not valid.
187 **/
rtp_session_send_dtmf(RtpSession * session,char dtmf,uint32_t userts)188 int rtp_session_send_dtmf(RtpSession *session, char dtmf, uint32_t userts)
189 {
190   return rtp_session_send_dtmf2(session, dtmf, userts, 480);
191 }
192 
193 /**
194  * A variation of rtp_session_send_dtmf() with duration specified.
195  *
196  * @param session a rtp session
197  * @param dtmf a character meaning the dtmf (ex: '1', '#' , '9' ...)
198  * @param userts the timestamp
199  * @param duration duration of the dtmf in timestamp units
200  * @return 0 if successfull, -1 if the session cannot support telephony events or if the dtmf given as argument is not valid.
201 **/
rtp_session_send_dtmf2(RtpSession * session,char dtmf,uint32_t userts,int duration)202 int rtp_session_send_dtmf2(RtpSession *session, char dtmf, uint32_t userts, int duration)
203 {
204 	mblk_t *m1,*m2,*m3;
205 	int tev_type;
206 	int durationtier = duration/3;
207 
208 	/* create the first telephony event packet */
209 	switch (dtmf){
210 		case '1':
211 			tev_type=TEV_DTMF_1;
212 		break;
213 		case '2':
214 			tev_type=TEV_DTMF_2;
215 		break;
216 		case '3':
217 			tev_type=TEV_DTMF_3;
218 		break;
219 		case '4':
220 			tev_type=TEV_DTMF_4;
221 		break;
222 		case '5':
223 			tev_type=TEV_DTMF_5;
224 		break;
225 		case '6':
226 			tev_type=TEV_DTMF_6;
227 		break;
228 		case '7':
229 			tev_type=TEV_DTMF_7;
230 		break;
231 		case '8':
232 			tev_type=TEV_DTMF_8;
233 		break;
234 		case '9':
235 			tev_type=TEV_DTMF_9;
236 		break;
237 		case '*':
238 			tev_type=TEV_DTMF_STAR;
239 		break;
240 		case '0':
241 			tev_type=TEV_DTMF_0;
242 		break;
243 		case '#':
244 			tev_type=TEV_DTMF_POUND;
245 		break;
246 
247 		case 'A':
248 		case 'a':
249 		  tev_type=TEV_DTMF_A;
250 		  break;
251 
252 
253 		case 'B':
254 		case 'b':
255 		  tev_type=TEV_DTMF_B;
256 		  break;
257 
258 		case 'C':
259 		case 'c':
260 		  tev_type=TEV_DTMF_C;
261 		  break;
262 
263 		case 'D':
264 		case 'd':
265 		  tev_type=TEV_DTMF_D;
266 		  break;
267 
268 		case '!':
269 		  tev_type=TEV_FLASH;
270 		  break;
271 
272 
273 		default:
274 		ortp_warning("Bad dtmf: %c.",dtmf);
275 		return -1;
276 	}
277 
278 	m1=rtp_session_create_telephone_event_packet(session,1);
279 	if (m1==NULL) return -1;
280 	rtp_session_add_telephone_event(session,m1,tev_type,0,10,durationtier);
281 	/* create a second packet */
282 	m2=rtp_session_create_telephone_event_packet(session,0);
283 	if (m2==NULL) return -1;
284 	rtp_session_add_telephone_event(session,m2,tev_type,0,10, durationtier+durationtier);
285 
286 	/* create a third and final packet */
287 	m3=rtp_session_create_telephone_event_packet(session,0);
288 	if (m3==NULL) return -1;
289 	rtp_session_add_telephone_event(session,m3,tev_type,1,10,duration);
290 
291 	/* and now sends them */
292 	rtp_session_sendm_with_ts(session,m1,userts);
293 	rtp_session_sendm_with_ts(session,m2,userts);
294 	/* the last packet is sent three times in order to improve reliability*/
295 	m1=copymsg(m3);
296 	m2=copymsg(m3);
297 	/*			NOTE:			*/
298 	/* we need to copymsg() instead of dupmsg() because the buffers are modified when
299 	the packet is sended because of the host-to-network conversion of timestamp,ssrc, csrc, and
300 	seq number.
301 	*/
302 	rtp_session_sendm_with_ts(session,m3,userts);
303 	session->rtp.snd_seq--;
304 	rtp_session_sendm_with_ts(session,m1,userts);
305 	session->rtp.snd_seq--;
306 	rtp_session_sendm_with_ts(session,m2,userts);
307 	return 0;
308 }
309 
310 
311 /**
312  *	Reads telephony events from a rtp packet. \a *tab points to the beginning of the event buffer.
313  *
314  * @param session a rtp session from which telephony events are received.
315  * @param packet a rtp packet as a mblk_t.
316  * @param tab the address of a pointer.
317  * @return the number of events in the packet if successfull, 0 if the packet did not contain telephony events.
318 **/
rtp_session_read_telephone_event(RtpSession * session,mblk_t * packet,telephone_event_t ** tab)319 int rtp_session_read_telephone_event(RtpSession *session,
320 		mblk_t *packet,telephone_event_t **tab)
321 {
322 	int datasize;
323 	int num;
324 	int i;
325 	telephone_event_t *tev;
326 	rtp_header_t *hdr=(rtp_header_t*)packet->b_rptr;
327 	unsigned char *payload;
328 	if (!rtp_profile_is_telephone_event(session->rcv.profile, hdr->paytype)) return 0;  /* this is not tel ev.*/
329 	datasize=rtp_get_payload(packet,&payload);
330 	tev=*tab=(telephone_event_t*)payload;
331 	/* convert from network to host order what should be */
332 	num=datasize/sizeof(telephone_event_t);
333 	for (i=0;i<num;i++)
334 	{
335 		tev[i].duration=ntohs(tev[i].duration);
336 	}
337 	return num;
338 }
339 
notify_tev(RtpSession * session,telephone_event_t * event)340 static void notify_tev(RtpSession *session, telephone_event_t *event){
341 	OrtpEvent *ev;
342 	OrtpEventData *evd;
343 	rtp_signal_table_emit2(&session->on_telephone_event,ORTP_INT_TO_POINTER(event[0].event));
344 	if (session->eventqs!=NULL){
345 		ev=ortp_event_new(ORTP_EVENT_TELEPHONE_EVENT);
346 		evd=ortp_event_get_data(ev);
347 		evd->packet=dupmsg(session->current_tev);
348 		evd->info.telephone_event=event[0].event;
349 		rtp_session_dispatch_event(session,ev);
350 	}
351 }
352 
notify_events_ended(RtpSession * session,telephone_event_t * events,int num)353 static void notify_events_ended(RtpSession *session, telephone_event_t *events, int num){
354 	int i;
355 	for (i=0;i<num;i++){
356 		if (events[i].E==1){
357 			notify_tev(session, &events[i]);
358 		}
359 	}
360 }
361 
362 /* for high level telephony event callback */
rtp_session_check_telephone_events(RtpSession * session,mblk_t * m0)363 void rtp_session_check_telephone_events(RtpSession *session, mblk_t *m0)
364 {
365 	telephone_event_t *events,*evbuf;
366 	int num,num2;
367 	int i;
368 	rtp_header_t *hdr;
369 	mblk_t *cur_tev;
370 	unsigned char *payload;
371 	int datasize;
372 
373 	hdr=(rtp_header_t*)m0->b_rptr;
374 
375 	datasize=rtp_get_payload(m0,&payload);
376 
377 	num=datasize/sizeof(telephone_event_t);
378 	events=(telephone_event_t*)payload;
379 
380 
381 	if (hdr->markbit==1)
382 	{
383 		/* this is a start of new events. Store the event buffer for later use*/
384 		if (session->current_tev!=NULL) {
385 			freemsg(session->current_tev);
386 			session->current_tev=NULL;
387 		}
388 		session->current_tev=copymsg(m0);
389 		/* handle the case where the events are short enough to end within the packet that has the marker bit*/
390 		notify_events_ended(session,events,num);
391 	}
392 	/* whatever there is a markbit set or not, we parse the packet and compare it to previously received one */
393 	cur_tev=session->current_tev;
394 	if (cur_tev!=NULL)
395 	{
396 		/* first compare timestamp, they must be identical */
397 		if (((rtp_header_t*)cur_tev->b_rptr)->timestamp==
398 			((rtp_header_t*)m0->b_rptr)->timestamp)
399 		{
400 			datasize=rtp_get_payload(cur_tev,&payload);
401 			num2=datasize/sizeof(telephone_event_t);
402 			evbuf=(telephone_event_t*)payload;
403 			for (i=0;i<MIN(num,num2);i++)
404 			{
405 				if (events[i].E==1)
406 				{
407 					/* update events that have ended */
408 					if (evbuf[i].E==0){
409 						evbuf[i].E=1;
410 						/* this is a end of event, report it */
411 						notify_tev(session,&events[i]);
412 					}
413 				}
414 			}
415 		}
416 		else
417 		{
418 			/* timestamp are not identical: this is not the same events*/
419 			if (session->current_tev!=NULL) {
420 				freemsg(session->current_tev);
421 				session->current_tev=NULL;
422 			}
423 			session->current_tev=copymsg(m0);
424 			notify_events_ended(session,events,num);
425 		}
426 	}
427 	else
428 	{
429 		/* there is no pending events, but we did not received marked bit packet
430 		either the sending implementation is not compliant, either it has been lost,
431 		we must deal with it anyway.*/
432 		session->current_tev=copymsg(m0);
433 		/* inform the application if there are tone ends */
434 		notify_events_ended(session,events,num);
435 	}
436 }
437