Ignore:
Timestamp:
Feb 22, 2006 12:06:39 PM (18 years ago)
Author:
bennylp
Message:

RFC 2833 support!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r214 r215  
    2222#include <pjmedia/rtcp.h> 
    2323#include <pjmedia/jbuf.h> 
     24#include <pj/array.h> 
     25#include <pj/assert.h> 
     26#include <pj/ctype.h> 
     27#include <pj/compat/socket.h> 
     28#include <pj/errno.h> 
     29#include <pj/log.h> 
    2430#include <pj/os.h> 
    25 #include <pj/ctype.h> 
    26 #include <pj/log.h> 
     31#include <pj/pool.h> 
     32#include <pj/sock_select.h> 
    2733#include <pj/string.h>      /* memcpy() */ 
    28 #include <pj/pool.h> 
    29 #include <pj/assert.h> 
    30 #include <pj/compat/socket.h> 
    31 #include <pj/sock_select.h> 
    32 #include <pj/errno.h> 
    33 #include <stdlib.h> 
    3434 
    3535 
     
    6969    int             event; 
    7070    pj_uint32_t     start_ts; 
    71     pj_uint32_t     end_ts; 
    7271}; 
    7372 
     
    8786    pjmedia_dir              dir;           /**< Stream direction.          */ 
    8887    pjmedia_stream_stat      stat;          /**< Stream statistics.         */ 
     88    void                    *user_data;     /**< User data.                 */ 
    8989 
    9090    pjmedia_codec_mgr       *codec_mgr;     /**< Codec manager instance.    */ 
     
    104104 
    105105    /* RFC 2833 DTMF transmission queue: */ 
    106     int                      dtmf_count;    /**< # of digits in queue.      */ 
    107     struct dtmf              dtmf_queue[32];/**< Outgoing dtmf queue.       */ 
     106    int                      tx_event_pt;   /**< Outgoing pt for dtmf.      */ 
     107    int                      tx_dtmf_count; /**< # of digits in tx dtmf buf.*/ 
     108    struct dtmf              tx_dtmf_buf[32];/**< Outgoing dtmf queue.      */ 
     109 
     110    /* Incoming DTMF: */ 
     111    int                      rx_event_pt;   /**< Incoming pt for dtmf.      */ 
     112    int                      last_dtmf;     /**< Current digit, or -1.      */ 
     113    pj_uint32_t              last_dtmf_dur; /**< Start ts for cur digit.    */ 
     114    unsigned                 rx_dtmf_count; /**< # of digits in dtmf rx buf.*/ 
     115    char                     rx_dtmf_buf[32];/**< Incoming DTMF buffer.     */ 
    108116}; 
    109117 
     
    194202 * Transmit DTMF 
    195203 */ 
    196 static void transmit_dtmf(pjmedia_stream *stream,  
     204static void create_dtmf_payload(pjmedia_stream *stream,  
    197205                          struct pjmedia_frame *frame_out) 
    198206{ 
    199207    pjmedia_rtp_dtmf_event *event; 
    200     struct dtmf *digit = &stream->dtmf_queue[0]; 
     208    struct dtmf *digit = &stream->tx_dtmf_buf[0]; 
     209    unsigned duration; 
    201210    pj_uint32_t cur_ts; 
     211 
     212    pj_assert(sizeof(pjmedia_rtp_dtmf_event) == 4); 
    202213 
    203214    event = frame_out->buf; 
    204215    cur_ts = pj_ntohl(stream->enc->rtp.out_hdr.ts); 
     216    duration = cur_ts - digit->start_ts; 
    205217 
    206218    event->event = (pj_uint8_t)digit->event; 
    207219    event->e_vol = 10; 
    208     event->duration = pj_htonl(cur_ts - digit->start_ts); 
     220    event->duration = pj_htons((pj_uint16_t)duration); 
     221 
     222    if (duration >= PJMEDIA_DTMF_DURATION) { 
     223        event->e_vol |= 0x80; 
     224 
     225        /* Prepare next digit. */ 
     226        pj_mutex_lock(stream->jb_mutex); 
     227        pj_array_erase(stream->tx_dtmf_buf, sizeof(stream->tx_dtmf_buf[0]), 
     228                       stream->tx_dtmf_count, 0); 
     229        --stream->tx_dtmf_count; 
     230 
     231        stream->tx_dtmf_buf[0].start_ts = cur_ts; 
     232        pj_mutex_unlock(stream->jb_mutex); 
     233    } 
     234 
     235    frame_out->size = 4; 
    209236} 
    210237 
     
    228255    pj_ssize_t sent; 
    229256 
    230  
    231257    /* Check if stream is quitting. */ 
    232258    if (stream->quit_flag) 
     
    242268     * Otherwise encode the PCM buffer. 
    243269     */ 
    244     if (stream->dtmf_count) { 
    245         transmit_dtmf(stream, &frame_out); 
     270    if (stream->tx_dtmf_count) { 
     271 
     272        create_dtmf_payload(stream, &frame_out); 
     273 
     274        /* Encapsulate. */ 
     275        status = pjmedia_rtp_encode_rtp( &channel->rtp,  
     276                                         stream->tx_event_pt, 0,  
     277                                         frame_out.size, ts_len,  
     278                                         (const void**)&rtphdr,  
     279                                         &rtphdrlen); 
     280 
    246281    } else { 
    247282        unsigned max_size; 
     
    255290            return status; 
    256291        } 
    257     } 
    258  
    259     /* Encapsulate. */ 
    260     status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    261                                 channel->pt, 0,  
    262                                 frame_out.size, ts_len,  
    263                                 (const void**)&rtphdr, &rtphdrlen); 
     292 
     293        /* Encapsulate. */ 
     294        status = pjmedia_rtp_encode_rtp( &channel->rtp,  
     295                                         channel->pt, 0,  
     296                                         frame_out.size, ts_len,  
     297                                         (const void**)&rtphdr,  
     298                                         &rtphdrlen); 
     299    } 
     300 
    264301    if (status != 0) { 
    265302        TRACE_((THIS_FILE, "RTP encode_rtp() error", status)); 
     
    290327} 
    291328 
    292  
     329#if 0 
    293330static void dump_bin(const char *buf, unsigned len) 
    294331{ 
     
    313350    PJ_LOG(3,(THIS_FILE, "end dump")); 
    314351} 
     352#endif 
     353 
     354/* 
     355 * Handle incoming DTMF digits. 
     356 */ 
     357static void handle_incoming_dtmf( pjmedia_stream *stream,  
     358                                  const void *payload, unsigned payloadlen) 
     359{ 
     360    static const char digitmap[16] = { '0', '1', '2', '3',  
     361                                       '4', '5', '6', '7',  
     362                                       '8', '9', '*', '#', 
     363                                       'A', 'B', 'C', 'D'}; 
     364    const pjmedia_rtp_dtmf_event *event = payload; 
     365 
     366    /* Check compiler packing. */ 
     367    pj_assert(sizeof(pjmedia_rtp_dtmf_event)==4); 
     368 
     369    /* Must have sufficient length before we proceed. */ 
     370    if (payloadlen < sizeof(pjmedia_rtp_dtmf_event)) 
     371        return; 
     372 
     373    //dump_bin(payload, payloadlen); 
     374 
     375    /* Check if this is the same/current digit of the last packet. */ 
     376    if (stream->last_dtmf != -1 && 
     377        event->event == stream->last_dtmf && 
     378        pj_ntohs(event->duration) >= stream->last_dtmf_dur) 
     379    { 
     380        /* Yes, this is the same event. */ 
     381        stream->last_dtmf_dur = pj_ntohs(event->duration); 
     382        return; 
     383    } 
     384 
     385    /* Ignore unknown event. */ 
     386    if (event->event > 15) { 
     387        PJ_LOG(5,(THIS_FILE, "Ignored RTP pkt with bad DTMF event %d", 
     388                             event->event)); 
     389        return; 
     390    } 
     391 
     392    /* New event! */ 
     393    PJ_LOG(5,(THIS_FILE, "Received DTMF digit %c, vol=%d", 
     394                         digitmap[event->event], 
     395                         (event->e_vol & 0x3F))); 
     396 
     397    stream->last_dtmf = event->event; 
     398    stream->last_dtmf_dur = pj_ntohs(event->duration); 
     399 
     400    /* By convention, we use jitter buffer's mutex to access shared 
     401     * DTMF variables. 
     402     */ 
     403    pj_mutex_lock(stream->jb_mutex); 
     404    if (stream->rx_dtmf_count >= PJ_ARRAY_SIZE(stream->rx_dtmf_buf)) { 
     405        /* DTMF digits overflow.  Discard the oldest digit. */ 
     406        pj_array_erase(stream->rx_dtmf_buf, sizeof(stream->rx_dtmf_buf[0]), 
     407                       stream->rx_dtmf_count, 0); 
     408        --stream->rx_dtmf_count; 
     409    } 
     410    stream->rx_dtmf_buf[stream->rx_dtmf_count++] = digitmap[event->event]; 
     411    pj_mutex_unlock(stream->jb_mutex); 
     412} 
     413 
    315414 
    316415/* 
     
    377476        } 
    378477 
    379 #if 1 
    380         if (hdr->pt == 101) { 
    381             dump_bin((char*)payload, payloadlen); 
     478        /* Handle incoming DTMF. */ 
     479        if (hdr->pt == stream->rx_event_pt) { 
     480            handle_incoming_dtmf(stream, payload, payloadlen); 
    382481            continue; 
    383482        } 
    384 #endif 
    385483 
    386484        status = pjmedia_rtp_session_update(&channel->rtp, hdr); 
     
    521619                                           pj_pool_t *pool, 
    522620                                           const pjmedia_stream_info *info, 
     621                                           void *user_data, 
    523622                                           pjmedia_stream **p_stream) 
    524623 
     
    553652    
    554653    stream->dir = info->dir; 
     654    stream->user_data = user_data; 
    555655    stream->codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); 
    556656    stream->skinfo = info->sock_info; 
    557657    stream->rem_rtp_addr = info->rem_addr; 
     658    stream->tx_event_pt = info->tx_event_pt; 
     659    stream->rx_event_pt = info->rx_event_pt; 
     660    stream->last_dtmf = -1; 
     661 
    558662 
    559663    PJ_TODO(INITIALIZE_RTCP_REMOTE_ADDRESS); 
     
    825929    PJ_ASSERT_RETURN(stream && digit_char, PJ_EINVAL); 
    826930 
     931    /* Check that remote can receive DTMF events. */ 
     932    if (stream->tx_event_pt < 0) { 
     933        return PJMEDIA_RTP_EINDTMF; 
     934    } 
     935     
    827936    pj_mutex_lock(stream->jb_mutex); 
    828937     
    829     if (stream->dtmf_count+digit_char->slen >= 
    830         PJ_ARRAY_SIZE(stream->dtmf_queue)) 
     938    if (stream->tx_dtmf_count+digit_char->slen >= 
     939        PJ_ARRAY_SIZE(stream->tx_dtmf_buf)) 
    831940    { 
    832941        status = PJ_ETOOMANY; 
     
    864973            } 
    865974 
    866             stream->dtmf_queue[stream->dtmf_count+1].event = pt; 
    867             stream->dtmf_queue[stream->dtmf_count+1].start_ts = start_ts; 
    868             stream->dtmf_queue[stream->dtmf_count+1].end_ts =  
    869                 start_ts + PJMEDIA_DTMF_DURATION; 
    870  
    871             start_ts += PJMEDIA_DTMF_DURATION + 320; 
     975            stream->tx_dtmf_buf[stream->tx_dtmf_count+i].event = pt; 
    872976        } 
    873977 
     
    875979            goto on_return; 
    876980 
    877         if (stream->dtmf_count ==0) { 
     981        /* Init start_ts and end_ts only for the first digit. 
     982         * Subsequent digits are initialized on the fly. 
     983         */ 
     984        if (stream->tx_dtmf_count ==0) { 
    878985            pj_uint32_t start_ts; 
    879986 
    880987            start_ts = pj_ntohl(stream->enc->rtp.out_hdr.ts); 
    881             stream->dtmf_queue[0].start_ts = start_ts; 
    882             stream->dtmf_queue[0].end_ts = start_ts + PJMEDIA_DTMF_DURATION; 
     988            stream->tx_dtmf_buf[0].start_ts = start_ts; 
    883989        } 
    884990 
    885991        /* Increment digit count only if all digits are valid. */ 
    886         stream->dtmf_count += digit_char->slen; 
     992        stream->tx_dtmf_count += digit_char->slen; 
    887993 
    888994    } 
     
    8941000} 
    8951001 
     1002 
     1003/* 
     1004 * See if we have DTMF digits in the rx buffer. 
     1005 */ 
     1006PJ_DEF(pj_bool_t) pjmedia_stream_check_dtmf(pjmedia_stream *stream) 
     1007{ 
     1008    return stream->rx_dtmf_count != 0; 
     1009} 
     1010 
     1011 
     1012/* 
     1013 * Retrieve incoming DTMF digits from the stream's DTMF buffer. 
     1014 */ 
     1015PJ_DEF(pj_status_t) pjmedia_stream_get_dtmf( pjmedia_stream *stream, 
     1016                                             char *digits, 
     1017                                             unsigned *size) 
     1018{ 
     1019    PJ_ASSERT_RETURN(stream && digits && size, PJ_EINVAL); 
     1020 
     1021    pj_assert(sizeof(stream->rx_dtmf_buf[0]) == 0); 
     1022 
     1023    /* By convention, we use jitter buffer's mutex to access DTMF 
     1024     * digits resources. 
     1025     */ 
     1026    pj_mutex_lock(stream->jb_mutex); 
     1027 
     1028    if (stream->rx_dtmf_count < *size) 
     1029        *size = stream->rx_dtmf_count; 
     1030 
     1031    if (*size) { 
     1032        pj_memcpy(digits, stream->rx_dtmf_buf, *size); 
     1033        stream->rx_dtmf_count -= *size; 
     1034        if (stream->rx_dtmf_count) { 
     1035            pj_memmove(stream->rx_dtmf_buf, 
     1036                       &stream->rx_dtmf_buf[*size], 
     1037                       stream->rx_dtmf_count); 
     1038        } 
     1039    } 
     1040 
     1041    pj_mutex_unlock(stream->jb_mutex); 
     1042 
     1043    return PJ_SUCCESS; 
     1044} 
Note: See TracChangeset for help on using the changeset viewer.