Changeset 215 for pjproject


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

RFC 2833 support!

Location:
pjproject/trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/errno.h

    r214 r215  
    294294 */ 
    295295#define PJMEDIA_EINVALIMEDIATYPE    (PJMEDIA_ERRNO_START+104)    /* 220104 */ 
     296/** 
     297 * @hideinitializer 
     298 * Remote does not support DTMF. 
     299 */ 
     300#define PJMEDIA_EREMOTENODTMF       (PJMEDIA_ERRNO_START+105)    /* 220105 */ 
     301/** 
     302 * @hideinitializer 
     303 * Invalid DTMF digit. 
     304 */ 
     305#define PJMEDIA_RTP_EINDTMF         (PJMEDIA_ERRNO_START+106)    /* 220106 */ 
    296306 
    297307 
     
    355365 */ 
    356366#define PJMEDIA_RTP_ENOCONFIG       (PJMEDIA_ERRNO_START+134)    /* 220134 */ 
    357 /** 
    358  * @hideinitializer 
    359  * Invalid DTMF digit. 
    360  */ 
    361 #define PJMEDIA_RTP_EINDTMF         (PJMEDIA_ERRNO_START+135)    /* 220135 */ 
    362367 
    363368 
  • pjproject/trunk/pjmedia/include/pjmedia/session.h

    r205 r215  
    8181 * @param local_sdp     The SDP describing local capability. 
    8282 * @param rem_sdp       The SDP describing remote capability. 
     83 * @param user_data     Arbitrary user data to be kept in the session. 
    8384 * @param p_session     Pointer to receive the media session. 
    8485 * 
     
    9293                        const pjmedia_sdp_session *local_sdp, 
    9394                        const pjmedia_sdp_session *rem_sdp, 
     95                        void *user_data, 
    9496                        pjmedia_session **p_session ); 
    9597 
     
    198200 
    199201/** 
     202 * Dial DTMF digit to the stream, using RFC 2833 mechanism. 
     203 * 
     204 * @param session       The media session. 
     205 * @param index         The stream index. 
     206 * @param ascii_digits  String of ASCII digits (i.e. 0-9*#A-B). 
     207 * 
     208 * @return              PJ_SUCCESS on success. 
     209 */ 
     210PJ_DECL(pj_status_t) pjmedia_session_dial_dtmf( pjmedia_session *session, 
     211                                                unsigned index, 
     212                                                const pj_str_t *ascii_digits ); 
     213 
     214 
     215/** 
     216 * Check if the specified stream has received DTMF digits. 
     217 * 
     218 * @param session       The media session. 
     219 * @param index         The stream index. 
     220 * 
     221 * @return              Non-zero (PJ_TRUE) if the stream has DTMF digits. 
     222 */ 
     223PJ_DECL(pj_status_t) pjmedia_session_check_dtmf( pjmedia_session *session, 
     224                                                 unsigned index); 
     225 
     226 
     227/** 
     228 * Retrieve DTMF digits from the specified stream. 
     229 * 
     230 * @param session       The media session. 
     231 * @param index         The stream index. 
     232 * @param ascii_digits  Buffer to receive the digits. The length of this 
     233 *                      buffer is indicated in the "size" argument. 
     234 * @param size          On input, contains the maximum digits to be copied 
     235 *                      to the buffer. 
     236 *                      On output, it contains the actual digits that has 
     237 *                      been copied to the buffer. 
     238 * 
     239 * @return              PJ_SUCCESS on success. 
     240 */ 
     241PJ_DECL(pj_status_t) pjmedia_session_get_dtmf( pjmedia_session *session, 
     242                                               unsigned index, 
     243                                               char *ascii_digits, 
     244                                               unsigned *size ); 
     245 
     246/** 
    200247 * Destroy media session. 
    201248 * 
  • pjproject/trunk/pjmedia/include/pjmedia/stream.h

    r214 r215  
    7272    pj_sockaddr_in      rem_addr;   /**< Remote RTP address                 */ 
    7373    pjmedia_codec_info  fmt;        /**< Codec format info.                 */ 
    74     unsigned            tx_event_pt;/**< Outgoing pt for telephone-events.  */ 
    75     unsigned            rx_event_pt;/**< Incoming pt for telephone-events.  */ 
     74    int                 tx_event_pt;/**< Outgoing pt for telephone-events.  */ 
     75    int                 rx_event_pt;/**< Incoming pt for telephone-events.  */ 
    7676    pj_uint32_t         ssrc;       /**< RTP SSRC.                          */ 
    7777    int                 jb_min;     /**< Jitter buffer min delay.           */ 
     
    111111 *                      buffer needs to preallocate some storage. 
    112112 * @param info          Stream information. 
     113 * @param user_data     Arbitrary user data (for future callback feature). 
    113114 * @param p_stream      Pointer to receive the media stream. 
    114115 * 
     
    118119                                           pj_pool_t *pool, 
    119120                                           const pjmedia_stream_info *info, 
     121                                           void *user_data, 
    120122                                           pjmedia_stream **p_stream); 
    121123 
     
    192194 * 
    193195 * @param stream        The media stream. 
    194  * @param digit         A single digit ('0123456789*#ABCD'). 
     196 * @param ascii_digit   String containing digits to be sent to remote. 
     197 *                      Currently the maximum number of digits are 32. 
    195198 * 
    196199 * @return              PJ_SUCCESS on success. 
    197200 */ 
    198201PJ_DECL(pj_status_t) pjmedia_stream_dial_dtmf(pjmedia_stream *stream, 
    199                                               const pj_str_t *digit_char); 
    200  
     202                                              const pj_str_t *ascii_digit); 
     203 
     204 
     205/** 
     206 * Check if the stream has incoming DTMF digits in the incoming DTMF 
     207 * queue. Incoming DTMF digits received via RFC 2833 mechanism are 
     208 * saved in the incoming digits queue. 
     209 * 
     210 * @param stream        The media stream. 
     211 * 
     212 * @return              Non-zero (PJ_TRUE) if the stream has received DTMF 
     213 *                      digits in the . 
     214 */ 
     215PJ_DECL(pj_bool_t) pjmedia_stream_check_dtmf(pjmedia_stream *stream); 
     216 
     217 
     218/** 
     219 * Retrieve the incoming DTMF digits from the stream. Note that the digits 
     220 * buffer will not be NULL terminated. 
     221 * 
     222 * @param stream        The media stream. 
     223 * @param ascii_digits  Buffer to receive the digits. The length of this 
     224 *                      buffer is indicated in the "size" argument. 
     225 * @param size          On input, contains the maximum digits to be copied 
     226 *                      to the buffer. 
     227 *                      On output, it contains the actual digits that has 
     228 *                      been copied to the buffer. 
     229 * 
     230 * @return              Non-zero (PJ_TRUE) if the stream has received DTMF 
     231 *                      digits in the . 
     232 */ 
     233PJ_DECL(pj_status_t) pjmedia_stream_get_dtmf( pjmedia_stream *stream, 
     234                                              char *ascii_digits, 
     235                                              unsigned *size); 
    201236 
    202237 
  • pjproject/trunk/pjmedia/src/pjmedia/endpoint.c

    r214 r215  
    264264 
    265265#if 1 
    266     // 
    267     // Test: add telephony events 
    268     // 
     266    /* 
     267     * Add support telephony event 
     268     */ 
    269269    m->desc.fmt[m->desc.fmt_count++] = pj_str("101"); 
    270270    /* Add rtpmap. */ 
  • pjproject/trunk/pjmedia/src/pjmedia/errno.c

    r188 r215  
    9090    { PJMEDIA_EMISSINGRTPMAP,       "Missing rtpmap in media description" }, 
    9191    { PJMEDIA_EINVALIMEDIATYPE,     "Invalid media type" }, 
     92    { PJMEDIA_EREMOTENODTMF,        "Remote does not support DTMF" }, 
     93    { PJMEDIA_RTP_EINDTMF,          "Invalid DTMF digit" }, 
    9294 
    9395    /* RTP session errors. */ 
     
    101103    { PJMEDIA_RTP_ESESSPROBATION,   "RTP session in probation" }, 
    102104    { PJMEDIA_RTP_EBADSEQ,          "Bad sequence number in RTP packet" }, 
    103  
     105    { PJMEDIA_RTP_EBADDEST,         "RTP media port destination is not configured" }, 
     106    { PJMEDIA_RTP_ENOCONFIG,        "RTP is not configured" }, 
     107     
     108    /* Media port errors: */ 
     109    { PJMEDIA_ENOTCOMPATIBLE,       "Media ports are not compatible" }, 
     110    { PJMEDIA_ENCCLOCKRATE,         "Media ports have incompatible clock rate" }, 
     111    { PJMEDIA_ENCSAMPLESPFRAME,     "Media ports have incompatible samples per frame" }, 
     112    { PJMEDIA_ENCTYPE,              "Media ports have incompatible media type" }, 
     113    { PJMEDIA_ENCBITS,              "Media ports have incompatible bits per sample" }, 
     114    { PJMEDIA_ENCBYTES,             "Media ports have incompatible bytes per frame" }, 
    104115}; 
    105116 
  • pjproject/trunk/pjmedia/src/pjmedia/session.c

    r205 r215  
    3434    pjmedia_stream_info     stream_info[PJMEDIA_MAX_SDP_MEDIA]; 
    3535    pjmedia_stream         *stream[PJMEDIA_MAX_SDP_MEDIA]; 
     36    void                   *user_data; 
    3637}; 
    3738 
     
    4849static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 }; 
    4950static const pj_str_t ID_RTPMAP = { "rtpmap", 6 }; 
     51static const pj_str_t ID_TELEPHONE_EVENT = { "telephone-event", 15 }; 
    5052 
    5153static const pj_str_t STR_INACTIVE = { "inactive", 8 }; 
     
    6769    const pjmedia_sdp_attr *attr; 
    6870    pjmedia_sdp_rtpmap *rtpmap; 
     71    unsigned i; 
    6972    pj_status_t status; 
    7073 
     
    152155     * type without rtpmap. 
    153156     */ 
    154     attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, NULL); 
     157    attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,  
     158                                       &local_m->desc.fmt[0]); 
    155159    if (attr == NULL) 
    156160        return PJMEDIA_EMISSINGRTPMAP; 
     
    166170    pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name); 
    167171    si->fmt.sample_rate = rtpmap->clock_rate; 
     172 
     173    /* Get local DTMF payload type */ 
     174    si->tx_event_pt = -1; 
     175    for (i=0; i<local_m->attr_count; ++i) { 
     176        pjmedia_sdp_rtpmap r; 
     177 
     178        attr = local_m->attr[i]; 
     179        if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) 
     180            continue; 
     181        if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) 
     182            continue; 
     183        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { 
     184            si->tx_event_pt = pj_strtoul(&r.pt); 
     185            break; 
     186        } 
     187    } 
     188 
     189    /* Get remote DTMF payload type */ 
     190    si->rx_event_pt = -1; 
     191    for (i=0; i<rem_m->attr_count; ++i) { 
     192        pjmedia_sdp_rtpmap r; 
     193 
     194        attr = rem_m->attr[i]; 
     195        if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) 
     196            continue; 
     197        if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) 
     198            continue; 
     199        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { 
     200            si->rx_event_pt = pj_strtoul(&r.pt); 
     201            break; 
     202        } 
     203    } 
     204 
    168205 
    169206    /* Leave SSRC to zero. */ 
     
    183220                                            const pjmedia_sdp_session *local_sdp, 
    184221                                            const pjmedia_sdp_session *rem_sdp, 
     222                                            void *user_data, 
    185223                                            pjmedia_session **p_session ) 
    186224{ 
     
    204242    session->endpt = endpt; 
    205243    session->stream_cnt = stream_cnt; 
     244    session->user_data = user_data; 
    206245     
    207246    /* Stream count is the lower number of stream_cnt or SDP m= lines count */ 
     
    240279        status = pjmedia_stream_create(endpt, session->pool, 
    241280                                       &session->stream_info[i], 
     281                                       session, 
    242282                                       &session->stream[i]); 
    243283        if (status == PJ_SUCCESS) 
     
    386426 
    387427 
     428/* 
     429 * Get the port interface. 
     430 */ 
    388431PJ_DEF(pj_status_t) pjmedia_session_get_port(  pjmedia_session *session, 
    389432                                               unsigned index, 
     
    393436} 
    394437 
    395 /** 
     438/* 
    396439 * Get statistics 
    397440 */ 
     
    407450 
    408451 
     452/* 
     453 * Dial DTMF digit to the stream, using RFC 2833 mechanism. 
     454 */ 
     455PJ_DEF(pj_status_t) pjmedia_session_dial_dtmf( pjmedia_session *session, 
     456                                               unsigned index, 
     457                                               const pj_str_t *ascii_digits ) 
     458{ 
     459    PJ_ASSERT_RETURN(session && ascii_digits, PJ_EINVAL); 
     460    return pjmedia_stream_dial_dtmf(session->stream[index], ascii_digits); 
     461} 
     462 
     463/* 
     464 * Check if the specified stream has received DTMF digits. 
     465 */ 
     466PJ_DEF(pj_status_t) pjmedia_session_check_dtmf( pjmedia_session *session, 
     467                                                unsigned index ) 
     468{ 
     469    PJ_ASSERT_RETURN(session, PJ_EINVAL); 
     470    return pjmedia_stream_check_dtmf(session->stream[index]); 
     471} 
     472 
     473 
     474/* 
     475 * Retrieve DTMF digits from the specified stream. 
     476 */ 
     477PJ_DEF(pj_status_t) pjmedia_session_get_dtmf( pjmedia_session *session, 
     478                                              unsigned index, 
     479                                              char *ascii_digits, 
     480                                              unsigned *size ) 
     481{ 
     482    PJ_ASSERT_RETURN(session && ascii_digits && size, PJ_EINVAL); 
     483    return pjmedia_stream_get_dtmf(session->stream[index], ascii_digits, 
     484                                   size); 
     485} 
  • 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} 
  • pjproject/trunk/pjsip/src/pjsua/main.c

    r212 r215  
    140140    puts("|  v  re-inVite (release hold) | cl  List ports           |                   |"); 
    141141    puts("|  x  Xfer call                | cc  Connect port         |                   |"); 
    142     puts("|                              | cd  Disconnect port      |                   |"); 
     142    puts("|  #  Send DTMF string         | cd  Disconnect port      |                   |"); 
    143143    puts("+------------------------------+--------------------------+-------------------+"); 
    144144    puts("|  q  QUIT                                                                    |"); 
     
    437437                } else if (result.uri_result) { 
    438438                    pjsua_inv_xfer_call( inv_session, result.uri_result); 
     439                } 
     440            } 
     441            break; 
     442 
     443        case '#': 
     444            /* 
     445             * Send DTMF strings. 
     446             */ 
     447            if (inv_session == &pjsua.inv_list) { 
     448                 
     449                PJ_LOG(3,(THIS_FILE, "No current call")); 
     450 
     451            } else if (inv_session->session == NULL) { 
     452 
     453                PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
     454 
     455            } else { 
     456                pj_str_t digits; 
     457                pj_status_t status; 
     458 
     459                if (!simple_input("DTMF strings to send (0-9*#A-B)", buf,  
     460                                  sizeof(buf))) 
     461                        break; 
     462 
     463                digits = pj_str(buf); 
     464                status = pjmedia_session_dial_dtmf(inv_session->session, 0,  
     465                                                   &digits); 
     466                if (status != PJ_SUCCESS) { 
     467                    pjsua_perror(THIS_FILE, "Unable to send DTMF", status); 
     468                } else { 
     469                    puts("DTMF digits enqueued for transmission"); 
    439470                } 
    440471            } 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c

    r212 r215  
    717717                                     &pjsua.med_sock_info[inv_data->call_slot], 
    718718                                     local_sdp, remote_sdp,  
     719                                     inv_data, 
    719720                                     &inv_data->session ); 
    720721    if (status != PJ_SUCCESS) { 
Note: See TracChangeset for help on using the changeset viewer.