Location>code7788 >text

Bugs and fixes of spandsp_start_dtmf

Popularity:897 ℃/2025-01-23 17:51:37

Overview

freeswitch is a simple and easy-to-use VOIP open source soft switching platform.

The previous article introduced the conversion of DTMF from 2833 to inband. The conversion of inband to 2833 uses "spandsp_start_dtmf". This function has defects in the conversion process.

environment

CentOS 7.9

freeswitch 1.10.7

Problem description

In fs bridged calls, "spandsp_start_dtmf" processes the dtmf button in the inband. When switching to otherleg, the 2833 dtmf can be generated normally, but the waveform in the inband is not deleted cleanly enough. If the subsequent voice node will detect the inband, This will cause the problem of duplicate codes.

 

solution

Modify the idea. During spandsp's processing of dtmf waveforms, 2 media packets are cached. When DTMF is detected, the cached media packets are cleared.

Modify mod_dtptools.c

case SWITCH_DTMF_RTP:
    switch_channel_set_variable(switch_core_session_get_channel(session), "deduplicate_dtmf_seen_rtp", "true");
    /* change state to only allow RTP events */
    filter->only_rtp = 1;

    //modify by zr, 20241021, for DTMF inband to 2833
    /* stop inband detector */
    // switch_ivr_broadcast(switch_core_session_get_uuid(session), "spandsp_stop_dtmf::", SMF_ECHO_ALEG);
    break;

Modify mod_spandsp_dsp.c

//modify by zr, 20241021, for DTMF inband to 2833
#define INBAND_DTMF_BUF_SIZE (2)
#define INBAND_DTMF_BUF_LEN (512)

typedef struct {
	switch_core_session_t *session;
	dtmf_rx_state_t *dtmf_detect;
	int verbose;
	char last_digit;
	uint32_t samples;
	uint32_t last_digit_end;
	uint32_t digit_begin;
	uint32_t min_dup_digit_spacing;
	int twist;
	int reverse_twist;
	int filter_dialtone;
	int threshold;
	switch_audio_resampler_t *resampler;
//modify by zr, 20241021, for DTMF inband to 2833
	char data_buf[INBAND_DTMF_BUF_SIZE][INBAND_DTMF_BUF_LEN];
	int buf_index;
} switch_inband_dtmf_t;

...

			dtmf_rx(pvt->dtmf_detect, dp, samples);

			//modify by zr, 20241021, for DTMF inband to 2833
			// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "dtmf_rx return, last_hit=%d, in_digit=%d, current_sample=%d,"
			// 														"duration=%d, lost_digits=%d, current_digits=%d\n", 
			// 														pvt->dtmf_detect->last_hit, pvt->dtmf_detect->in_digit, pvt->dtmf_detect->current_sample, 
			// 														pvt->dtmf_detect->duration, pvt->dtmf_detect->lost_digits, pvt->dtmf_detect->current_digits);
			
			if(pvt->dtmf_detect->filter_dialtone)
			{	
				// double buffer mode
				if(pvt->dtmf_detect->last_hit > 0 || pvt->dtmf_detect->in_digit > 0) 
				{
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, 
						"inband_dtmf_callback, memset frame to 0x00, pvt->dtmf_detect->last_hit=%d, pvt->dtmf_detect->in_digit=%d\n", 
						pvt->dtmf_detect->last_hit, pvt->dtmf_detect->in_digit);
					memset(pvt->data_buf, 0x00, INBAND_DTMF_BUF_LEN*INBAND_DTMF_BUF_SIZE);
					memset(frame->data, 0x00, frame->datalen);
				}
				else
				{
					char data_tmp[INBAND_DTMF_BUF_LEN] = {0};
					memcpy(data_tmp, frame->data, INBAND_DTMF_BUF_LEN);
					memcpy(frame->data, pvt->data_buf[pvt->buf_index], frame->datalen);
					memcpy(pvt->data_buf[pvt->buf_index], data_tmp, datalen);
				}
				pvt->buf_index = (1 - pvt->buf_index);
			}
			
			switch_core_media_bug_set_read_replace_frame(bug, frame);

...

	pvt->session = session;
	//modify by zr, 20241021, for DTMF inband to 2833
	pvt->buf_index = 0;

Modify switch_core_media.c

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Set 2833 dtmf send payload to %u recv payload to %u\n",
 switch_channel_get_name(session->channel), smh->mparams->te, smh->mparams->recv_te);

 //add by zr 20241018, for 2833 to inband, update method
 //If the inband mode has been set in the 183 negotiation, the function setting of the inband mode needs to be canceled in the subsequent update negotiation.
 if (switch_true(switch_channel_get_variable(session->channel, "inband_flag")))
 {
 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "reset inband_flag and channel variables.\n");
 //B road
 switch_channel_set_variable(session->channel, "inband_flag", NULL);
 switch_channel_set_variable(session->channel, "spandsp_dtmf_rx_filter_dialtone", NULL);
 switch_channel_set_variable(session->channel, "execute_on_answer_101", NULL);
 switch_channel_set_variable(session->channel, "execute_on_answer_102", NULL);

 //A road, 2833 to inband
 if( switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS )
 {
 switch_channel_set_variable(other_session->channel, "execute_on_answer_101", NULL);
 switch_core_session_rwunlock(other_session);
 }
 }

 } else {
 /* by default, use SIP INFO if 2833 is not in the SDP */
 if (!switch_false(switch_channel_get_variable(channel, "rtp_info_when_no_2833"))) {
 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No 2833 in SDP. Disable 2833 dtmf and switch to INFO\n");
 switch_channel_set_variable(session->channel, "dtmf_type", "info");
 smh->mparams->dtmf_type = DTMF_INFO;
 smh->mparams->recv_te = smh->mparams->te = 0;
 } else {
 // switch_channel_set_variable(session->channel, "dtmf_type", "none");
 // smh->mparams->dtmf_type = DTMF_NONE;
 // smh->mparams->recv_te = smh->mparams->te = 0;
 //add by zr 20241018, for 2833 to inband, update method
 switch_channel_set_variable(session->channel, "dtmf_type", "inband");
 smh->mparams->dtmf_type = DTMF_AUTO;
 smh->mparams->recv_te = smh->mparams->te = 0;
 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "set inband_flag, No 2833 in SDP. Disable 2833 dtmf and switch to INBAND.\n");
 					
 //TODO: add inband dtmf
 //A road, 2833 to inband
 if( switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS )
 {
 switch_channel_set_variable(other_session->channel, "execute_on_answer_101", "start_dtmf_generate");
 switch_core_session_rwunlock(other_session);
 }

 //B road, inband to 2833
 switch_channel_set_variable(session->channel, "inband_flag", "true");
 switch_channel_set_variable(session->channel, "spandsp_dtmf_rx_filter_dialtone", "true");
 switch_channel_set_variable(session->channel, "execute_on_answer_101", "deduplicate_dtmf");
 switch_channel_set_variable(session->channel, "execute_on_answer_102", "spandsp_start_dtmf");
 }
 }

test

The new fs bridge call is processed by "spandsp_start_dtmf" and the dtmf button in the inband is not left in the waveform of channel A.

 

Summarize

Because the inband media stream needs to be cached, this processing will produce a voice delay of about 40ms.

 

Empty as usual

Seek truth and get truth