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

Putting initial DTMF efforts

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.