Changeset 214


Ignore:
Timestamp:
Feb 22, 2006 9:21:09 AM (19 years ago)
Author:
bennylp
Message:

Putting initial DTMF efforts

Location:
pjproject/trunk/pjmedia
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/build/pjmedia.dsp

    r205 r214  
    6666# PROP Target_Dir "" 
    6767# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 
    68 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /D "_DEBUG" /D "PA_NO_ASIO" /D "PA_NO_WIN_DS" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c 
     68# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /D "_DEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c 
    6969# SUBTRACT CPP /YX 
    7070# ADD BASE RSC /l 0x409 /d "_DEBUG" 
  • pjproject/trunk/pjmedia/include/pjmedia/errno.h

    r205 r214  
    355355 */ 
    356356#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 */ 
    357362 
    358363 
  • pjproject/trunk/pjmedia/include/pjmedia/rtp.h

    r205 r214  
    123123 
    124124 
     125#pragma pack(1) 
     126 
     127/** 
     128 * Declaration for DTMF telephony-events (RFC2833). 
     129 */ 
     130struct pjmedia_rtp_dtmf_event 
     131{ 
     132    pj_uint8_t  event; 
     133    pj_uint8_t  e_vol; 
     134    pj_uint16_t duration; 
     135}; 
     136 
     137/** 
     138 * @see pjmedia_rtp_dtmf_event 
     139 */ 
     140typedef struct pjmedia_rtp_dtmf_event pjmedia_rtp_dtmf_event; 
     141 
     142#pragma pack() 
     143 
     144 
    125145/** 
    126146 * A generic sequence number management, used by both RTP and RTCP. 
  • pjproject/trunk/pjmedia/include/pjmedia/stream.h

    r205 r214  
    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.  */ 
    7476    pj_uint32_t         ssrc;       /**< RTP SSRC.                          */ 
    7577    int                 jb_min;     /**< Jitter buffer min delay.           */ 
     
    184186                                           pjmedia_dir dir); 
    185187 
     188/** 
     189 * Transmit DTMF to this stream. The DTMF will be transmitted uisng 
     190 * RTP telephone-events as described in RFC 2833. This operation is 
     191 * only valid for audio stream. 
     192 * 
     193 * @param stream        The media stream. 
     194 * @param digit         A single digit ('0123456789*#ABCD'). 
     195 * 
     196 * @return              PJ_SUCCESS on success. 
     197 */ 
     198PJ_DECL(pj_status_t) pjmedia_stream_dial_dtmf(pjmedia_stream *stream, 
     199                                              const pj_str_t *digit_char); 
     200 
     201 
    186202 
    187203/** 
  • pjproject/trunk/pjmedia/src/pjmedia/conference.c

    r211 r214  
    747747            continue; 
    748748 
     749        // 
     750        // TODO: 
     751        //  When there's no source, not transmit the frame, but instead 
     752        //  transmit a 'silence' frame. This is to allow the 'port' to 
     753        //  do some processing, such as updating timestamp for RTP session 
     754        //  or transmit signal when it's in the middle of transmitting DTMF. 
     755        // 
    749756 
    750757        target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1? 
  • pjproject/trunk/pjmedia/src/pjmedia/endpoint.c

    r176 r214  
    258258    } 
    259259 
    260     /* Add sendrect attribute. */ 
     260    /* Add sendrecv attribute. */ 
    261261    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 
    262262    attr->name = STR_SENDRECV; 
    263263    m->attr[m->attr_count++] = attr; 
    264264 
     265#if 1 
     266    // 
     267    // Test: add telephony events 
     268    // 
     269    m->desc.fmt[m->desc.fmt_count++] = pj_str("101"); 
     270    /* Add rtpmap. */ 
     271    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 
     272    attr->name = pj_str("rtpmap"); 
     273    attr->value = pj_str(":101 telephone-event/8000"); 
     274    m->attr[m->attr_count++] = attr; 
     275    /* Add fmtp */ 
     276    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); 
     277    attr->name = pj_str("fmtp"); 
     278    attr->value = pj_str(":101 0-15"); 
     279    m->attr[m->attr_count++] = attr; 
     280#endif 
    265281 
    266282    /* Done */ 
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r213 r214  
    2323#include <pjmedia/jbuf.h> 
    2424#include <pj/os.h> 
     25#include <pj/ctype.h> 
    2526#include <pj/log.h> 
    2627#include <pj/string.h>      /* memcpy() */ 
     
    4041#define PJMEDIA_MAX_BUFFER_SIZE_MS      2000 
    4142#define PJMEDIA_MAX_MTU                 1500 
    42  
     43#define PJMEDIA_DTMF_DURATION           1600    /* in timestamp */ 
    4344 
    4445 
     
    6465 
    6566 
     67struct dtmf 
     68{ 
     69    int             event; 
     70    pj_uint32_t     start_ts; 
     71    pj_uint32_t     end_ts; 
     72}; 
     73 
    6674/** 
    6775 * This structure describes media stream. 
     
    94102    pj_bool_t                quit_flag;     /**< To signal thread exit.     */ 
    95103    pj_thread_t             *thread;        /**< Jitter buffer's thread.    */ 
     104 
     105    /* RFC 2833 DTMF transmission queue: */ 
     106    int                      dtmf_count;    /**< # of digits in queue.      */ 
     107    struct dtmf              dtmf_queue[32];/**< Outgoing dtmf queue.       */ 
    96108}; 
    97109 
     
    179191 
    180192 
     193/* 
     194 * Transmit DTMF 
     195 */ 
     196static void transmit_dtmf(pjmedia_stream *stream,  
     197                          struct pjmedia_frame *frame_out) 
     198{ 
     199    pjmedia_rtp_dtmf_event *event; 
     200    struct dtmf *digit = &stream->dtmf_queue[0]; 
     201    pj_uint32_t cur_ts; 
     202 
     203    event = frame_out->buf; 
     204    cur_ts = pj_ntohl(stream->enc->rtp.out_hdr.ts); 
     205 
     206    event->event = (pj_uint8_t)digit->event; 
     207    event->e_vol = 10; 
     208    event->duration = pj_htonl(cur_ts - digit->start_ts); 
     209} 
     210 
    181211/** 
    182212 * rec_callback() 
     
    203233        return -1; 
    204234 
    205     /* Encode. */ 
     235    /* Number of samples in the frame */ 
     236    ts_len = frame->size / (channel->snd_info.bits_per_sample / 8); 
     237 
     238    /* Init frame_out buffer. */ 
    206239    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 
    207     status = stream->codec->op->encode( stream->codec, frame,  
    208                                         channel->out_pkt_size - sizeof(pjmedia_rtp_hdr),  
    209                                         &frame_out); 
    210     if (status != 0) { 
    211         TRACE_((THIS_FILE, "Codec encode() error", status)); 
    212         return status; 
     240 
     241    /* If we have DTMF digits in the queue, transmit the digits.  
     242     * Otherwise encode the PCM buffer. 
     243     */ 
     244    if (stream->dtmf_count) { 
     245        transmit_dtmf(stream, &frame_out); 
     246    } else { 
     247        unsigned max_size; 
     248 
     249        max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr); 
     250        status = stream->codec->op->encode( stream->codec, frame,  
     251                                            max_size,  
     252                                            &frame_out); 
     253        if (status != 0) { 
     254            TRACE_((THIS_FILE, "Codec encode() error", status)); 
     255            return status; 
     256        } 
    213257    } 
    214258 
    215259    /* Encapsulate. */ 
    216     ts_len = frame->size / (channel->snd_info.bits_per_sample / 8); 
    217260    status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    218261                                channel->pt, 0,  
     
    247290} 
    248291 
     292 
     293static void dump_bin(const char *buf, unsigned len) 
     294{ 
     295    unsigned i; 
     296 
     297    PJ_LOG(3,(THIS_FILE, "begin dump")); 
     298    for (i=0; i<len; ++i) { 
     299        int j; 
     300        char bits[9]; 
     301        unsigned val = buf[i] & 0xFF; 
     302 
     303        bits[8] = '\0'; 
     304        for (j=0; j<8; ++j) { 
     305            if (val & (1 << (7-j))) 
     306                bits[j] = '1'; 
     307            else 
     308                bits[j] = '0'; 
     309        } 
     310 
     311        PJ_LOG(3,(THIS_FILE, "%2d %s [%d]", i, bits, val)); 
     312    } 
     313    PJ_LOG(3,(THIS_FILE, "end dump")); 
     314} 
    249315 
    250316/* 
     
    311377        } 
    312378 
     379#if 1 
     380        if (hdr->pt == 101) { 
     381            dump_bin((char*)payload, payloadlen); 
     382            continue; 
     383        } 
     384#endif 
     385 
    313386        status = pjmedia_rtp_session_update(&channel->rtp, hdr); 
    314387        if (status != 0 &&  
     
    739812} 
    740813 
     814/* 
     815 * Dial DTMF 
     816 */ 
     817PJ_DEF(pj_status_t) pjmedia_stream_dial_dtmf( pjmedia_stream *stream, 
     818                                              const pj_str_t *digit_char) 
     819{ 
     820    pj_status_t status = PJ_SUCCESS; 
     821 
     822    /* By convention we use jitter buffer mutex to access DTMF 
     823     * queue. 
     824     */ 
     825    PJ_ASSERT_RETURN(stream && digit_char, PJ_EINVAL); 
     826 
     827    pj_mutex_lock(stream->jb_mutex); 
     828     
     829    if (stream->dtmf_count+digit_char->slen >= 
     830        PJ_ARRAY_SIZE(stream->dtmf_queue)) 
     831    { 
     832        status = PJ_ETOOMANY; 
     833    } else { 
     834        int i; 
     835 
     836        /* convert ASCII digits into payload type first, to make sure 
     837         * that all digits are valid.  
     838         */ 
     839        for (i=0; i<digit_char->slen; ++i) { 
     840            unsigned pt; 
     841 
     842            if (digit_char->ptr[i] >= '0' && 
     843                digit_char->ptr[i] <= '9') 
     844            { 
     845                pt = digit_char->ptr[i] - '0'; 
     846            }  
     847            else if (pj_tolower(digit_char->ptr[i]) >= 'a' && 
     848                     pj_tolower(digit_char->ptr[i]) <= 'd') 
     849            { 
     850                pt = pj_tolower(digit_char->ptr[i]) - 'a' + 12; 
     851            } 
     852            else if (digit_char->ptr[i] == '*') 
     853            { 
     854                pt = 10; 
     855            } 
     856            else if (digit_char->ptr[i] == '#') 
     857            { 
     858                pt = 11; 
     859            } 
     860            else 
     861            { 
     862                status = PJMEDIA_RTP_EINDTMF; 
     863                break; 
     864            } 
     865 
     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; 
     872        } 
     873 
     874        if (status != PJ_SUCCESS) 
     875            goto on_return; 
     876 
     877        if (stream->dtmf_count ==0) { 
     878            pj_uint32_t start_ts; 
     879 
     880            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; 
     883        } 
     884 
     885        /* Increment digit count only if all digits are valid. */ 
     886        stream->dtmf_count += digit_char->slen; 
     887 
     888    } 
     889 
     890on_return: 
     891    pj_mutex_unlock(stream->jb_mutex); 
     892 
     893    return status; 
     894} 
     895 
Note: See TracChangeset for help on using the changeset viewer.