#include "precompile.h" #include "audiortp.h" #include "audioframe.h" #include "audiostream.h" #include "audiocontext.h" #include "audiolog.h" #include "other/jbuf.h" #include #include "memutil.h" #define CIRC_LEN(rd, wr, n) (((wr)+(n)-(rd))%(n)) #define CIRC_ADD(old, val, n) (((old)+(n)+(val))%(n)) #define CIRC_SUB(old, val, n) (((old)+(n)-(val))%(n)) #define CIRC_INC(i, n) CIRC_ADD(i, 1, n) #define CIRC_DEC(i, n) CIRC_SUB(i, 1, n) #define CIRC_IS_EMPTY(rd, wr) ((rd) == (wr)) #define JB_MAX 10 #define DTMF_DURATION 1600 #define DTMF_DURATION_STEP 320 #define DTMF_VOLUME 10 static const char digitmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#','A', 'B', 'C', 'D'}; static __inline int digit2event(int digit) { int event; switch (digit) { case '0':case '1':case '2':case '3':case '4': case '5':case '6':case '7':case '8':case '9': event = digit - '0'; break; case '*': event = 10; break; case '#': event = 11; break; case 'a':case 'b':case 'c':case 'd': event = 12 + digit - 'a'; break; default: return -1; } return event; } static int send_dtmf_digit(rtp_session_t *sess, rtp_dtmf_event *digit, unsigned dtmf_pt) { rtp_state *st = rtp_session_get_rtp_state(sess); rtp_session_send(sess, 0, dtmf_pt, digit->e, 0, (const char*)digit, sizeof(rtp_dtmf_event)); if (digit->e) { rtp_session_send(sess, 0, dtmf_pt, digit->e, 0, (const char*)digit, sizeof(rtp_dtmf_event)); rtp_session_send(sess, 0, dtmf_pt, digit->e, 0, (const char*)digit, sizeof(rtp_dtmf_event)); } return 0; } static int pt2bitsample(int pt) { switch (pt) { case RTP_PT_PCM16: return 16; case RTP_PT_PCM8: case RTP_PT_PCMA: case RTP_PT_PCMU: return 8; case RTP_PT_G729: return 1; default: break; } assert(0); return 0; } static apr_status_t read_frame(void *self, audioframe_t *frame) { audiortp_t *audiortp = CONTAINING_RECORD(self, audiortp_t, base); char buf[SUGGEST_FRAME_SIZE]; unsigned short seq; unsigned mark; unsigned ts; unsigned pt; int i; int max_recv_cnt = 5; // max int new_dtmf = 0; audiortp->m_rtp_tick++; /* read packet from net */ for (i = 0 ; i < max_recv_cnt; ++i) { int ret = rtp_session_recv_hook(audiortp->m_rtpsession, &pt, &mark, &ts, &seq, buf, sizeof(buf), audiortp->m_on_recv_hook, audiortp->m_hook_data); if (ret <= 0) break; audiortp->m_last_rtp_tick = audiortp->m_rtp_tick; if (pt == audiortp->m_recv_dtmf_pt) { /* dtmf */ if (ret == sizeof(rtp_dtmf_event)) { int digit[2]; int digit_cnt = 0; int j; rtp_dtmf_event *dtmf = (rtp_dtmf_event *)&buf[0]; if (ts != audiortp->m_recving_dtmf_ts) { audiortp->m_recving_dtmf_ts = ts; if (!audiortp->m_recving_dtmf_event.e) digit[digit_cnt++] = audiortp->m_recving_dtmf_event.event; audiortp->m_recving_dtmf_event.event = dtmf->event; audiortp->m_recving_dtmf_event.e = dtmf->e; if (audiortp->m_recving_dtmf_event.e) digit[digit_cnt++] = audiortp->m_recving_dtmf_event.event; } else { if (dtmf->e) { /* end bit set */ if (!audiortp->m_recving_dtmf_event.e) { audiortp->m_recving_dtmf_event.e = 1; audiortp->m_recving_dtmf_event.event = dtmf->event; digit[digit_cnt++] = audiortp->m_recving_dtmf_event.event; } else { if (audiortp->m_recving_dtmf_event.event == 0xff) { audiortp->m_recving_dtmf_event.event = dtmf->event; digit[digit_cnt++] = audiortp->m_recving_dtmf_event.event; } } } else { audiortp->m_recving_dtmf_event.event = dtmf->event; } } for (j = 0; j < digit_cnt; ++j) { if (digit[j] < sizeof(digitmap)) { int ch = digitmap[digit[j]]; audiostream_raise_event(self, STREAM_EVT_RTP_DTMF, digit[j], 0); EnterCriticalSection(&audiortp->m_dtmf_lock); if (audiortp->m_recv_dtmf_cnt < MAX_DTMF) audiortp->m_recv_dtmf[audiortp->m_recv_dtmf_cnt++] = digit[j]; LeaveCriticalSection(&audiortp->m_dtmf_lock); } } if (digit_cnt > 0) new_dtmf = digit[digit_cnt-1]; // the last one } } else if (pt == audiortp->m_recv_pt) { /* audio frame */ if (ret == audiortp->m_recv_psize) { int time_span = (audiortp->m_recv_clock / 1000 * audiortp->m_recv_ptime); jbuf_put_frame2(audiortp->m_jitterbuf, &buf[0], ret, 0, ts / time_span, NULL); } } else { break; } audiortp->m_last_rtp_tick = audiortp->m_rtp_tick; } if (audiortp->m_timeout > 0) { unsigned int diffms = (audiortp->m_rtp_tick - audiortp->m_last_rtp_tick) * FRAME_TIME; if (diffms >= (unsigned)audiortp->m_timeout) { audiostream_raise_event(self, STREAM_EVT_RTP_TIMEOUT, 0, 0); } } { char frm_type; jbuf_get_frame(audiortp->m_jitterbuf, frame->buffer, &frm_type); if (frm_type == JB_NORMAL_FRAME) { frame->size = audiortp->m_jbuf_psize; } else { frame->size = 0; } } frame->dtmf = new_dtmf; return APR_SUCCESS; } static apr_status_t write_frame(void *self, const audioframe_t *frame) { audiortp_t *audiortp = CONTAINING_RECORD(self, audiortp_t, base); int dtmf = 0; EnterCriticalSection(&audiortp->m_dtmf_lock); if (frame->dtmf && CIRC_LEN(audiortp->m_send_dtmf_rd, audiortp->m_send_dtmf_wr, MAX_DTMF) < MAX_DTMF-1) { rtp_dtmf_event *dtmf = &audiortp->m_send_dtmf[audiortp->m_send_dtmf_wr]; dtmf->event = (unsigned char)digit2event(frame->dtmf); dtmf->e_vol = DTMF_VOLUME; dtmf->p = 0; dtmf->e = 0; dtmf->duration = 0; audiortp->m_send_dtmf_wr = CIRC_INC(audiortp->m_send_dtmf_wr, MAX_DTMF); } if (!CIRC_IS_EMPTY(audiortp->m_send_dtmf_rd, audiortp->m_send_dtmf_wr)) { rtp_dtmf_event *digit = &audiortp->m_send_dtmf[audiortp->m_send_dtmf_rd]; send_dtmf_digit(audiortp->m_rtpsession, digit, audiortp->m_send_dtmf_pt); dtmf = 1; digit->duration += DTMF_DURATION_STEP; if (!digit->e) { if (digit->duration == DTMF_DURATION) { digit->e = 1; } } else { audiortp->m_send_dtmf_rd = CIRC_INC(audiortp->m_send_dtmf_rd, MAX_DTMF); rtp_session_advance_timestamp(audiortp->m_rtpsession, DTMF_DURATION); } } LeaveCriticalSection(&audiortp->m_dtmf_lock); if (dtmf) { /* because we send dtmf, so ignore this frame */ return 0; } if (frame->size < (unsigned long)audiortp->m_send_psize) { if (frame->size) { memcpy(audiortp->m_SendSample.buffer + audiortp->m_SendSample.size, frame->buffer, frame->size); audiortp->m_SendSample.size += frame->size; } else { char tmp[160]; int tmp_cnt = FRAME_TIME * audiortp->m_send_clock / 1000 * audiortp->m_send_samplebit / 8; memset(tmp, 0, tmp_cnt); memcpy(audiortp->m_SendSample.buffer + audiortp->m_SendSample.size, tmp, tmp_cnt); audiortp->m_SendSample.size += tmp_cnt; } if (audiortp->m_SendSample.size >= (unsigned long)audiortp->m_send_psize) { //printf("send out %d\n", audiortp->m_send_psize); rtp_session_send_hook(audiortp->m_rtpsession, 0, audiortp->m_send_pt, 0, audiortp->m_send_ptime*audiortp->m_send_clock/1000, audiortp->m_SendSample.buffer, audiortp->m_send_psize, audiortp->m_on_send_hook, audiortp->m_hook_data); if (audiortp->m_SendSample.size > (unsigned long)audiortp->m_send_psize) { audiortp->m_SendSample.size -= audiortp->m_send_psize; memmove(audiortp->m_SendSample.buffer, audiortp->m_SendSample.buffer+audiortp->m_send_psize, audiortp->m_SendSample.size); } else { audiortp->m_SendSample.size = 0; } } } else { int delta_ts = audiortp->m_send_ptime*audiortp->m_send_clock/1000; rtp_session_send_hook(audiortp->m_rtpsession, 0, audiortp->m_send_pt, 0, delta_ts, frame->buffer, audiortp->m_send_psize, audiortp->m_on_send_hook, audiortp->m_hook_data); if (frame->size > (unsigned long)audiortp->m_send_psize) { audiortp->m_SendSample.size = frame->size-audiortp->m_send_psize; memcpy(audiortp->m_SendSample.buffer, frame->buffer+audiortp->m_send_psize, audiortp->m_SendSample.size); } } return APR_SUCCESS; } static audiostream_vtbl_t g_stream_vtbl = { &read_frame, &write_frame, }; void audiortp_destroy(audiortp_t *self) { audiortp_t *audiortp = (audiortp_t *)self; DeleteCriticalSection(&audiortp->m_dtmf_lock); } apr_status_t audiortp_create(apr_pool_t *pool, audioengine_t *engine, rtp_session_t *sess, audiortp_t **p_audiortp) { audiortp_t *audiortp; audiortp = apr_palloc(pool, sizeof(audiortp_t)); memset(audiortp, 0, sizeof(audiortp_t)); audiostream_init(engine, &g_stream_vtbl, &audiortp->base); audiortp->m_rtpsession = sess; audiortp->m_SendSample.buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE); audiortp->m_SendSample.size = 0; audiortp->m_SendSample.dtmf = 0; audiortp->m_RecvSample.buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE); audiortp->m_RecvSample.size = 0; audiortp->m_RecvSample.dtmf = 0; audiortp->m_send_ptime = 0; audiortp->m_recv_ptime = 0; audiortp->m_send_psize = 0; audiortp->m_recv_psize = 0; audiortp->m_send_samplebit = 0; audiortp->m_recv_samplebit = 0; audiortp->m_timeout = -1; audiortp->m_send_pt = -1; audiortp->m_recv_pt = -1; audiortp->m_send_clock = 8000; audiortp->m_recv_clock = 8000; audiortp->m_send_dtmf_rd = 0; audiortp->m_send_dtmf_wr = 0; audiortp->m_recv_dtmf_cnt = 0; audiortp->m_recving_dtmf_ts = 0; audiortp->m_recving_dtmf_event.e = 1; audiortp->m_recving_dtmf_event.event = 0xff; audiortp->m_rtp_tick = 0; audiortp->m_last_rtp_tick = 0; audiortp->m_jitterbuf = 0; audiortp->m_on_recv_hook = NULL; audiortp->m_on_send_hook = NULL; audiortp->m_hook_data = NULL; InitializeCriticalSection(&audiortp->m_dtmf_lock); *p_audiortp = audiortp; return APR_SUCCESS; } apr_status_t audiortp_set_param(audiortp_t *audiortp, int flag, const void *ptr) { audiortp_t *rtp = (audiortp_t *)audiortp; switch (flag) { case AUDIO_RTP_FLAG_RECV_PTIME: rtp->m_recv_ptime = *(const int *)ptr; break; case AUDIO_RTP_FLAG_SEND_PTIME: rtp->m_send_ptime = *(const int *)ptr; break; case AUDIO_RTP_FLAG_RECV_PT: rtp->m_recv_pt = *(const int *)ptr; break; case AUDIO_RTP_FLAG_SEND_PT: rtp->m_send_pt = *(const int*)ptr; break; case AUDIO_RTP_FLAG_TIMEOUT: rtp->m_timeout = *(const int *)ptr; break; case AUDIO_RTP_FLAG_SEND_DTMF: rtp->m_send_dtmf_pt = *(const int *)ptr; break; case AUDIO_RTP_FLAG_RECV_DTMF: rtp->m_recv_dtmf_pt = *(const int *)ptr; break; case AUDIO_RTP_FLAG_SEND_CLOCK: rtp->m_send_clock = *(const int*)ptr; break; case AUDIO_RTP_FLAG_RECV_CLOCK: rtp->m_recv_clock = *(const int*)ptr; break; case AUDIO_RTP_FLAG_SEND_HOOK: rtp->m_on_send_hook = /**(void (**)(const char*,int,void*))*/(void*)ptr; break; case AUDIO_RTP_FLAG_RECV_HOOK: rtp->m_on_recv_hook = /**(void (**)(const char*,int,void*))*/(void*)ptr; break; case AUDIO_RTP_FLAG_HOOK_ARG: rtp->m_hook_data = /**(void**)*/(void*)ptr; break; default: return APR_BADARG; } return APR_SUCCESS; } apr_status_t audiortp_get_param(audiortp_t *audiortp, int flag, void *ptr) { audiortp_t *rtp = (audiortp_t *)audiortp; switch (flag) { case AUDIO_RTP_FLAG_RECV_PTIME: *(int *)ptr = rtp->m_recv_ptime; break; case AUDIO_RTP_FLAG_SEND_PTIME: *(int *)ptr = rtp->m_send_ptime; break; case AUDIO_RTP_FLAG_RECV_PT: *(int *)ptr = rtp->m_recv_pt; break; case AUDIO_RTP_FLAG_SEND_PT: *(int*)ptr = rtp->m_send_pt; break; case AUDIO_RTP_FLAG_TIMEOUT: *(int *)ptr = rtp->m_timeout; break; case AUDIO_RTP_FLAG_SEND_DTMF: *(int *)ptr = rtp->m_send_dtmf_pt; break; case AUDIO_RTP_FLAG_RECV_DTMF: *(int *)ptr = rtp->m_recv_dtmf_pt; break; case AUDIO_RTP_FLAG_SEND_CLOCK: *(int*)ptr = rtp->m_send_clock; break; case AUDIO_RTP_FLAG_RECV_CLOCK: *(int*)ptr = rtp->m_recv_clock; break; case AUDIO_RTP_FLAG_SEND_HOOK: *(void (**)(const char*,int,void*))ptr = rtp->m_on_send_hook; break; case AUDIO_RTP_FLAG_RECV_HOOK: *(void (**)(const char*,int,void*))ptr = rtp->m_on_recv_hook; break; case AUDIO_RTP_FLAG_HOOK_ARG: *(void**)ptr = rtp->m_hook_data; break; default: return APR_BADARG; } return APR_SUCCESS; } apr_status_t audiortp_init(audiortp_t *ar) { audiortp_t *audiortp = (audiortp_t *)ar; audiortp->m_send_samplebit = pt2bitsample(audiortp->m_send_pt); audiortp->m_recv_samplebit = pt2bitsample(audiortp->m_recv_pt); audiortp->m_send_psize = audiortp->m_send_ptime * audiortp->m_send_clock / 1000 * audiortp->m_send_samplebit / 8; audiortp->m_recv_psize = audiortp->m_recv_ptime * audiortp->m_recv_clock / 1000 * audiortp->m_recv_samplebit / 8; audiortp->m_jbuf_ptime = audiortp->m_recv_ptime; audiortp->m_jbuf_psize = audiortp->m_jbuf_ptime * audiortp->m_recv_clock / 1000 * audiortp->m_recv_samplebit / 8; jbuf_create(audiortp->m_jbuf_psize, audiortp->m_jbuf_ptime, JB_MAX, &audiortp->m_jitterbuf); jbuf_set_adaptive(audiortp->m_jitterbuf, 0, 7, JB_MAX); DEBUG_TRACE("audiortp init, send_psize:%d, recv_psize:%d", audiortp->m_send_psize, audiortp->m_recv_psize); return APR_SUCCESS; } apr_status_t audiortp_term(audiortp_t *self) { audiortp_t *audiortp = (audiortp_t *)self; jbuf_destroy(audiortp->m_jitterbuf); audiortp->m_jitterbuf = 0; return APR_SUCCESS; } apr_status_t audiortp_send_dtmf(audiortp_t *self, const char *digits, unsigned cnt) { audiortp_t *audiortp = (audiortp_t *)self; unsigned count = 0; if (!(audiostream_get_direction(&audiortp->base)&STREAM_DIR_WRITE)) { AUDIO_LOG_ERROR("audio rtp cannot used for send!"); return APR_EGENERAL; } if (!digits || !cnt) return -1; if (!(audiostream_get_direction(&audiortp->base)&STREAM_DIR_WRITE)) return -1; EnterCriticalSection(&audiortp->m_dtmf_lock); while (CIRC_LEN(audiortp->m_send_dtmf_rd, audiortp->m_send_dtmf_wr, MAX_DTMF) < MAX_DTMF-1 && count < cnt) { rtp_dtmf_event *dtmf = &audiortp->m_send_dtmf[audiortp->m_send_dtmf_wr]; dtmf->event = (unsigned char)digit2event(digits[count]); dtmf->e_vol = DTMF_VOLUME; dtmf->p = 0; dtmf->e = 0; dtmf->duration = 0; audiortp->m_send_dtmf_wr = CIRC_INC(audiortp->m_send_dtmf_wr, MAX_DTMF); count ++; } LeaveCriticalSection(&audiortp->m_dtmf_lock); return APR_SUCCESS; } apr_status_t audiortp_recv_dtmf(audiortp_t *self, char *digits, unsigned *cnt) { audiortp_t *audiortp = (audiortp_t *)self; unsigned count = 0; int i = 0; if (!(audiostream_get_direction(&audiortp->base)&STREAM_DIR_READ)) { AUDIO_LOG_ERROR("audio rtp cannot used for recv!"); return APR_EGENERAL; } if (!digits) return APR_BADARG; EnterCriticalSection(&audiortp->m_dtmf_lock); while (count < *cnt && i < audiortp->m_recv_dtmf_cnt) { digits[count++] = audiortp->m_recv_dtmf[i++]; } if (i < audiortp->m_recv_dtmf_cnt) memmove(&audiortp->m_recv_dtmf[0], &audiortp->m_recv_dtmf[i], audiortp->m_recv_dtmf_cnt-i); audiortp->m_recv_dtmf_cnt -= i; *cnt = count; LeaveCriticalSection(&audiortp->m_dtmf_lock); return APR_SUCCESS; } apr_status_t audiortp_reset_jitter(audiortp_t *audiortp) { jbuf_reset(audiortp->m_jitterbuf); return APR_SUCCESS; }