Ejemplo n.º 1
0
int speex_aec_playback_for_async(int16_t* farend, float snd_amplification)
{
    int ret_val = -1;
    switch(aec_core_used)
    {
#ifdef WEBRTC_AEC_CORE_ENABLED
    case WEBRTC_AEC:
        if(webrtc_aec_pty.webrtc_aec)
            ret_val = WebRtcAec_BufferFarend(webrtc_aec_pty.webrtc_aec, farend, webrtc_aec_pty.frame_size);
        break;
    case WEBRTC_AECM:
        if(webrtc_aecm_pty.webrtc_aec)
            ret_val = WebRtcAecm_BufferFarend(webrtc_aecm_pty.webrtc_aec, farend, webrtc_aecm_pty.frame_size);
        break;
#endif
    case SPEEX_AEC:
    default:
        if(speex_aec_pty.speex_echo_state)
        {
            speex_echo_playback((SpeexEchoState*)speex_aec_pty.speex_echo_state, farend);
    //        speex_preprocess_run((SpeexPreprocessState*)speex_aec_pty.speex_preprocess_state_tmp, farend);
            ret_val = 0;
        }
        break;
    }

    if(snd_amplification != 1.0f && snd_amplification > 0)
    {
        for(int i=0; i<speex_aec_pty.frame_size; ++i)
            farend[i] = farend[i]*snd_amplification;
    }

    return ret_val;
}
Ejemplo n.º 2
0
static int tdav_speex_denoise_echo_playback(tmedia_denoise_t* self, const void* echo_frame)
{
	tdav_speex_denoise_t *denoiser = (tdav_speex_denoise_t *)self;
	if(denoiser->echo_state){
		speex_echo_playback(denoiser->echo_state, echo_frame);
	}
	return 0;
}
Ejemplo n.º 3
0
static int decode(struct aufilt_dec_st *st, int16_t *sampv, size_t *sampc)
{
    struct dec_st *dst = (struct dec_st *)st;
    struct speex_st *sp = dst->st;

    if (*sampc)
        speex_echo_playback(sp->state, sampv);

    return 0;
}
Ejemplo n.º 4
0
/*
 * Let AEC know that a frame was queued to be played.
 */
PJ_DEF(pj_status_t) speex_aec_playback( void *state,
					pj_int16_t *play_frm )
{
    speex_ec *echo = (speex_ec*) state;

    /* Sanity checks */
    PJ_ASSERT_RETURN(echo && play_frm, PJ_EINVAL);

    speex_echo_playback(echo->state, (spx_int16_t*)play_frm);

    return PJ_SUCCESS;

}
Ejemplo n.º 5
0
void t_audio_tx::run(void) {
	const AppDataUnit* adu;
	struct timespec sleeptimer;
	//struct timeval debug_timer, debug_timer_prev;
	int last_seqnum = -1; // seqnum of last received RTP packet
	
	// RTP packets with multiple SSRCs may be received. Each SSRC
	// represents an audio stream. Twinkle will only play 1 audio stream.
	// On a reception of a new SSRC, Twinkle will switch over to play the
	// new stream. This supports devices that change SSRC during a call.
	uint32 ssrc_current = 0;
	
	bool recvd_dtmf = false; // indicates if last RTP packets is a DTMF event

	// The running flag is set already in t_audio_session::run to prevent
	// a crash when the thread gets destroyed before it starts running.
	// is_running = true;

	uint32 rtp_timestamp = 0;
	
	// This thread may not take the lock on the transaction layer to
	// prevent dead locks
	phone->add_prohibited_thread();
	ui->add_prohibited_thread();
	
	while (true) {
		do {
			adu = NULL;
			if (stop_running) break;
			rtp_timestamp = rtp_session->getFirstTimestamp();
			adu = rtp_session->getData(
					rtp_session->getFirstTimestamp());
			if (adu == NULL || adu->getSize() <= 0) {
				// There is no packet available. This may have
				// several reasons:
				// - the thread scheduling granularity does
				//   not match ptime
				// - packet lost
				// - packet delayed
				// Wait another cycle for a packet. The
				// jitter buffer will cope with this variation.
				if (adu) {
					delete adu;
					adu = NULL;
				}

				// If we are the mixer in a 3-way call and there
				// is enough media from the other far-end then
				// this must be sent to the dsp.
				if (is_3way && is_3way_mixer &&
				    media_3way_peer_tx->size_content() >=
				    	ptime * (audio_sample_rate(codec) / 1000) * 2)
				{
					// Fill the sample buffer with silence
					int len = ptime * (audio_sample_rate(codec) / 1000) * 2;
					memset(sample_buf, 0, len);
					play_pcm(sample_buf, len, true);
				}

				// Sleep ptime ms
				sleeptimer.tv_sec = 0;

				if (ptime >= 20) {
					sleeptimer.tv_nsec =
						ptime * 1000000 - 10000000;
				} else {
					// With a thread schedule of 10ms
					// granularity, this will schedule the
					// thread every 10ms.
					sleeptimer.tv_nsec = 5000000;
				}
				nanosleep(&sleeptimer, NULL);
			}
		} while (adu == NULL || (adu->getSize() <= 0));
		
		if (stop_running) {
			if (adu) delete adu;
			break;
		}

		if (adu) {
			// adu is created by ccRTP, but we have to delete it,
			// so report it to MEMMAN
			MEMMAN_NEW(const_cast<ost::AppDataUnit*>(adu));
		}

		// Check for a codec change
		map<unsigned short, t_audio_codec>::const_iterator it_codec;
		it_codec = payload2codec.find(adu->getType());
		t_audio_codec recvd_codec = CODEC_NULL;
		if (it_codec != payload2codec.end()) {
			recvd_codec = it_codec->second;
		}
		
		// Switch over to new SSRC
		if (last_seqnum == -1 || ssrc_current != adu->getSource().getID()) {
			if (recvd_codec != CODEC_NULL) {
				ssrc_current = adu->getSource().getID();
				
				// An SSRC defines a sequence number space. So a new
				// SSRC starts with a new random sequence number
				last_seqnum = -1;
				
				log_file->write_header("t_audio_tx::run", 
					LOG_NORMAL);
				log_file->write_raw("Audio tx line ");
				log_file->write_raw(get_line()->get_line_number()+1);
				log_file->write_raw(": play SSRC ");
				log_file->write_raw(ssrc_current);
				log_file->write_endl();
				log_file->write_footer();
			} else {
				// SSRC received had an unsupported codec
				// Discard.
				// KLUDGE: for now this supports a scenario where a
				// far-end starts ZRTP negotiation by sending CN
				// packets with a separate SSRC while ZRTP is disabled
				// in Twinkle. Twinkle will then receive the CN packets
				// and discard them here as CN is an unsupported codec.
				log_file->write_header("t_audio_tx::run", 
					LOG_NORMAL, LOG_DEBUG);
				log_file->write_raw("Audio tx line ");
				log_file->write_raw(get_line()->get_line_number()+1);
				log_file->write_raw(": SSRC received (");
				log_file->write_raw(adu->getSource().getID());
				log_file->write_raw(") has unsupported codec ");
				log_file->write_raw(adu->getType());
				log_file->write_endl();
				log_file->write_footer();
				
				MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
				delete adu;
				continue;
			}
		}
		
		map<t_audio_codec, t_audio_decoder *>::const_iterator it_decoder;
		it_decoder = map_audio_decoder.find(recvd_codec);
		if (it_decoder != map_audio_decoder.end()) {
			if (codec != recvd_codec) {
				codec = recvd_codec;
				get_line()->ci_set_recv_codec(codec);
				ui->cb_async_recv_codec_changed(get_line()->get_line_number(),
					codec);

				log_file->write_header("t_audio_tx::run", 
					LOG_NORMAL, LOG_DEBUG);
				log_file->write_raw("Audio tx line ");
				log_file->write_raw(get_line()->get_line_number()+1);
				log_file->write_raw(": codec change to ");
				log_file->write_raw(ui->format_codec(codec));
				log_file->write_endl();
				log_file->write_footer();
			}
		} else {
			if (adu->getType() == pt_telephone_event ||
			    adu->getType() == pt_telephone_event_alt) 
			{
				recvd_dtmf = true;
			} else {
				if (codec != CODEC_UNSUPPORTED) {
					codec = CODEC_UNSUPPORTED;
					get_line()->ci_set_recv_codec(codec);
					ui->cb_async_recv_codec_changed(
						get_line()->get_line_number(), codec);
	
					log_file->write_header("t_audio_tx::run", 
						LOG_NORMAL, LOG_DEBUG);
					log_file->write_raw("Audio tx line ");
					log_file->write_raw(get_line()->get_line_number()+1);
					log_file->write_raw(": payload type ");
					log_file->write_raw(adu->getType());
					log_file->write_raw(" not supported\n");
					log_file->write_footer();
				}
	
				last_seqnum = adu->getSeqNum();
				MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
				delete adu;
				continue;
			}
		}

		// DTMF event
		if (recvd_dtmf) {
			// NOTE: the DTMF tone will be detected here
			// while there might still be data in the jitter
			// buffer. If the jitter buffer was already sent
			// to the DSP, then the DSP will continue to play
			// out the buffer sound samples.

			if (dtmf_previous_timestamp != rtp_timestamp) {
				// A new DTMF tone has been received.
				dtmf_previous_timestamp = rtp_timestamp;
				t_rtp_telephone_event *e =
					(t_rtp_telephone_event *)adu->getData();
				ui->cb_async_dtmf_detected(get_line()->get_line_number(),
					e->get_event());

				// Log DTMF event
				log_file->write_header("t_audio_tx::run");
				log_file->write_raw("Audio tx line ");
				log_file->write_raw(get_line()->get_line_number()+1);
				log_file->write_raw(": detected DTMF event - ");
				log_file->write_raw(e->get_event());
				log_file->write_endl();
				log_file->write_footer();
			}

			recvd_dtmf = false;
			last_seqnum = adu->getSeqNum();
			MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
			delete adu;
			continue;
		}

		// Discard invalide payload sizes
		if (!map_audio_decoder[codec]->valid_payload_size(
				adu->getSize(), SAMPLE_BUF_SIZE / 2))
		{
			log_file->write_header("t_audio_tx::run", LOG_NORMAL, LOG_DEBUG);
			log_file->write_raw("Audio tx line ");
			log_file->write_raw(get_line()->get_line_number()+1);
			log_file->write_raw(": RTP payload size (");
			log_file->write_raw((unsigned long)(adu->getSize()));
			log_file->write_raw(" bytes) invalid for \n");
			log_file->write_raw(ui->format_codec(codec));
			log_file->write_footer();
			last_seqnum = adu->getSeqNum();
			MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
			delete adu;
			continue;
		}
		
		unsigned short recvd_ptime;
		recvd_ptime = map_audio_decoder[codec]->get_ptime(adu->getSize());

		// Log a change of ptime
		if (ptime != recvd_ptime) {
			log_file->write_header("t_audio_tx::run", LOG_NORMAL, LOG_DEBUG);
			log_file->write_raw("Audio tx line ");
			log_file->write_raw(get_line()->get_line_number()+1);
			log_file->write_raw(": ptime changed from ");
			log_file->write_raw(ptime);
			log_file->write_raw(" ms to ");
			log_file->write_raw(recvd_ptime);
			log_file->write_raw(" ms\n");
			log_file->write_footer();
			ptime = recvd_ptime;
		}
		
		// Check for lost packets
		// This must be done before decoding the received samples as the
		// speex decoder has its own PLC algorithm for which it needs the decoding
		// state before decoding the new samples.
		seq16_t seq_recvd(adu->getSeqNum());
		seq16_t seq_last(static_cast<uint16>(last_seqnum));
		if (last_seqnum != -1 && seq_recvd - seq_last > 1) {
			// Packets have been lost
			uint16 num_lost = (seq_recvd - seq_last) - 1;
			log_file->write_header("t_audio_tx::run", LOG_NORMAL, LOG_DEBUG);
			log_file->write_raw("Audio tx line ");
			log_file->write_raw(get_line()->get_line_number()+1);
			log_file->write_raw(": ");
			log_file->write_raw(num_lost);
			log_file->write_raw(" RTP packets lost.\n");
			log_file->write_footer();

			if (num_lost <= conceal_num) {
				// Conceal packet loss
				conceal(num_lost);
			}
			clear_conceal_buf();
		}
		
		// Determine if resampling is needed due to dynamic change to
		// codec with other sample rate.
		short downsample_factor = 1;
		short upsample_factor = 1;
		if (audio_sample_rate(codec) > sc_sample_rate) {
			downsample_factor = audio_sample_rate(codec) / sc_sample_rate;
		} else if (audio_sample_rate(codec) < sc_sample_rate) {
			upsample_factor = sc_sample_rate / audio_sample_rate(codec);
		}
		
		// Create sample buffer. If no resampling is needed, the sample
		// buffer from the audio_tx object can be used directly.
		// Otherwise a temporary sample buffers is created that will
		// be resampled to the object's sample buffer later.
		short *sb;
		int sb_size;
		if (downsample_factor > 1) {
			sb_size = SAMPLE_BUF_SIZE / 2 * downsample_factor;
			sb = new short[sb_size];
			MEMMAN_NEW_ARRAY(sb);
		} else if (upsample_factor > 1) {
			sb_size = SAMPLE_BUF_SIZE / 2;
			sb = new short[SAMPLE_BUF_SIZE / 2];
			MEMMAN_NEW_ARRAY(sb);
		} else {
			sb_size = SAMPLE_BUF_SIZE / 2;
			sb = (short *)sample_buf;
		}
				
				
		// Decode the audio
		unsigned char *payload = const_cast<uint8 *>(adu->getData());
		short sample_size; // size in bytes
		
		sample_size = 2 * map_audio_decoder[codec]->decode(payload, adu->getSize(), sb, sb_size);
				
		// Resample if needed
		if (downsample_factor > 1) {
			short *p = sb;
			sb = (short *)sample_buf;
			for (int i = 0; i < sample_size / 2; i += downsample_factor) {
				sb[i / downsample_factor] = p[i];
			}
			MEMMAN_DELETE_ARRAY(p);
			delete [] p;
			sample_size /= downsample_factor;
		} else if (upsample_factor > 1) {
			short *p = sb;
			sb = (short *)sample_buf;
			for (int i = 0; i < sample_size / 2; i++) {
				for (int j = 0; j < upsample_factor; j++) {
					sb[i * upsample_factor + j] = p[i];
				}
			}
			MEMMAN_DELETE_ARRAY(p);
			delete [] p;
			sample_size *= upsample_factor;
		}
		
		// If the decoder deliverd 0 bytes, then it failed
		if (sample_size == 0) {
			last_seqnum = adu->getSeqNum();
			MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
			delete adu;	
			continue;
		}
		
		// Discard packet if we are lacking behind. This happens if the
		// soundcard plays at a rate less than the requested sample rate.
		if (rtp_session->isWaiting(&(adu->getSource()))) {

			uint32 last_ts = rtp_session->getLastTimestamp(&(adu->getSource()));
			uint32 diff;
			
			diff = last_ts - rtp_timestamp;
			
			if (diff > (uint32_t)(JITTER_BUF_SIZE(sc_sample_rate) / AUDIO_SAMPLE_SIZE) * 8)
			{
				log_file->write_header("t_audio_tx::run", LOG_NORMAL, LOG_DEBUG);
				log_file->write_raw("Audio tx line ");
				log_file->write_raw(get_line()->get_line_number()+1);
				log_file->write_raw(": discard delayed packet.\n");
				log_file->write_raw("Timestamp: ");
				log_file->write_raw(rtp_timestamp);
				log_file->write_raw(", Last timestamp: ");
				log_file->write_raw((long unsigned int)last_ts);
				log_file->write_endl();
				log_file->write_footer();
					
				last_seqnum = adu->getSeqNum();
				MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
				delete adu;
				continue;
			}
		}

		play_pcm(sample_buf, sample_size);
		retain_for_concealment(sample_buf, sample_size);
		last_seqnum = adu->getSeqNum();
		MEMMAN_DELETE(const_cast<ost::AppDataUnit*>(adu));
		delete adu;

		// No sleep is done here but in the loop waiting
		// for a new packet. If a packet is already available
		// it can be send to the sound card immediately so
		// the play-out buffer keeps filled.
		// If the play-out buffer gets empty you hear a
		// crack in the sound.


#ifdef HAVE_SPEEX		
		// store decoded output for (optional) echo cancellation 
		if (audio_session->get_do_echo_cancellation()) {
		    if (audio_session->get_echo_captured_last()) {
			speex_echo_playback(audio_session->get_speex_echo_state(), (spx_int16_t *) sb);
			audio_session->set_echo_captured_last(false);;
		    }
		}
#endif

	}

	phone->remove_prohibited_thread();
	ui->remove_prohibited_thread();
	is_running = false;
}
Ejemplo n.º 6
0
int main(int argc, char *argv[])
{

    int sd, rc, n;
    int i;
    struct sockaddr_in cliAddr, remoteAddr;
    char msg[MAX_MSG];
    struct hostent *h;
    int local_port, remote_port;
    int nfds;
    struct pollfd *pfds;
    SpeexPreprocessState *preprocess;
    AlsaDevice *audio_dev;
    int tmp;

    if (argc != 5)
    {
        fprintf(stderr, "wrong options\n");
        exit(1);
    }

    h = gethostbyname(argv[2]);
    if(h==NULL) {
        fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[1]);
        exit(1);
    }

    local_port = atoi(argv[3]);
    remote_port = atoi(argv[4]);

    printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,
           inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));

    {
        remoteAddr.sin_family = h->h_addrtype;
        memcpy((char *) &remoteAddr.sin_addr.s_addr,
               h->h_addr_list[0], h->h_length);
        remoteAddr.sin_port = htons(remote_port);
    }
    /* socket creation */
    sd=socket(AF_INET, SOCK_DGRAM, 0);
    if(sd<0) {
        printf("%s: cannot open socket \n",argv[0]);
        exit(1);
    }

    /* bind any port */
    cliAddr.sin_family = AF_INET;
    cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    cliAddr.sin_port = htons(local_port);

    rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
    if(rc<0) {
        printf("%s: cannot bind port\n", argv[0]);
        exit(1);
    }

    /* Setup audio device */
    audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, 1, FRAME_SIZE);

    /* Setup the encoder and decoder in wideband */
    void *enc_state, *dec_state;
    enc_state = speex_encoder_init(&speex_wb_mode);
    tmp = 8;
    speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp);
    tmp = 2;
    speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &tmp);
    dec_state = speex_decoder_init(&speex_wb_mode);
    tmp = 1;
    speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &tmp);
    SpeexBits enc_bits, dec_bits;
    speex_bits_init(&enc_bits);
    speex_bits_init(&dec_bits);


    struct sched_param param;
    /*param.sched_priority = 40; */
    param.sched_priority = sched_get_priority_min(SCHED_FIFO);
    if (sched_setscheduler(0,SCHED_FIFO,&param))
        perror("sched_setscheduler");

    int send_timestamp = 0;
    int recv_started=0;

    /* Setup all file descriptors for poll()ing */
    nfds = alsa_device_nfds(audio_dev);
    pfds = malloc(sizeof(*pfds)*(nfds+1));
    alsa_device_getfds(audio_dev, pfds, nfds);
    pfds[nfds].fd = sd;
    pfds[nfds].events = POLLIN;

    /* Setup jitter buffer using decoder */
    SpeexJitter jitter;
    speex_jitter_init(&jitter, dec_state, SAMPLING_RATE);

    /* Echo canceller with 200 ms tail length */
    SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE);
    tmp = SAMPLING_RATE;
    speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);

    /* Setup preprocessor and associate with echo canceller for residual echo suppression */
    preprocess = speex_preprocess_state_init(FRAME_SIZE, SAMPLING_RATE);
    speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, echo_state);

    alsa_device_start(audio_dev);

    /* Infinite loop on capture, playback and receiving packets */
    while (1)
    {
        /* Wait for either 1) capture 2) playback 3) socket data */
        poll(pfds, nfds+1, -1);
        /* Received packets */
        if (pfds[nfds].revents & POLLIN)
        {
            /*fprintf (stderr, "x");*/
            n = recv(sd, msg, MAX_MSG, 0);
            int recv_timestamp = ((int*)msg)[1];
            int payload = ((int*)msg)[0];

            if ((payload & 0x80000000) == 0)
            {
                /* Put content of the packet into the jitter buffer, except for the pseudo-header */
                speex_jitter_put(&jitter, msg+8, n-8, recv_timestamp);
                recv_started = 1;
            }

        }
        /* Ready to play a frame (playback) */
        if (alsa_device_playback_ready(audio_dev, pfds, nfds))
        {
            short pcm[FRAME_SIZE];
            if (recv_started)
            {
                /* Get audio from the jitter buffer */
                speex_jitter_get(&jitter, pcm, NULL);
            } else {
                for (i=0; i<FRAME_SIZE; i++)
                    pcm[i] = 0;
            }
            /* Playback the audio and reset the echo canceller if we got an underrun */
            if (alsa_device_write(audio_dev, pcm, FRAME_SIZE))
                speex_echo_state_reset(echo_state);
            /* Put frame into playback buffer */
            speex_echo_playback(echo_state, pcm);
        }
        /* Audio available from the soundcard (capture) */
        if (alsa_device_capture_ready(audio_dev, pfds, nfds))
        {
            short pcm[FRAME_SIZE], pcm2[FRAME_SIZE];
            char outpacket[MAX_MSG];
            /* Get audio from the soundcard */
            alsa_device_read(audio_dev, pcm, FRAME_SIZE);

            /* Perform echo cancellation */
            speex_echo_capture(echo_state, pcm, pcm2);
            for (i=0; i<FRAME_SIZE; i++)
                pcm[i] = pcm2[i];

            speex_bits_reset(&enc_bits);

            /* Apply noise/echo suppression */
            speex_preprocess_run(preprocess, pcm);

            /* Encode */
            speex_encode_int(enc_state, pcm, &enc_bits);
            int packetSize = speex_bits_write(&enc_bits, outpacket+8, MAX_MSG);

            /* Pseudo header: four null bytes and a 32-bit timestamp */
            ((int*)outpacket)[0] = htonl(0);
            ((int*)outpacket)[1] = send_timestamp;
            send_timestamp += FRAME_SIZE;
            rc = sendto(sd, outpacket, packetSize+8, 0,
                        (struct sockaddr *) &remoteAddr,
                        sizeof(remoteAddr));

            if(rc<0) {
                printf("cannot send audio data\n");
                close(sd);
                exit(1);
            }
        }


    }


    return 0;
}
Ejemplo n.º 7
0
void CSpeexEC::DoEchoPlayback(short* pEchoFrame)
{
    if (!m_bHasInit)
        return;
    speex_echo_playback(m_pState, pEchoFrame);
}