diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index c9000de1f2..1e282d1138 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2743,10 +2743,9 @@ static ftdm_status_t ftdmchan_activate_dtmf_buffer(ftdm_channel_t *ftdmchan) if (!ftdmchan->dtmf_buffer) { if (ftdm_buffer_create(&ftdmchan->dtmf_buffer, 1024, 3192, 0) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate DTMF Buffer!\n"); - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "buffer error"); return FTDM_FAIL; } else { - ftdm_log(FTDM_LOG_DEBUG, "Created DTMF Buffer!\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Created DTMF buffer\n"); } } @@ -3588,8 +3587,17 @@ static FIO_READ_FUNCTION(ftdm_raw_read) return status; } -static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) +/* This function takes care of automatically generating DTMF or FSK tones when needed */ +static ftdm_status_t handle_tone_generation(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) { + /* + * datalen: size in bytes of the chunk of data the user requested to read (this function + * is called from the ftdm_channel_read function) + * dblen: size currently in use in any of the tone generation buffers (data available in the buffer) + * gen_dtmf_buffer: buffer holding the raw ASCII digits that the user requested to generate + * dtmf_buffer: raw linear tone data generated by teletone to be written to the devices + * fsk_buffer: raw linear FSK modulated data for caller id + */ ftdm_buffer_t *buffer = NULL; ftdm_size_t dblen = 0; int wrote = 0; @@ -3604,7 +3612,7 @@ static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) } if (ftdm_buffer_read(ftdmchan->gen_dtmf_buffer, digits, dblen) && !ftdm_strlen_zero_buf(digits)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generating DTMF [%s]\n", digits); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generating DTMF [%s]\n", digits); cur = digits; @@ -3618,7 +3626,7 @@ static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) ftdm_buffer_write(ftdmchan->dtmf_buffer, ftdmchan->tone_session.buffer, wrote * 2); x++; } else { - ftdm_log(FTDM_LOG_ERROR, "%d:%d Problem Adding DTMF SEQ [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, digits); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Problem adding DTMF sequence [%s]\n", digits); return FTDM_FAIL; } } @@ -3631,6 +3639,7 @@ static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) if (!ftdmchan->buffer_delay || --ftdmchan->buffer_delay == 0) { + /* time to pick a buffer, either the dtmf or fsk buffer */ if (ftdmchan->dtmf_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) { buffer = ftdmchan->dtmf_buffer; } else if (ftdmchan->fsk_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->fsk_buffer))) { @@ -3638,22 +3647,41 @@ static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) } } + /* if we picked a buffer, time to read from it and write the linear data to the device */ if (buffer) { - ftdm_size_t dlen = datalen; uint8_t auxbuf[1024]; + /* we initialize dlen to datalen, which is the size in bytes the + * user wants to read (typically chunks of 160 bytes, 20ms G.711) */ + ftdm_size_t dlen = datalen; ftdm_size_t len, br, max = sizeof(auxbuf); + /* if the codec is not linear, then data is really twice as much cuz + tone generation is done in linear (we assume anything different than linear is G.711) */ if (ftdmchan->native_codec != FTDM_CODEC_SLIN) { dlen *= 2; } - + + /* we do not expect the user chunks to be bigger than auxbuf */ + ftdm_assert(dlen <= sizeof(auxbuf), "Unexpected size for user data chunk size\n"); + + /* dblen is the size in use for dtmf_buffer or fsk_buffer, and dlen is the size + * of the read chunks of the user, we pick the smaller one */ len = dblen > dlen ? dlen : dblen; + /* we can't read more than the size of our auxiliary buffer */ + ftdm_assert((len <= sizeof(auxbuf)), "Unexpected size to read into auxbuf\n"); + br = ftdm_buffer_read(buffer, auxbuf, len); + + /* the amount read can't possibly be bigger than what we requested */ + ftdm_assert((br <= len), "Unexpected size read from tone generation buffer\n"); + + /* if we read less than the chunk size, we must fill in with silence the rest */ if (br < dlen) { memset(auxbuf + br, 0, dlen - br); } + /* finally we convert to the native format for the channel if necessary */ if (ftdmchan->native_codec != FTDM_CODEC_SLIN) { if (ftdmchan->native_codec == FTDM_CODEC_ULAW) { fio_slin2ulaw(auxbuf, max, &dlen); @@ -3662,6 +3690,7 @@ static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen) } } + /* write the tone to the channel */ return ftdm_raw_write(ftdmchan, auxbuf, &dlen); } @@ -3741,7 +3770,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data rdata[i] = ftdmchan->rxgain_table[rdata[i]]; } } - handle_dtmf(ftdmchan, *datalen); + handle_tone_generation(ftdmchan, *datalen); if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) { if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) { @@ -3938,7 +3967,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *dat if (!ftdmchan->buffer_delay && ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer)) || (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer)))) { - /* read size writing DTMF ATM */ + /* generating some kind of tone at the moment (see handle_tone_generation), + * we ignore user data ... */ goto done; }