static pj_status_t avi_event_cb(pjmedia_event *event, void *user_data) { avi_port_t *ap = (avi_port_t *)user_data; switch (event->type) { case PJMEDIA_EVENT_WND_CLOSED: ap->is_quitting = PJ_TRUE; break; case PJMEDIA_EVENT_MOUSE_BTN_DOWN: if (ap->is_running) { pjmedia_vid_port_stop(ap->vid_port); if (ap->snd_port) pjmedia_aud_stream_stop( pjmedia_snd_port_get_snd_stream(ap->snd_port)); } else { pjmedia_vid_port_start(ap->vid_port); if (ap->snd_port) pjmedia_aud_stream_start( pjmedia_snd_port_get_snd_stream(ap->snd_port)); } ap->is_running = !ap->is_running; break; default: return PJ_SUCCESS; } /* We handled the event on our own, so return non-PJ_SUCCESS here */ return -1; }
static void record(unsigned rec_index, const char *filename) { pj_pool_t *pool = NULL; pjmedia_port *wav = NULL; pjmedia_aud_param param; pjmedia_aud_stream *strm = NULL; char line[10], *dummy; pj_status_t status; if (filename == NULL) filename = WAV_FILE; pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "wav", 1000, 1000, NULL); status = pjmedia_wav_writer_port_create(pool, filename, 16000, 1, 320, 16, 0, 0, &wav); if (status != PJ_SUCCESS) { app_perror("Error creating WAV file", status); goto on_return; } status = pjmedia_aud_dev_default_param(rec_index, ¶m); if (status != PJ_SUCCESS) { app_perror("pjmedia_aud_dev_default_param()", status); goto on_return; } param.dir = PJMEDIA_DIR_CAPTURE; param.clock_rate = PJMEDIA_PIA_SRATE(&wav->info); param.samples_per_frame = PJMEDIA_PIA_SPF(&wav->info); param.channel_count = PJMEDIA_PIA_CCNT(&wav->info); param.bits_per_sample = PJMEDIA_PIA_BITS(&wav->info); status = pjmedia_aud_stream_create(¶m, &wav_rec_cb, NULL, wav, &strm); if (status != PJ_SUCCESS) { app_perror("Error opening the sound device", status); goto on_return; } status = pjmedia_aud_stream_start(strm); if (status != PJ_SUCCESS) { app_perror("Error starting the sound device", status); goto on_return; } PJ_LOG(3,(THIS_FILE, "Recording started, press ENTER to stop")); dummy = fgets(line, sizeof(line), stdin); on_return: if (strm) { pjmedia_aud_stream_stop(strm); pjmedia_aud_stream_destroy(strm); } if (wav) pjmedia_port_destroy(wav); if (pool) pj_pool_release(pool); }
static void play_file(unsigned play_index, const char *filename) { pj_pool_t *pool = NULL; pjmedia_port *wav = NULL; pjmedia_aud_param param; pjmedia_aud_stream *strm = NULL; char line[10], *dummy; pj_status_t status; if (filename == NULL) filename = WAV_FILE; pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "wav", 1000, 1000, NULL); status = pjmedia_wav_player_port_create(pool, filename, 20, 0, 0, &wav); if (status != PJ_SUCCESS) { app_perror("Error opening WAV file", status); goto on_return; } status = pjmedia_aud_dev_default_param(play_index, ¶m); if (status != PJ_SUCCESS) { app_perror("pjmedia_aud_dev_default_param()", status); goto on_return; } param.dir = PJMEDIA_DIR_PLAYBACK; param.clock_rate = wav->info.clock_rate; param.samples_per_frame = wav->info.samples_per_frame; param.channel_count = wav->info.channel_count; param.bits_per_sample = wav->info.bits_per_sample; status = pjmedia_aud_stream_create(¶m, NULL, &wav_play_cb, wav, &strm); if (status != PJ_SUCCESS) { app_perror("Error opening the sound device", status); goto on_return; } status = pjmedia_aud_stream_start(strm); if (status != PJ_SUCCESS) { app_perror("Error starting the sound device", status); goto on_return; } PJ_LOG(3,(THIS_FILE, "Playback started, press ENTER to stop")); dummy = fgets(line, sizeof(line), stdin); on_return: if (strm) { pjmedia_aud_stream_stop(strm); pjmedia_aud_stream_destroy(strm); } if (wav) pjmedia_port_destroy(wav); if (pool) pj_pool_release(pool); }
/* Start sound */ static pj_status_t snd_start(unsigned flag) { pj_status_t status; if (strm != NULL) { app_perror("snd already open", PJ_EINVALIDOP); return PJ_EINVALIDOP; } pjmedia_aud_dev_default_param(0, ¶m); param.channel_count = CHANNEL_COUNT; param.clock_rate = CLOCK_RATE; param.samples_per_frame = SAMPLES_PER_FRAME; param.dir = (pjmedia_dir) flag; param.ext_fmt.id = PJMEDIA_FORMAT_AMR; param.ext_fmt.bitrate = 12200; param.output_route = PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER; status = pjmedia_aud_stream_create(¶m, &rec_cb, &play_cb, NULL, &strm); if (status != PJ_SUCCESS) { app_perror("snd open", status); return status; } rec_cnt = play_cnt = 0; pj_gettimeofday(&t_start); pjmedia_delay_buf_reset(delaybuf); status = pjmedia_aud_stream_start(strm); if (status != PJ_SUCCESS) { app_perror("snd start", status); pjmedia_aud_stream_destroy(strm); strm = NULL; return status; } return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream) { return pjmedia_aud_stream_start(stream->aud_strm); }
/* * Start the sound stream. * This may be called even when the sound stream has already been started. */ static pj_status_t start_sound_device( pj_pool_t *pool, pjmedia_snd_port *snd_port ) { pjmedia_aud_rec_cb snd_rec_cb; pjmedia_aud_play_cb snd_play_cb; pjmedia_aud_param param_copy; pj_status_t status; /* Check if sound has been started. */ if (snd_port->aud_stream != NULL) return PJ_SUCCESS; PJ_ASSERT_RETURN(snd_port->dir == PJMEDIA_DIR_CAPTURE || snd_port->dir == PJMEDIA_DIR_PLAYBACK || snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EBUG); /* Get device caps */ if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) { pjmedia_aud_dev_info dev_info; status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id, &dev_info); if (status != PJ_SUCCESS) return status; snd_port->aud_caps = dev_info.caps; } else { snd_port->aud_caps = 0; } /* Process EC settings */ pj_memcpy(¶m_copy, &snd_port->aud_param, sizeof(param_copy)); if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) { /* EC is wanted */ if ((snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) == 0 && (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)) { /* Device supports EC */ /* Nothing to do */ } else { /* Application wants to use software EC or device * doesn't support EC, remove EC settings from * device parameters */ param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); } } /* Use different callback if format is not PCM */ if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) { snd_rec_cb = &rec_cb; snd_play_cb = &play_cb; } else { snd_rec_cb = &rec_cb_ext; snd_play_cb = &play_cb_ext; } /* Open the device */ status = pjmedia_aud_stream_create(¶m_copy, snd_rec_cb, snd_play_cb, snd_port, &snd_port->aud_stream); if (status != PJ_SUCCESS) return status; /* Inactivity limit before EC is suspended. */ snd_port->ec_suspend_limit = AEC_SUSPEND_LIMIT * (snd_port->clock_rate / snd_port->samples_per_frame); /* Create software EC if parameter specifies EC and * (app specifically requests software EC or device * doesn't support EC). Only do this if the format is PCM! */ if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) && ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 || (snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) != 0) && param_copy.ext_fmt.id == PJMEDIA_FORMAT_PCM) { if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; snd_port->aud_param.ec_tail_ms = AEC_TAIL; PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", snd_port->aud_param.ec_tail_ms)); } status = pjmedia_snd_port_set_ec(snd_port, pool, snd_port->aud_param.ec_tail_ms, snd_port->prm_ec_options); if (status != PJ_SUCCESS) { pjmedia_aud_stream_destroy(snd_port->aud_stream); snd_port->aud_stream = NULL; return status; } } /* Start sound stream. */ if (!(snd_port->options & PJMEDIA_SND_PORT_NO_AUTO_START)) { status = pjmedia_aud_stream_start(snd_port->aud_stream); } if (status != PJ_SUCCESS) { pjmedia_aud_stream_destroy(snd_port->aud_stream); snd_port->aud_stream = NULL; return status; } return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_param *param, pjmedia_aud_test_results *result) { pj_status_t status = PJ_SUCCESS; pjmedia_aud_stream *strm; struct test_data test_data; unsigned ptime, tmp; /* * Init test parameters */ pj_bzero(&test_data, sizeof(test_data)); test_data.param = param; test_data.result = result; test_data.pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "audtest", 1000, 1000, NULL); pj_mutex_create_simple(test_data.pool, "sndtest", &test_data.mutex); /* * Open device. */ status = pjmedia_aud_stream_create(test_data.param, &rec_cb, &play_cb, &test_data, &strm); if (status != PJ_SUCCESS) { app_perror("Unable to open device", status); pj_pool_release(test_data.pool); return status; } /* Sleep for a while to let sound device "settles" */ pj_thread_sleep(200); /* * Start the stream. */ status = pjmedia_aud_stream_start(strm); if (status != PJ_SUCCESS) { app_perror("Unable to start capture stream", status); pjmedia_aud_stream_destroy(strm); pj_pool_release(test_data.pool); return status; } PJ_LOG(3,(THIS_FILE, " Please wait while test is in progress (~%d secs)..", (DURATION+SKIP_DURATION)/1000)); /* Let the stream runs for few msec/sec to get stable result. * (capture normally begins with frames available simultaneously). */ pj_thread_sleep(SKIP_DURATION); /* Begin gather data */ test_data.running = 1; /* * Let the test runs for a while. */ pj_thread_sleep(DURATION); /* * Close stream. */ test_data.running = 0; pjmedia_aud_stream_destroy(strm); pj_pool_release(test_data.pool); /* * Gather results */ ptime = param->samples_per_frame * 1000 / param->clock_rate; tmp = pj_math_stat_get_stddev(&test_data.capture_data.delay); result->rec.frame_cnt = test_data.capture_data.delay.n; result->rec.min_interval = DIV_ROUND(test_data.capture_data.delay.min, 1000); result->rec.max_interval = DIV_ROUND(test_data.capture_data.delay.max, 1000); result->rec.avg_interval = DIV_ROUND(test_data.capture_data.delay.mean, 1000); result->rec.dev_interval = DIV_ROUND(tmp, 1000); result->rec.max_burst = DIV_ROUND_UP(result->rec.max_interval, ptime); tmp = pj_math_stat_get_stddev(&test_data.playback_data.delay); result->play.frame_cnt = test_data.playback_data.delay.n; result->play.min_interval = DIV_ROUND(test_data.playback_data.delay.min, 1000); result->play.max_interval = DIV_ROUND(test_data.playback_data.delay.max, 1000); result->play.avg_interval = DIV_ROUND(test_data.capture_data.delay.mean, 1000); result->play.dev_interval = DIV_ROUND(tmp, 1000); result->play.max_burst = DIV_ROUND_UP(result->play.max_interval, ptime); /* Check drifting */ if (param->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) { int end_diff, start_diff, drift; end_diff = test_data.capture_data.last_timestamp - test_data.playback_data.last_timestamp; start_diff = test_data.capture_data.first_timestamp- test_data.playback_data.first_timestamp; drift = end_diff > start_diff? end_diff - start_diff : start_diff - end_diff; /* Allow one frame tolerance for clock drift detection */ if (drift < (int)param->samples_per_frame) { result->rec_drift_per_sec = 0; } else { unsigned msec_dur; msec_dur = (test_data.capture_data.last_timestamp - test_data.capture_data.first_timestamp) * 1000 / test_data.param->clock_rate; result->rec_drift_per_sec = drift * 1000 / msec_dur; } } return test_data.has_error? PJ_EUNKNOWN : PJ_SUCCESS; }
static void pcap2wav(const pj_str_t *codec, const pj_str_t *wav_filename, pjmedia_aud_dev_index dev_id, const pj_str_t *srtp_crypto, const pj_str_t *srtp_key) { const pj_str_t WAV = {".wav", 4}; struct pkt { pj_uint8_t buffer[320]; pjmedia_rtp_hdr *rtp; pj_uint8_t *payload; unsigned payload_len; } pkt0; pjmedia_codec_mgr *cmgr; const pjmedia_codec_info *ci; pjmedia_codec_param param; unsigned samples_per_frame; pj_status_t status; /* Initialize all codecs */ T( pjmedia_codec_register_audio_codecs(app.mept, NULL) ); /* Create SRTP transport is needed */ #if PJMEDIA_HAS_SRTP if (srtp_crypto->slen) { pjmedia_srtp_crypto crypto; pj_bzero(&crypto, sizeof(crypto)); crypto.key = *srtp_key; crypto.name = *srtp_crypto; T( pjmedia_transport_srtp_create(app.mept, NULL, NULL, &app.srtp) ); T( pjmedia_transport_srtp_start(app.srtp, &crypto, &crypto) ); } #else PJ_UNUSED_ARG(srtp_crypto); PJ_UNUSED_ARG(srtp_key); #endif /* Read first packet */ read_rtp(pkt0.buffer, sizeof(pkt0.buffer), &pkt0.rtp, &pkt0.payload, &pkt0.payload_len, PJ_FALSE); cmgr = pjmedia_endpt_get_codec_mgr(app.mept); /* Get codec info and param for the specified payload type */ app.pt = pkt0.rtp->pt; if (app.pt >=0 && app.pt < 96) { T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); } else { unsigned cnt = 2; const pjmedia_codec_info *info[2]; T( pjmedia_codec_mgr_find_codecs_by_id(cmgr, codec, &cnt, info, NULL) ); if (cnt != 1) err_exit("Codec ID must be specified and unique!", 0); ci = info[0]; } T( pjmedia_codec_mgr_get_default_param(cmgr, ci, ¶m) ); /* Alloc and init codec */ T( pjmedia_codec_mgr_alloc_codec(cmgr, ci, &app.codec) ); T( pjmedia_codec_init(app.codec, app.pool) ); T( pjmedia_codec_open(app.codec, ¶m) ); /* Init audio device or WAV file */ samples_per_frame = ci->clock_rate * param.info.frm_ptime / 1000; if (pj_strcmp2(wav_filename, "-") == 0) { pjmedia_aud_param aud_param; /* Open audio device */ T( pjmedia_aud_dev_default_param(dev_id, &aud_param) ); aud_param.dir = PJMEDIA_DIR_PLAYBACK; aud_param.channel_count = ci->channel_cnt; aud_param.clock_rate = ci->clock_rate; aud_param.samples_per_frame = samples_per_frame; T( pjmedia_aud_stream_create(&aud_param, NULL, &play_cb, NULL, &app.aud_strm) ); T( pjmedia_aud_stream_start(app.aud_strm) ); } else if (pj_stristr(wav_filename, &WAV)) { /* Open WAV file */ T( pjmedia_wav_writer_port_create(app.pool, wav_filename->ptr, ci->clock_rate, ci->channel_cnt, samples_per_frame, param.info.pcm_bits_per_sample, 0, 0, &app.wav) ); } else { err_exit("invalid output file", PJ_EINVAL); } /* Loop reading PCAP and writing WAV file */ for (;;) { struct pkt pkt1; pj_timestamp ts; pjmedia_frame frames[16], pcm_frame; short pcm[320]; unsigned i, frame_cnt; long samples_cnt, ts_gap; pj_assert(sizeof(pcm) >= samples_per_frame); /* Parse first packet */ ts.u64 = 0; frame_cnt = PJ_ARRAY_SIZE(frames); T( pjmedia_codec_parse(app.codec, pkt0.payload, pkt0.payload_len, &ts, &frame_cnt, frames) ); /* Decode and write to WAV file */ samples_cnt = 0; for (i=0; i<frame_cnt; ++i) { pjmedia_frame pcm_frame; pcm_frame.buf = pcm; pcm_frame.size = samples_per_frame * 2; T( pjmedia_codec_decode(app.codec, &frames[i], (unsigned)pcm_frame.size, &pcm_frame) ); if (app.wav) { T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); } if (app.aud_strm) { T( wait_play(&pcm_frame) ); } samples_cnt += samples_per_frame; } /* Read next packet */ read_rtp(pkt1.buffer, sizeof(pkt1.buffer), &pkt1.rtp, &pkt1.payload, &pkt1.payload_len, PJ_TRUE); /* Fill in the gap (if any) between pkt0 and pkt1 */ ts_gap = pj_ntohl(pkt1.rtp->ts) - pj_ntohl(pkt0.rtp->ts) - samples_cnt; while (ts_gap >= (long)samples_per_frame) { pcm_frame.buf = pcm; pcm_frame.size = samples_per_frame * 2; if (app.codec->op->recover) { T( pjmedia_codec_recover(app.codec, (unsigned)pcm_frame.size, &pcm_frame) ); } else { pj_bzero(pcm_frame.buf, pcm_frame.size); } if (app.wav) { T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); } if (app.aud_strm) { T( wait_play(&pcm_frame) ); } ts_gap -= samples_per_frame; } /* Next */ pkt0 = pkt1; pkt0.rtp = (pjmedia_rtp_hdr*)pkt0.buffer; pkt0.payload = pkt0.buffer + (pkt1.payload - pkt1.buffer); } }
pj_status_t latency_checker::start(latency_config_t &config) { pj_status_t result = PJ_EINVAL; if(m_pool == NULL) { m_dstate = 0; m_start_tone_time.u64 = 0; m_latency = 0; m_quality = 0; m_config = config; m_status_string[0] = 0; m_gain = new snd_agc("",30,1,32000,32000); m_idle_freq1_det = new tone_detector(m_config.clock_rate,IDLE_FREQ1); m_idle_freq2_det = new tone_detector(m_config.clock_rate,IDLE_FREQ2); m_active_freq1_det = new tone_detector(m_config.clock_rate,ACTIVE_FREQ1); m_active_freq2_det = new tone_detector(m_config.clock_rate,ACTIVE_FREQ2); init_generate_dual_tone(&m_idle_tone,m_config.clock_rate,IDLE_FREQ1,IDLE_FREQ2,32767); init_generate_dual_tone(&m_active_tone,m_config.clock_rate,ACTIVE_FREQ1,ACTIVE_FREQ2,32767); pj_log_set_level(0); pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC); if(pj_init()==PJ_SUCCESS) { m_caching_pool = (pj_caching_pool *)malloc(sizeof(pj_caching_pool)); pj_caching_pool_init( m_caching_pool, NULL, 0 ); m_pool_factory=&m_caching_pool->factory; m_pool = pj_pool_create(m_pool_factory, "LATENCY NATIVE", 4000, 4000, NULL); pj_log_set_level(m_config.logs.level); pj_logging_init(m_pool); pj_logging_setLogToConsole(1); pj_logging_setFilename(m_config.logs.file_name); pj_logging_setMaxLogFiles(m_config.logs.max_files); pj_logging_setMaxLogFileSize(m_config.logs.max_file_size*1024*1024); pj_logging_start(); pj_get_timestamp(&m_last_get_frame_time); m_lock = new PPJ_SemaphoreLock(m_pool,NULL,1,1); pjmedia_aud_subsys_init(m_pool_factory); #if PJMEDIA_AUDIO_DEV_HAS_ANDROID #if PJ_ANDROID_DEVICE==1 pjmedia_aud_register_factory(&pjmedia_android_factory); #endif #if PJ_ANDROID_DEVICE==2 pjmedia_aud_register_factory(&pjmedia_opensl_factory); #endif #if PJ_ANDROID_DEVICE==3 pjmedia_aud_register_factory(&pjmedia_alsa_factory); #endif #endif pjmedia_aud_param params; params.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; params.rec_id = 1; params.play_id = 6; params.clock_rate = m_config.clock_rate; params.channel_count = 1; params.samples_per_frame = m_config.min_frame_length*m_config.clock_rate/1000; params.bits_per_sample = 16; params.flags = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY; params.input_latency_ms = m_config.min_frame_length; params.output_latency_ms = m_config.min_frame_length; result = pjmedia_aud_stream_create(¶ms,&rec_cb_s,&play_cb_s,this,&m_aud_stream); if(result==PJ_SUCCESS) { result = pjmedia_aud_stream_start(m_aud_stream); if(result==PJ_SUCCESS) { } } } } if(result!=PJ_SUCCESS) internal_clean(); return result; }
/* * Start the sound stream. * This may be called even when the sound stream has already been started. */ static pj_status_t start_sound_device( pj_pool_t *pool, pjmedia_snd_port *snd_port ) { int i;float f; pjmedia_aud_rec_cb snd_rec_cb; pjmedia_aud_play_cb snd_play_cb; pjmedia_aud_param param_copy; pj_status_t status; /* Check if sound has been started. */ if (snd_port->aud_stream != NULL) return PJ_SUCCESS; PJ_ASSERT_RETURN(snd_port->dir == PJMEDIA_DIR_CAPTURE || snd_port->dir == PJMEDIA_DIR_PLAYBACK || snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EBUG); /* Get device caps */ if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) { pjmedia_aud_dev_info dev_info; status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id, &dev_info); if (status != PJ_SUCCESS) return status; snd_port->aud_caps = dev_info.caps; } else { snd_port->aud_caps = 0; } /* Process EC settings */ pj_memcpy(¶m_copy, &snd_port->aud_param, sizeof(param_copy)); if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) { /* EC is wanted */ if ((snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) == 0 && (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)) { /* Device supports EC */ /* Nothing to do */ } else { /* Application wants to use software EC or device * doesn't support EC, remove EC settings from * device parameters */ param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL); } } /* Use different callback if format is not PCM */ if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) { snd_rec_cb = &rec_cb; snd_play_cb = &play_cb; } else { snd_rec_cb = &rec_cb_ext; snd_play_cb = &play_cb_ext; } /* Open the device */ status = pjmedia_aud_stream_create(¶m_copy, snd_rec_cb, snd_play_cb, snd_port, &snd_port->aud_stream); if (status != PJ_SUCCESS) return status; /* Inactivity limit before EC is suspended. */ snd_port->ec_suspend_limit = AEC_SUSPEND_LIMIT * (snd_port->clock_rate / snd_port->samples_per_frame); /* Create software EC if parameter specifies EC and * (app specifically requests software EC or device * doesn't support EC). Only do this if the format is PCM! */ if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) && ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 || (snd_port->prm_ec_options & PJMEDIA_ECHO_USE_SW_ECHO) != 0) && param_copy.ext_fmt.id == PJMEDIA_FORMAT_PCM) { if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; snd_port->aud_param.ec_tail_ms = AEC_TAIL; PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", snd_port->aud_param.ec_tail_ms)); } status = pjmedia_snd_port_set_ec(snd_port, pool, snd_port->aud_param.ec_tail_ms, snd_port->prm_ec_options); if (status != PJ_SUCCESS) { pjmedia_aud_stream_destroy(snd_port->aud_stream); snd_port->aud_stream = NULL; return status; } } /* Start sound stream. */ if (!(snd_port->options & PJMEDIA_SND_PORT_NO_AUTO_START)) { status = pjmedia_aud_stream_start(snd_port->aud_stream); } if (status != PJ_SUCCESS) { pjmedia_aud_stream_destroy(snd_port->aud_stream); snd_port->aud_stream = NULL; return status; } #ifdef MY_SAVE_FILE_SEND if (fd_save !=NULL) fclose(fd_save); fd_save = fopen("/sdcard/send_data.pcm","wb"); if (fd_save == NULL) PJ_LOG(1,(THIS_FILE, "open /sdcard/send_data.pcm failed!")); #endif #ifdef MY_SAVE_FILE_BEFORE_SPEEX if (fd_bfspeex != NULL) fclose(fd_bfspeex); fd_bfspeex = fopen("/sdcard/send_data_bfspeex.pcm","wb"); if (fd_bfspeex == NULL) PJ_LOG(1,(THIS_FILE, "open /sdcard/send_data_bfspeex.pcm failed!")); #endif if (pjmedia_audio_use_speex_ns == PJ_TRUE) PJ_LOG(4,(THIS_FILE,"pjmedia_audio_use_speex_ns:true")); else PJ_LOG(4,(THIS_FILE,"pjmedia_audio_use_speex_ns:false")); if (pjmedia_audio_use_speex_ns == PJ_TRUE){ if (snd_port->speex_st){ PJ_LOG(4,(THIS_FILE, "speex noise suppress destroy")); speex_preprocess_state_destroy(snd_port->speex_st); } PJ_LOG(4,(THIS_FILE, "speex noise suppress start")); snd_port->speex_st =speex_preprocess_state_init(snd_port->samples_per_frame,snd_port->clock_rate); i=1; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_DENOISE, &i); i=0; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_AGC, &i); i=8000; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i); i=0; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_DEREVERB, &i); f=.0; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); f=.0; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); #if 0 int vad = 1; int vadProbStart = 80; int vadProbContinue = 65; speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_VAD, &vad); //静音检测 speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_PROB_START , &vadProbStart); //Set probability required for the VAD to go from silence to voice speex_preprocess_ctl(snd_port->speex_st, SPEEX_PREPROCESS_SET_PROB_CONTINUE, &vadProbContinue); #endif } return PJ_SUCCESS; }