/* * 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; }
/* * 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; }
/* * main() */ int main(int argc, char *argv[]) { pj_caching_pool cp; pjmedia_endpt *med_endpt; pj_pool_t *pool; pjmedia_port *play_port; pjmedia_port *rec_port; pjmedia_port *bidir_port; pjmedia_snd_port *snd; char tmp[10]; pj_status_t status; if (argc != 3) { puts("Error: arguments required"); puts(desc); return 1; } /* Must init PJLIB first: */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* * Initialize media endpoint. * This will implicitly initialize PJMEDIA too. */ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create memory pool for our file player */ pool = pj_pool_create( &cp.factory, /* pool factory */ "wav", /* pool name. */ 4000, /* init size */ 4000, /* increment size */ NULL /* callback on error */ ); /* Create file media port from the WAV file */ status = pjmedia_wav_player_port_create( pool, /* memory pool */ argv[1], /* file to play */ PTIME, /* ptime. */ 0, /* flags */ 0, /* default buffer */ &play_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to open input WAV file", status); return 1; } if (play_port->info.channel_count != 1) { puts("Error: input WAV must have 1 channel audio"); return 1; } if (play_port->info.bits_per_sample != 16) { puts("Error: input WAV must be encoded as 16bit PCM"); return 1; } #ifdef PJ_DARWINOS /* Need to force clock rate on MacOS */ if (play_port->info.clock_rate != 44100) { pjmedia_port *resample_port; status = pjmedia_resample_port_create(pool, play_port, 44100, 0, &resample_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create resampling port", status); return 1; } data.play_port = resample_port; } #endif /* Create WAV output file port */ status = pjmedia_wav_writer_port_create(pool, argv[2], play_port->info.clock_rate, play_port->info.channel_count, play_port->info.samples_per_frame, play_port->info.bits_per_sample, 0, 0, &rec_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to open output file", status); return 1; } /* Create bidirectional port from the WAV ports */ pjmedia_bidirectional_port_create(pool, play_port, rec_port, &bidir_port); /* Create sound device. */ status = pjmedia_snd_port_create(pool, -1, -1, play_port->info.clock_rate, play_port->info.channel_count, play_port->info.samples_per_frame, play_port->info.bits_per_sample, 0, &snd); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to open sound device", status); return 1; } /* Customize AEC */ pjmedia_snd_port_set_ec(snd, pool, TAIL_LENGTH, 0); /* Connect sound to the port */ pjmedia_snd_port_connect(snd, bidir_port); puts(""); printf("Playing %s and recording to %s\n", argv[1], argv[2]); puts("Press <ENTER> to quit"); fgets(tmp, sizeof(tmp), stdin); /* Start deinitialization: */ /* Destroy sound device */ status = pjmedia_snd_port_destroy( snd ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Destroy file port(s) */ status = pjmedia_port_destroy( play_port ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_port_destroy( rec_port ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Release application pool */ pj_pool_release( pool ); /* Destroy media endpoint. */ pjmedia_endpt_destroy( med_endpt ); /* Destroy pool factory */ pj_caching_pool_destroy( &cp ); /* Shutdown PJLIB */ pj_shutdown(); /* Done. */ return 0; }