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