src/telephonyevents.c

00001 /*
00002   The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack.
00003   Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009 
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014 
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the Free Software
00017   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00020 #include <ortp/telephonyevents.h>
00021 #include "utils.h"
00022 #include "rtpsession_priv.h"
00023 #include <ortp/ortp.h>
00024 
00025 PayloadType     payload_type_telephone_event={
00026         PAYLOAD_AUDIO_PACKETIZED, /*type */
00027         8000,   /*clock rate */
00028         0,              /* bytes per sample N/A */
00029         NULL,   /* zero pattern N/A*/
00030         0,              /*pattern_length N/A */
00031         0,              /*      normal_bitrate */
00032         "telephone-event",
00033         0       /*flags */
00034 };
00035 
00043 int rtp_session_telephone_events_supported(RtpSession *session)
00044 {
00045         /* search for a telephony event payload in the current profile */
00046         session->snd.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->snd.profile,"telephone-event");
00047         session->rcv.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->rcv.profile,"telephone-event");
00048         /*printf("Telephone event pt is %i\n",session->telephone_events_pt);*/
00049         return session->snd.telephone_events_pt;
00050 }
00051 
00052 
00060 int rtp_session_send_telephone_events_supported(RtpSession *session)
00061 {
00062         /* search for a telephony event payload in the current profile */
00063         session->snd.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->snd.profile,"telephone-event");
00064         /*printf("Telephone event pt is %i\n",session->telephone_events_pt);*/
00065         return session->snd.telephone_events_pt;
00066 }
00067 int rtp_session_recv_telephone_events_supported(RtpSession *session)
00075 {
00076         /* search for a telephony event payload in the current profile */
00077         session->rcv.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->rcv.profile,"telephone-event");
00078         /*printf("Telephone event pt is %i\n",session->telephone_events_pt);*/
00079         return session->snd.telephone_events_pt;
00080 }
00081 
00082 
00095 mblk_t  *rtp_session_create_telephone_event_packet(RtpSession *session, int start)
00096 {
00097         mblk_t *mp;
00098         rtp_header_t *rtp;
00099         
00100         return_val_if_fail(session->snd.telephone_events_pt!=-1,NULL);
00101         
00102         mp=allocb(RTP_FIXED_HEADER_SIZE+TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED);
00103         if (mp==NULL) return NULL;
00104         rtp=(rtp_header_t*)mp->b_rptr;
00105         rtp->version = 2;
00106         rtp->markbit=start;
00107         rtp->padbit = 0;
00108         rtp->extbit = 0;
00109         rtp->cc = 0;
00110         rtp->ssrc = session->snd.ssrc;
00111         /* timestamp set later, when packet is sended */
00112         /*seq number set later, when packet is sended */
00113         
00114         /*set the payload type */
00115         rtp->paytype=session->snd.telephone_events_pt;
00116         
00117         /*copy the payload */
00118         mp->b_wptr+=RTP_FIXED_HEADER_SIZE;
00119         return mp;
00120 }
00121 
00122 
00136 int rtp_session_add_telephone_event(RtpSession *session,
00137                         mblk_t *packet, uint8_t event, int end, uint8_t volume, uint16_t duration)
00138 {
00139         mblk_t *mp=packet;
00140         telephone_event_t *event_hdr;
00141 
00142 
00143         /* find the place where to add the new telephony event to the packet */
00144         while(mp->b_cont!=NULL) mp=mp->b_cont;
00145         /* see if we need to allocate a new mblk_t */
00146         if ( ( mp->b_wptr) >= (mp->b_datap->db_lim)){
00147                 mblk_t *newm=allocb(TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED);
00148                 mp->b_cont=newm;
00149                 mp=mp->b_cont;
00150         }
00151         if (mp==NULL) return -1;
00152         event_hdr=(telephone_event_t*)mp->b_wptr;
00153         event_hdr->event=event;
00154         event_hdr->R=0;
00155         event_hdr->E=end;
00156         event_hdr->volume=volume;
00157         event_hdr->duration=htons(duration);
00158         mp->b_wptr+=sizeof(telephone_event_t);
00159         return 0;
00160 }
00172 int rtp_session_send_dtmf(RtpSession *session, char dtmf, uint32_t userts)
00173 {
00174   return rtp_session_send_dtmf2(session, dtmf, userts, 480);
00175 }
00176 
00186 int rtp_session_send_dtmf2(RtpSession *session, char dtmf, uint32_t userts, int duration)
00187 {
00188         mblk_t *m1,*m2,*m3;
00189         int tev_type;
00190         int durationtier = duration/3;
00191 
00192         /* create the first telephony event packet */
00193         switch (dtmf){
00194                 case '1':
00195                         tev_type=TEV_DTMF_1;
00196                 break;
00197                 case '2':
00198                         tev_type=TEV_DTMF_2;
00199                 break;
00200                 case '3':
00201                         tev_type=TEV_DTMF_3;
00202                 break;
00203                 case '4':
00204                         tev_type=TEV_DTMF_4;
00205                 break;
00206                 case '5':
00207                         tev_type=TEV_DTMF_5;
00208                 break;
00209                 case '6':
00210                         tev_type=TEV_DTMF_6;
00211                 break;
00212                 case '7':
00213                         tev_type=TEV_DTMF_7;
00214                 break;
00215                 case '8':
00216                         tev_type=TEV_DTMF_8;
00217                 break;
00218                 case '9':
00219                         tev_type=TEV_DTMF_9;
00220                 break;
00221                 case '*':
00222                         tev_type=TEV_DTMF_STAR;
00223                 break;
00224                 case '0':
00225                         tev_type=TEV_DTMF_0;
00226                 break;
00227                 case '#':
00228                         tev_type=TEV_DTMF_POUND;
00229                 break;
00230 
00231                 case 'A':
00232                 case 'a':
00233                   tev_type=TEV_DTMF_A;
00234                   break;
00235 
00236 
00237                 case 'B':
00238                 case 'b':
00239                   tev_type=TEV_DTMF_B;
00240                   break;
00241 
00242                 case 'C':
00243                 case 'c':
00244                   tev_type=TEV_DTMF_C;
00245                   break;
00246 
00247                 case 'D':
00248                 case 'd':
00249                   tev_type=TEV_DTMF_D;
00250                   break;
00251 
00252                 case '!':
00253                   tev_type=TEV_FLASH;
00254                   break;
00255 
00256 
00257                 default:
00258                 ortp_warning("Bad dtmf: %c.",dtmf);
00259                 return -1;
00260         }
00261 
00262         m1=rtp_session_create_telephone_event_packet(session,1);
00263         if (m1==NULL) return -1;
00264         rtp_session_add_telephone_event(session,m1,tev_type,0,10,durationtier);
00265         /* create a second packet */
00266         m2=rtp_session_create_telephone_event_packet(session,0);
00267         if (m2==NULL) return -1;
00268         rtp_session_add_telephone_event(session,m2,tev_type,0,10, durationtier+durationtier);
00269                 
00270         /* create a third and final packet */
00271         m3=rtp_session_create_telephone_event_packet(session,0);
00272         if (m3==NULL) return -1;
00273         rtp_session_add_telephone_event(session,m3,tev_type,1,10,duration);
00274         
00275         /* and now sends them */
00276         rtp_session_sendm_with_ts(session,m1,userts);
00277         rtp_session_sendm_with_ts(session,m2,userts+durationtier);
00278         /* the last packet is sent three times in order to improve reliability*/
00279         m1=copymsg(m3);
00280         m2=copymsg(m3);
00281         /*                      NOTE:                   */
00282         /* we need to copymsg() instead of dupmsg() because the buffers are modified when
00283         the packet is sended because of the host-to-network conversion of timestamp,ssrc, csrc, and
00284         seq number.
00285         It could be avoided by making a copy of the buffer when sending physically the packet, but
00286         it add one more copy for every buffer.
00287         Using iomapped socket, it is possible to avoid the user to kernel copy.
00288         */
00289         rtp_session_sendm_with_ts(session,m3,userts+durationtier+durationtier);
00290         rtp_session_sendm_with_ts(session,m1,userts+durationtier+durationtier);
00291         rtp_session_sendm_with_ts(session,m2,userts+durationtier+durationtier);
00292         return 0;
00293 }
00294 
00295 
00304 int rtp_session_read_telephone_event(RtpSession *session,
00305                 mblk_t *packet,telephone_event_t **tab)
00306 {
00307         int datasize;
00308         int num;
00309         int i;
00310         telephone_event_t *tev;
00311         rtp_header_t *hdr=(rtp_header_t*)packet->b_rptr;
00312         return_val_if_fail(packet->b_cont!=NULL,-1);
00313         if (hdr->paytype!=session->rcv.telephone_events_pt) return 0;  /* this is not tel ev.*/
00314         datasize=msgdsize(packet);
00315         tev=*tab=(telephone_event_t*)packet->b_cont->b_rptr;
00316         /* convert from network to host order what should be */
00317         num=datasize/sizeof(telephone_event_t);
00318         for (i=0;i<num;i++)
00319         {
00320                 tev[i].duration=ntohs(tev[i].duration);
00321         }
00322         return num;
00323 }
00324 
00325 static void notify_tev(RtpSession *session, telephone_event_t *event){
00326         OrtpEvent *ev;
00327         OrtpEventData *evd;
00328         rtp_signal_table_emit2(&session->on_telephone_event,(long)(long)event[0].event);
00329         if (session->eventqs!=NULL){
00330                 ev=ortp_event_new(ORTP_EVENT_TELEPHONE_EVENT);
00331                 evd=ortp_event_get_data(ev);
00332                 evd->packet=dupmsg(session->current_tev);
00333                 evd->info.telephone_event=event[0].event;
00334                 rtp_session_dispatch_event(session,ev);
00335         }
00336 }
00337 
00338 static void notify_events_ended(RtpSession *session, telephone_event_t *events, int num){
00339         int i;
00340         for (i=0;i<num;i++){
00341                 if (events[i].E==1){
00342                         notify_tev(session, &events[i]);
00343                 }
00344         }
00345 }
00346 
00347 /* for high level telephony event callback */
00348 void rtp_session_check_telephone_events(RtpSession *session, mblk_t *m0)
00349 {
00350         telephone_event_t *events,*evbuf;
00351         int num;
00352         int i;
00353         mblk_t *mp;
00354         rtp_header_t *hdr;
00355         mblk_t *cur_tev;
00356         
00357         hdr=(rtp_header_t*)m0->b_rptr;
00358         mp=m0->b_cont;
00359         
00360         num=((int)(mp->b_wptr-mp->b_rptr))/sizeof(telephone_event_t);
00361         events=(telephone_event_t*)mp->b_rptr;
00362         
00363         
00364         if (hdr->markbit==1)
00365         {
00366                 /* this is a start of new events. Store the event buffer for later use*/
00367                 if (session->current_tev!=NULL) {
00368                         freemsg(session->current_tev);
00369                         session->current_tev=NULL;
00370                 }
00371                 session->current_tev=copymsg(m0);
00372                 /* handle the case where the events are short enough to end within the packet that has the marker bit*/
00373                 notify_events_ended(session,events,num);
00374         }
00375         /* whatever there is a markbit set or not, we parse the packet and compare it to previously received one */
00376         cur_tev=session->current_tev;
00377         if (cur_tev!=NULL)
00378         {
00379                 /* first compare timestamp, they must be identical */
00380                 if (((rtp_header_t*)cur_tev->b_rptr)->timestamp==
00381                         ((rtp_header_t*)m0->b_rptr)->timestamp)
00382                 {
00383                         evbuf=(telephone_event_t*)cur_tev->b_cont;
00384                         for (i=0;i<num;i++)
00385                         {
00386                                 if (events[i].E==1)
00387                                 {
00388                                         /* update events that have ended */
00389                                         if (evbuf[i].E==0){
00390                                                 evbuf[i].E=1;
00391                                                 /* this is a end of event, report it */
00392                                                 notify_tev(session,&events[i]);
00393                                         }
00394                                 }
00395                         }
00396                 }
00397                 else
00398                 {
00399                         /* timestamp are not identical: this is not the same events*/
00400                         if (session->current_tev!=NULL) {
00401                                 freemsg(session->current_tev);
00402                                 session->current_tev=NULL;
00403                         }
00404                         session->current_tev=dupmsg(m0);
00405                 }
00406         }
00407         else
00408         {
00409                 /* there is no pending events, but we did not received marked bit packet
00410                 either the sending implementation is not compliant, either it has been lost, 
00411                 we must deal with it anyway.*/
00412                 session->current_tev=copymsg(m0);
00413                 /* inform the application if there are tone ends */
00414                 notify_events_ended(session,events,num);
00415         }
00416 }

Generated on Fri Jun 22 17:30:30 2007 for oRTP by  doxygen 1.5.2