Пример #1
0
/*
 * Create the echo canceller.
 */
pjs_echo_canceller::pjs_echo_canceller(pj_pool_t *pool_, unsigned clock_rate,
		unsigned samples_per_frame_, unsigned tail_ms, unsigned latency_ms,
		unsigned options) {
	int sampling_rate = clock_rate;
	unsigned ptime, lat_cnt;
	unsigned delay_buf_opt = 0;

	lat_ready = PJ_FALSE;
	/* Create new pool and instantiate and init the EC */
	pool = pj_pool_create(pool_->factory, "ec%p", 256, 256, NULL);
	lock = new PPJ_SemaphoreLock(pool, NULL, 1, 1);
	samples_per_frame = samples_per_frame_;
	frm_buf = (pj_int16_t*) pj_pool_alloc(pool, samples_per_frame << 1);

    state = speex_echo_state_init(samples_per_frame,
    					clock_rate * tail_ms / 1000);

    speex_echo_ctl(state, SPEEX_ECHO_SET_SAMPLING_RATE,
		   &sampling_rate);

    preprocess = speex_preprocess_state_init(samples_per_frame,
						   clock_rate);
    tmp_frame = (pj_int16_t*) pj_pool_zalloc(pool, 2*samples_per_frame);

    speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
 			state);

	pj_list_init(&lat_buf);
	pj_list_init(&lat_free);

	PJ_LOG(5, (THIS_FILE, "Creating echo canceler"));

	/* Create latency buffers */
	ptime = samples_per_frame * 1000 / clock_rate;
	if (latency_ms < ptime) {
		/* Give at least one frame delay to simplify programming */
		latency_ms = ptime;
	}
	lat_cnt = latency_ms / ptime;
	while (lat_cnt--) {
		struct frame *frm;

		frm = (struct frame*) pj_pool_alloc(pool,
				(samples_per_frame << 1) + sizeof(struct frame));
		pj_list_push_back(&lat_free, frm);
	}

	/* Create delay buffer to compensate drifts */
	if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO)
		delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO;
	pjmedia_delay_buf_create(pool, NULL, clock_rate, samples_per_frame,
			1, (PJMEDIA_SOUND_BUFFER_COUNT + 1) * ptime, delay_buf_opt,
			&delay_buf);
	PJ_LOG(4, (THIS_FILE, "ECHO canceller created, clock_rate=%d, channel=%d, "
	"samples per frame=%d, tail length=%d ms, "
	"latency=%d ms", clock_rate, 1, samples_per_frame, tail_ms, latency_ms));
}
Пример #2
0
/*
 * Create the echo canceller. 
 */
PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
					 unsigned clock_rate,
					 unsigned channel_count,
					 unsigned samples_per_frame,
					 unsigned tail_ms,
					 unsigned latency_ms,
					 unsigned options,
					 pjmedia_echo_state **p_echo )
{
    unsigned ptime, lat_cnt;
    unsigned delay_buf_opt = 0;
    pjmedia_echo_state *ec;
    pj_status_t status;

    /* Create new pool and instantiate and init the EC */
    pool = pj_pool_create(pool->factory, "ec%p", 256, 256, NULL);
    ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state);
    ec->pool = pool;
    ec->obj_name = pool->obj_name;
    ec->samples_per_frame = samples_per_frame;
    ec->frm_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame<<1);
    pj_list_init(&ec->lat_buf);
    pj_list_init(&ec->lat_free);

    /* Select the backend algorithm */
    if (0) {
	/* Dummy */
	;
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
    } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_SPEEX ||
	       (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT) 
    {
	ec->op = &speex_aec_op;
#endif

#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
    } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_IPP ||
	       (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
    {
	ec->op = &ipp_aec_op;

#endif

    } else {
	ec->op = &echo_supp_op;
    }

    /* Completeness check for EC operation playback and capture, they must
     * be implemented both or none.
     */
    pj_assert(!ec->op->ec_capture == !ec->op->ec_playback);

    PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name));

    /* Instantiate EC object */
    status = (*ec->op->ec_create)(pool, clock_rate, channel_count, 
				  samples_per_frame, tail_ms, 
				  options, &ec->state);
    if (status != PJ_SUCCESS) {
	pj_pool_release(pool);
	return status;
    }

    /* If EC algo does not have playback and capture callbakcs,
     * create latency buffer and delay buffer to handle drift.
     */
    if (ec->op->ec_playback && ec->op->ec_capture) {
	latency_ms = 0;
    } else {
	/* Create latency buffers */
	ptime = samples_per_frame * 1000 / clock_rate;
	if (latency_ms > ptime) {
	    /* Normalize latency with delaybuf/WSOLA latency */
	    latency_ms -= PJ_MIN(ptime, PJMEDIA_WSOLA_DELAY_MSEC);
	}
	if (latency_ms < ptime) {
	    /* Give at least one frame delay to simplify programming */
	    latency_ms = ptime;
	}
	lat_cnt = latency_ms / ptime;
	while (lat_cnt--)  {
	    struct frame *frm;

	    frm = (struct frame*) pj_pool_alloc(pool, (samples_per_frame<<1) +
						      sizeof(struct frame));
	    pj_list_push_back(&ec->lat_free, frm);
	}

	/* Create delay buffer to compensate drifts */
	if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO)
	    delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO;
	status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate, 
					  samples_per_frame, channel_count,
					  (PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime,
					  delay_buf_opt, &ec->delay_buf);
	if (status != PJ_SUCCESS) {
	    pj_pool_release(pool);
	    return status;
	}
    }

    PJ_LOG(4,(ec->obj_name, 
	      "%s created, clock_rate=%d, channel=%d, "
	      "samples per frame=%d, tail length=%d ms, "
	      "latency=%d ms", 
	      ec->op->name, clock_rate, channel_count, samples_per_frame,
	      tail_ms, latency_ms));

    /* Done */
    *p_echo = ec;

    return PJ_SUCCESS;
}
Пример #3
0
/* Application init */
static pj_status_t app_init()
{
    unsigned i, count;
    pj_status_t status;

    /* Redirect log */
    pj_log_set_log_func((void (*)(int,const char*,int)) &log_writer);
    pj_log_set_decor(PJ_LOG_HAS_NEWLINE);
    pj_log_set_level(3);

    /* Init pjlib */
    status = pj_init();
    if (status != PJ_SUCCESS) {
    	app_perror("pj_init()", status);
    	return status;
    }

    pj_caching_pool_init(&cp, NULL, 0);

    /* Init sound subsystem */
    status = pjmedia_aud_subsys_init(&cp.factory);
    if (status != PJ_SUCCESS) {
    	app_perror("pjmedia_snd_init()", status);
        pj_caching_pool_destroy(&cp);
    	pj_shutdown();
    	return status;
    }

    count = pjmedia_aud_dev_count();
    PJ_LOG(3,(THIS_FILE, "Device count: %d", count));
    for (i=0; i<count; ++i) {
    	pjmedia_aud_dev_info info;
    	pj_status_t status;

    	status = pjmedia_aud_dev_get_info(i, &info);
    	pj_assert(status == PJ_SUCCESS);
    	PJ_LOG(3, (THIS_FILE, "%d: %s %d/%d %dHz",
    		   i, info.name, info.input_count, info.output_count,
    		   info.default_samples_per_sec));
    	
	unsigned j;

	/* Print extended formats supported by this audio device */
	PJ_LOG(3, (THIS_FILE, "   Extended formats supported:"));
	for (j = 0; j < info.ext_fmt_cnt; ++j) {
	    const char *fmt_name = NULL;
	    
	    switch (info.ext_fmt[j].id) {
	    case PJMEDIA_FORMAT_PCMA:
		fmt_name = "PCMA";
		break;
	    case PJMEDIA_FORMAT_PCMU:
		fmt_name = "PCMU";
		break;
	    case PJMEDIA_FORMAT_AMR:
		fmt_name = "AMR-NB";
		break;
	    case PJMEDIA_FORMAT_G729:
		fmt_name = "G729";
		break;
	    case PJMEDIA_FORMAT_ILBC:
		fmt_name = "ILBC";
		break;
	    case PJMEDIA_FORMAT_PCM:
		fmt_name = "PCM";
		break;
	    default:
		fmt_name = "Unknown";
		break;
	    }
	    PJ_LOG(3, (THIS_FILE, "   - %s", fmt_name));
	}
    }

    /* Create pool */
    pool = pj_pool_create(&cp.factory, THIS_FILE, 512, 512, NULL);
    if (pool == NULL) {
    	app_perror("pj_pool_create()", status);
        pj_caching_pool_destroy(&cp);
    	pj_shutdown();
    	return status;
    }

    /* Init delay buffer */
    status = pjmedia_delay_buf_create(pool, THIS_FILE, CLOCK_RATE,
				      SAMPLES_PER_FRAME, CHANNEL_COUNT,
				      0, 0, &delaybuf);
    if (status != PJ_SUCCESS) {
    	app_perror("pjmedia_delay_buf_create()", status);
        //pj_caching_pool_destroy(&cp);
    	//pj_shutdown();
    	//return status;
    }

    return PJ_SUCCESS;
}
Пример #4
0
/*
 * Create reverse phase port for the specified channel.
 */
PJ_DEF(pj_status_t) pjmedia_splitcomb_create_rev_channel( pj_pool_t *pool,
				      pjmedia_port *splitcomb,
				      unsigned ch_num,
				      unsigned options,
				      pjmedia_port **p_chport)
{
    const pj_str_t name = pj_str("scomb-rev");
    struct splitcomb *sc = (struct splitcomb*) splitcomb;
    struct reverse_port *rport;
    unsigned buf_cnt;
    const pjmedia_audio_format_detail *sc_afd, *p_afd;
    pjmedia_port *port;
    pj_status_t status;

    /* Sanity check */
    PJ_ASSERT_RETURN(pool && splitcomb, PJ_EINVAL);

    /* Make sure this is really a splitcomb port */
    PJ_ASSERT_RETURN(sc->base.info.signature == SIGNATURE, PJ_EINVAL);

    /* Check the channel number */
    PJ_ASSERT_RETURN(ch_num < PJMEDIA_PIA_CCNT(&sc->base.info), PJ_EINVAL);

    /* options is unused for now */
    PJ_UNUSED_ARG(options);

    sc_afd = pjmedia_format_get_audio_format_detail(&splitcomb->info.fmt, 1);

    /* Create the port */
    rport = PJ_POOL_ZALLOC_T(pool, struct reverse_port);
    rport->parent = sc;
    rport->ch_num = ch_num;

    /* Initialize port info... */
    port = &rport->base;
    pjmedia_port_info_init(&port->info, &name, SIGNATURE_PORT, 
			   sc_afd->clock_rate, 1,
			   sc_afd->bits_per_sample,
			   PJMEDIA_PIA_SPF(&splitcomb->info) /
				   sc_afd->channel_count);

    p_afd = pjmedia_format_get_audio_format_detail(&port->info.fmt, 1);

    /* ... and the callbacks */
    port->put_frame = &rport_put_frame;
    port->get_frame = &rport_get_frame;
    port->on_destroy = &rport_on_destroy;

    /* Buffer settings */
    buf_cnt = options & 0xFF;
    if (buf_cnt == 0)
	buf_cnt = MAX_BUF_CNT;

    rport->max_burst = MAX_BURST;
    rport->max_null_frames = MAX_NULL_FRAMES;

    /* Create downstream/put buffers */
    status = pjmedia_delay_buf_create(pool, "scombdb-dn",
				      p_afd->clock_rate,
				      PJMEDIA_PIA_SPF(&port->info),
				      p_afd->channel_count,
				      buf_cnt * p_afd->frame_time_usec / 1000,
				      0, &rport->buf[DIR_DOWNSTREAM].dbuf);
    if (status != PJ_SUCCESS) {
	return status;
    }

    /* Create upstream/get buffers */
    status = pjmedia_delay_buf_create(pool, "scombdb-up",
				      p_afd->clock_rate,
				      PJMEDIA_PIA_SPF(&port->info),
				      p_afd->channel_count,
				      buf_cnt * p_afd->frame_time_usec / 1000,
				      0, &rport->buf[DIR_UPSTREAM].dbuf);
    if (status != PJ_SUCCESS) {
	pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf);
	return status;
    }

    /* And temporary upstream/get buffer */
    rport->tmp_up_buf = (pj_int16_t*)
	                pj_pool_alloc(pool,
				      PJMEDIA_PIA_AVG_FSZ(&port->info));

    /* Save port in the splitcomb */
    sc->port_desc[ch_num].port = &rport->base;
    sc->port_desc[ch_num].reversed = PJ_TRUE;


    /* Done */
    *p_chport = port;
    return status;
}
Пример #5
0
/* Application init */
static pj_status_t app_init()
{
    unsigned i, count;
    pj_status_t status;

    /* Redirect log */
    pj_log_set_log_func((void (*)(int,const char*,int)) &log_writer);
    pj_log_set_decor(PJ_LOG_HAS_NEWLINE);
    pj_log_set_level(3);

    /* Init pjlib */
    status = pj_init();
    if (status != PJ_SUCCESS) {
    	app_perror("pj_init()", status);
    	return status;
    }

    pj_caching_pool_init(&cp, NULL, 0);

    /* Init sound subsystem */
    status = pjmedia_snd_init(&cp.factory);
    if (status != PJ_SUCCESS) {
    	app_perror("pjmedia_snd_init()", status);
        pj_caching_pool_destroy(&cp);
    	pj_shutdown();
    	return status;
    }

    count = pjmedia_snd_get_dev_count();
    PJ_LOG(3,(THIS_FILE, "Device count: %d", count));
    for (i=0; i<count; ++i) {
    	const pjmedia_snd_dev_info *info;

    	info = pjmedia_snd_get_dev_info(i);
    	PJ_LOG(3, (THIS_FILE, "%d: %s %d/%d %dHz",
    		   i, info->name, info->input_count, info->output_count,
    		   info->default_samples_per_sec));
    }

    /* Create pool */
    pool = pj_pool_create(&cp.factory, THIS_FILE, 512, 512, NULL);
    if (pool == NULL) {
    	app_perror("pj_pool_create()", status);
        pj_caching_pool_destroy(&cp);
    	pj_shutdown();
    	return status;
    }

    /* Init delay buffer */
    status = pjmedia_delay_buf_create(pool, THIS_FILE, CLOCK_RATE,
				      SAMPLES_PER_FRAME, CHANNEL_COUNT,
				      0, 0, &delaybuf);
    if (status != PJ_SUCCESS) {
    	app_perror("pjmedia_delay_buf_create()", status);
        //pj_caching_pool_destroy(&cp);
    	//pj_shutdown();
    	//return status;
    }

    return PJ_SUCCESS;
}