diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/channel.c | 73 | ||||
-rw-r--r-- | main/frame.c | 8 | ||||
-rw-r--r-- | main/rtp.c | 36 |
3 files changed, 77 insertions, 40 deletions
diff --git a/main/channel.c b/main/channel.c index 21007b7f6..925d5d363 100644 --- a/main/channel.c +++ b/main/channel.c @@ -104,8 +104,8 @@ unsigned long global_fin, global_fout; AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init); #define STATE2STR_BUFSIZE 32 -/* XXX 100ms ... this won't work with wideband support */ -#define AST_DEFAULT_EMULATE_DTMF_SAMPLES 800 +/*! 100ms */ +#define AST_DEFAULT_EMULATE_DTMF_DURATION 100 struct chanlist { const struct ast_channel_tech *tech; @@ -2086,14 +2086,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) if (!ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF) && !ast_strlen_zero(chan->dtmfq)) { /* We have DTMF that has been deferred. Return it now */ - chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN; chan->dtmff.subclass = chan->dtmfq[0]; /* Drop first digit from the buffer */ memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1); f = &chan->dtmff; - ast_set_flag(chan, AST_FLAG_EMULATE_DTMF); - chan->emulate_dtmf_digit = f->subclass; - chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES; + if (ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) + chan->dtmff.frametype = AST_FRAME_DTMF_END; + else { + chan->dtmff.frametype = AST_FRAME_DTMF_BEGIN; + ast_set_flag(chan, AST_FLAG_EMULATE_DTMF); + chan->emulate_dtmf_digit = f->subclass; + chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION; + chan->dtmf_begin_tv = ast_tvnow(); + } goto done; } @@ -2211,38 +2216,47 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) break; case AST_FRAME_DTMF_END: ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name); - if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF)) { + /* Queue it up if DTMF is deffered, or if DTMF emulation is forced. + * However, only let emulation be forced if the other end cares about BEGIN frames */ + if ( ast_test_flag(chan, AST_FLAG_DEFER_DTMF) || + (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) ) { if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2) chan->dtmfq[strlen(chan->dtmfq)] = f->subclass; else ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name); ast_frfree(f); f = &ast_null_frame; - } else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF)) { + } else if (!ast_test_flag(chan, AST_FLAG_IN_DTMF | AST_FLAG_END_DTMF_ONLY)) { f->frametype = AST_FRAME_DTMF_BEGIN; ast_set_flag(chan, AST_FLAG_EMULATE_DTMF); chan->emulate_dtmf_digit = f->subclass; - if (f->samples) - chan->emulate_dtmf_samples = f->samples; + chan->dtmf_begin_tv = ast_tvnow(); + if (f->len) + chan->emulate_dtmf_duration = f->len; else - chan->emulate_dtmf_samples = AST_DEFAULT_EMULATE_DTMF_SAMPLES; - } else + chan->emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION; + } else { ast_clear_flag(chan, AST_FLAG_IN_DTMF); + if (!f->len) + f->len = ast_tvdiff_ms(chan->dtmf_begin_tv, ast_tvnow()); + } break; case AST_FRAME_DTMF_BEGIN: ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name); - if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) { + if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF | AST_FLAG_END_DTMF_ONLY)) { ast_frfree(f); f = &ast_null_frame; - } else + } else { ast_set_flag(chan, AST_FLAG_IN_DTMF); + chan->dtmf_begin_tv = ast_tvnow(); + } break; case AST_FRAME_VOICE: /* The EMULATE_DTMF flag must be cleared here as opposed to when the samples * first get to zero, because we want to make sure we pass at least one * voice frame through before starting the next digit, to ensure a gap * between DTMF digits. */ - if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !chan->emulate_dtmf_samples) { + if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF) && !chan->emulate_dtmf_duration) { ast_clear_flag(chan, AST_FLAG_EMULATE_DTMF); chan->emulate_dtmf_digit = 0; } @@ -2251,12 +2265,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } else if (ast_test_flag(chan, AST_FLAG_EMULATE_DTMF)) { - if (f->samples >= chan->emulate_dtmf_samples) { - chan->emulate_dtmf_samples = 0; + if ((f->samples / 8) >= chan->emulate_dtmf_duration) { /* XXX 8kHz */ + chan->emulate_dtmf_duration = 0; f->frametype = AST_FRAME_DTMF_END; f->subclass = chan->emulate_dtmf_digit; } else { - chan->emulate_dtmf_samples -= f->samples; + chan->emulate_dtmf_duration -= f->samples / 8; /* XXX 8kHz */ ast_frfree(f); f = &ast_null_frame; } @@ -2531,12 +2545,12 @@ int ast_senddigit_begin(struct ast_channel *chan, char digit) return 0; } -int ast_senddigit_end(struct ast_channel *chan, char digit) +int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duration) { int res = -1; if (chan->tech->send_digit_end) - res = chan->tech->send_digit_end(chan, digit); + res = chan->tech->send_digit_end(chan, digit, duration); if (res && chan->generator) ast_playtones_stop(chan); @@ -2546,11 +2560,12 @@ int ast_senddigit_end(struct ast_channel *chan, char digit) int ast_senddigit(struct ast_channel *chan, char digit) { - ast_senddigit_begin(chan, digit); - - ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */ + if (!ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY)) { + ast_senddigit_begin(chan, digit); + ast_safe_sleep(chan, 100); /* XXX 100ms ... probably should be configurable */ + } - return ast_senddigit_end(chan, digit); + return ast_senddigit_end(chan, digit, 100); } int ast_prod(struct ast_channel *chan) @@ -2628,7 +2643,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) case AST_FRAME_DTMF_END: ast_clear_flag(chan, AST_FLAG_BLOCKING); ast_channel_unlock(chan); - res = ast_senddigit_end(chan, fr->subclass); + res = ast_senddigit_end(chan, fr->subclass, fr->len); ast_channel_lock(chan); CHECK_BLOCKING(chan); break; @@ -3917,6 +3932,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha nexteventts = ast_tvsub(nexteventts, ast_samp2tv(config->play_warning, 1000)); } + if (!c0->tech->send_digit_begin) + ast_set_flag(c1, AST_FLAG_END_DTMF_ONLY); + if (!c1->tech->send_digit_begin) + ast_set_flag(c0, AST_FLAG_END_DTMF_ONLY); + for (/* ever */;;) { struct timeval now = { 0, }; int to; @@ -4070,6 +4090,9 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha break; } + ast_clear_flag(c0, AST_FLAG_END_DTMF_ONLY); + ast_clear_flag(c1, AST_FLAG_END_DTMF_ONLY); + c0->_bridge = NULL; c1->_bridge = NULL; diff --git a/main/frame.c b/main/frame.c index 83599fff8..0cd0b03fb 100644 --- a/main/frame.c +++ b/main/frame.c @@ -496,11 +496,9 @@ struct ast_frame *ast_frdup(const struct ast_frame *f) strcpy((char *)out->src, f->src); } out->has_timing_info = f->has_timing_info; - if (f->has_timing_info) { - out->ts = f->ts; - out->len = f->len; - out->seqno = f->seqno; - } + out->ts = f->ts; + out->len = f->len; + out->seqno = f->seqno; return out; } diff --git a/main/rtp.c b/main/rtp.c index 9b4431d06..dc6efbd81 100644 --- a/main/rtp.c +++ b/main/rtp.c @@ -140,7 +140,7 @@ struct ast_rtp { char resp; unsigned int lasteventendseqn; int dtmfcount; - unsigned int dtmfduration; + unsigned int dtmfsamples; /* DTMF Transmission Variables */ unsigned int lastdigitts; char sending_digit; /* boolean - are we sending digits */ @@ -619,7 +619,7 @@ static struct ast_frame *send_dtmf(struct ast_rtp *rtp, enum ast_frame_type type if (option_debug) ast_log(LOG_DEBUG, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(rtp->them.sin_addr)); rtp->resp = 0; - rtp->dtmfduration = 0; + rtp->dtmfsamples = 0; return &ast_null_frame; } if (option_debug) @@ -709,18 +709,18 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat { unsigned int event; unsigned int event_end; - unsigned int duration; + unsigned int samples; char resp = 0; struct ast_frame *f = NULL; - /* Figure out event, event end, and duration */ + /* Figure out event, event end, and samples */ event = ntohl(*((unsigned int *)(data))); event >>= 24; event_end = ntohl(*((unsigned int *)(data))); event_end <<= 8; event_end >>= 24; - duration = ntohl(*((unsigned int *)(data))); - duration &= 0xFFFF; + samples = ntohl(*((unsigned int *)(data))); + samples &= 0xFFFF; /* Print out debug if turned on */ if (rtpdebug || option_debug > 2) @@ -745,19 +745,19 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN); } else if (event_end & 0x80 && rtp->lasteventendseqn != seqno && rtp->resp) { f = send_dtmf(rtp, AST_FRAME_DTMF_END); - f->samples = duration; + f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */ rtp->resp = 0; rtp->lasteventendseqn = seqno; } else if (ast_test_flag(rtp, FLAG_DTMF_COMPENSATE) && event_end & 0x80 && rtp->lasteventendseqn != seqno) { rtp->resp = resp; f = send_dtmf(rtp, AST_FRAME_DTMF_END); - f->samples = duration; + f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */ rtp->resp = 0; rtp->lasteventendseqn = seqno; } rtp->dtmfcount = dtmftimeout; - rtp->dtmfduration = duration; + rtp->dtmfsamples = samples; return f; } @@ -2000,7 +2000,7 @@ void ast_rtp_reset(struct ast_rtp *rtp) rtp->lasttxformat = 0; rtp->lastrxformat = 0; rtp->dtmfcount = 0; - rtp->dtmfduration = 0; + rtp->dtmfsamples = 0; rtp->seqno = 0; rtp->rxseqno = 0; } @@ -3180,6 +3180,22 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel audio_p1_res = AST_RTP_TRY_PARTIAL; } + /* If both sides are not using the same method of DTMF transmission + * (ie: one is RFC2833, other is INFO... then we can not do direct media. + * -------------------------------------------------- + * | DTMF Mode | HAS_DTMF | Accepts Begin Frames | + * |-----------|------------|-----------------------| + * | Inband | False | True | + * | RFC2833 | True | True | + * | SIP Info | False | False | + * -------------------------------------------------- + */ + if ( (ast_test_flag(p0, FLAG_HAS_DTMF) != ast_test_flag(p1, FLAG_HAS_DTMF)) || + (!c0->tech->send_digit_begin != !c1->tech->send_digit_begin)) { + audio_p0_res = AST_RTP_TRY_PARTIAL; + audio_p1_res = AST_RTP_TRY_PARTIAL; + } + /* Get codecs from both sides */ codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0; codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0; |