static void close_play_pcm(struct bb10_stream *stream) { if (stream != NULL && stream->pb_pcm != NULL) { snd_pcm_close(stream->pb_pcm); stream->pb_pcm = NULL; if (stream->pb_audio_manager_handle != 0) { audio_manager_free_handle(stream->pb_audio_manager_handle); stream->pb_audio_manager_handle = 0; } if (stream->pb_ctrl_audio_manager_handle != 0) { audio_manager_free_handle(stream->pb_ctrl_audio_manager_handle); stream->pb_ctrl_audio_manager_handle = 0; } } }
/** * Set up capture based on the audio sample waverec except we use VoIP parameters */ static int capture(circular_buffer_t* circular_buffer) { // Re-usable buffer for capture char *record_buffer; record_buffer = (char*) malloc(g_frame_size_c); // Some diagnostic variables int failed = 0; int totalRead = 0; snd_pcm_channel_status_t status; status.channel = SND_PCM_CHANNEL_CAPTURE; // Loop until stopAudio() flags us while (g_execute_audio) { // This blocking read appears to take much longer than 20ms on the simulator // but it never fails and always returns 160 bytes int read = snd_pcm_plugin_read(g_pcm_handle_c, record_buffer, g_frame_size_c); if (read < 0 || read != g_frame_size_c) { failed++; fprintf(stderr,"CAPTURE FAILURE: snd_pcm_plugin_read: %d requested = %d\n",read,g_frame_size_c); if (snd_pcm_plugin_status(g_pcm_handle_c, &status) < 0) { fprintf(stderr, "Capture channel status error: %d\n",status.status); } else { if (status.status == SND_PCM_STATUS_READY || status.status == SND_PCM_STATUS_OVERRUN || status.status == SND_PCM_STATUS_CHANGE || status.status == SND_PCM_STATUS_ERROR) { fprintf(stderr, "CAPTURE FAILURE:snd_pcm_plugin_status: = %d \n",status.status); if (snd_pcm_plugin_prepare (g_pcm_handle_c, SND_PCM_CHANNEL_CAPTURE) < 0) { fprintf (stderr, "Capture channel prepare error 1 %d\n",status.status); exit (1); } } } } else { totalRead += read; // On simulator always room in the circular buffer if (!writeToCircularBuffer(circular_buffer, record_buffer, g_frame_size_c)) { failed++; } } capture_ready = true; } fprintf(stderr,"CAPTURE EXIT BEGIN\n"); (void) snd_pcm_plugin_flush(g_pcm_handle_c, SND_PCM_CHANNEL_CAPTURE); //(void)snd_mixer_close (mixer_handle); (void) snd_pcm_close(g_pcm_handle_c); audio_manager_free_handle(g_audio_manager_handle_c); // IMPORTANT NB: You only get failed on capture if the play loop has exited hence the circular buffer fills. This is with the simulator fprintf(stderr, "CAPTURE EXIT Total Bytes read = %d failed = %d\n",totalRead,failed); free(record_buffer); return 0; }
/** * Set the thread exit flag and cleanup<br> */ void stopPcmAudio() { // Threads will see this flag every 20ms in their loop fprintf(stderr,"\nStopPCMAudio ****************: ENTER \n"); g_execute_audio = false; fprintf(stderr,"CAPTURE JOIN = %d\n",pthread_join(g_capturethread, NULL)); fprintf(stderr,"PLAY JOIN = %d\n",pthread_join(g_playerthread, NULL)); audio_manager_free_handle(g_audio_manager_handle_t); destroyCircularBuffer(g_circular_buffer); fprintf(stderr,"StopPCMAudio ****************: EXIT\n"); }
void AudioControl::releaseAudioManagerHandle() { if(m_dtmfAudioManager != 0){ int ret = audio_manager_free_handle(m_dtmfAudioManager); if(ret != 0){ qDebug() << "AudioControl::releaseHandle() = " << ret; } m_dtmfAudioManager = 0; } }
static void close_capture_pcm(struct bb10_stream *stream) { if (stream != NULL && stream->ca_pcm != NULL) { snd_pcm_close(stream->ca_pcm); stream->ca_pcm = NULL; if (stream->ca_audio_manager_handle != 0) { audio_manager_free_handle(stream->ca_audio_manager_handle); stream->ca_audio_manager_handle = 0; } } }
void cleanupToneGenerator() { int i; if( live == STOPPED ) { return; } pthread_mutex_lock( &toneMutex ); live = STOPPED; // Terminate all playbacks Tone *tone = NULL; for(tone = tones; tone != NULL; tone = tone->next ) { tone->active = false; } pthread_mutex_unlock( &toneMutex ); pthread_cond_signal( &condvar_newtone ); pthread_join( toneGeneratorThread, NULL ); snd_pcm_close (playback_handle); //free( frag_buffer ); if( audioman_handle ) { audio_manager_free_handle( audioman_handle ); } pthread_cond_destroy( &condvar_newtone ); pthread_mutex_destroy( &toneMutex ); pthread_mutex_destroy (&fillMutex); free(record_buffer); free(render_buffer); free(stage_samples); free(stage_buffer); }
static int voice_test() { int rtn = 0; char* name; fd_set rfds, wfds; Audio_t hPcm_Mic; Audio_t hPcm_Spk; snd_pcm_channel_params_t params; bool bQuit = false; /************************ CAPTURE **************************/ // configuring capture (mic) name = "voice"; // get audioman handle rtn = audio_manager_get_handle(AUDIO_TYPE_VIDEO_CHAT, getpid(), (bool)false, &hPcm_Mic.hAudioman); if(rtn < 0) { cli_print("audio_manager_get_handle (mic) failed %s", strerror(-rtn)); return -1; } cli_print("Opening %s - for capture", name); rtn = snd_pcm_open_name(&hPcm_Mic.pDs, name, SND_PCM_OPEN_CAPTURE); if (rtn < 0) { (void)audio_manager_free_handle(hPcm_Mic.hAudioman); cli_print("snd_pcm_open_name (mic) failed %s", snd_strerror(rtn)); return -1; // snd_pcm calls return negative values; make positive } rtn = snd_pcm_set_audioman_handle(hPcm_Mic.pDs, hPcm_Mic.hAudioman); if (rtn < 0) { (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); cli_print("snd_pcm_set_audioman_handle (mic) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); return -1; } // disable mmap (void)snd_pcm_plugin_set_disable(hPcm_Mic.pDs, (unsigned int)PLUGIN_DISABLE_MMAP); // set parameters memset(¶ms, 0, sizeof(params)); params.mode = SND_PCM_MODE_BLOCK; params.channel = SND_PCM_CHANNEL_CAPTURE; params.start_mode = SND_PCM_START_GO; params.stop_mode = SND_PCM_STOP_ROLLOVER; params.buf.block.frag_size = fragsize; params.buf.block.frags_max = 1; params.buf.block.frags_min = 1; params.format.rate = 8000; //samplerate; params.format.interleave = 1; params.format.voices = channels; params.format.format = SND_PCM_SFMT_S16_LE; rtn = snd_pcm_plugin_params(hPcm_Mic.pDs, ¶ms); if (rtn < 0) { cli_print("snd_pcm_plugin_params (mic) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); return -1; } // get file descriptor for use with the select() call hPcm_Mic.hFD = snd_pcm_file_descriptor(hPcm_Mic.pDs, SND_PCM_CHANNEL_CAPTURE); if (hPcm_Mic.hFD < 0) { cli_print("snd_pcm_file_descriptor (mic) failed %s", snd_strerror(hPcm_Mic.hFD)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); return -1; } // Signal the driver to ready the capture channel rtn = snd_pcm_plugin_prepare(hPcm_Mic.pDs, SND_PCM_CHANNEL_CAPTURE); if (rtn < 0) { cli_print("snd_pcm_plugin_prepare (mic) failed %s", snd_strerror(errno)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); return -1; } fragsize = params.buf.block.frag_size; /************************ PLAYBACK **************************/ name = "voice"; // get and set audioman handle rtn = audio_manager_get_handle(AUDIO_TYPE_VIDEO_CHAT, getpid(), (bool)false, &hPcm_Spk.hAudioman); if (rtn < 0) { cli_print("audioman audio_manager_get_handle (spk) failed %s", strerror(-rtn) ); (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); return -1; } #ifdef HANDSET // set audio manager handle type rtn = audio_manager_set_handle_type(hPcm_Spk.hAudioman, AUDIO_TYPE_VIDEO_CHAT, device_type, device_type); if (rtn < 0) { (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); cli_print("audio_manager_set_handle_type (spk) failed %s", strerror(-rtn)); return -1; } #endif // Create a handle and open a connection to an audio interface specified by name cli_print("Opening %s - for playback", name); rtn = snd_pcm_open_name(&hPcm_Spk.pDs, name, SND_PCM_OPEN_PLAYBACK); if (rtn < 0) { cli_print("snd_pcm_open_name (spk) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } rtn = snd_pcm_set_audioman_handle(hPcm_Spk.pDs, hPcm_Spk.hAudioman); if (rtn < 0) { cli_print("snd_pcm_set_audioman_handle (spk) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)snd_pcm_close(hPcm_Spk.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } // disable mmap (void)snd_pcm_plugin_set_disable(hPcm_Spk.pDs, (unsigned int)PLUGIN_DISABLE_MMAP); // set parameters memset(¶ms, 0, sizeof(params)); params.mode = SND_PCM_MODE_BLOCK; params.channel = SND_PCM_CHANNEL_PLAYBACK; params.start_mode = SND_PCM_START_GO; params.stop_mode = SND_PCM_STOP_ROLLOVER; params.buf.block.frag_size = fragsize; params.buf.block.frags_max = 1; params.buf.block.frags_min = 1; params.format.rate = samplerate; params.format.interleave = 1; params.format.voices = channels; params.format.format = SND_PCM_SFMT_S16_LE; // Set the configurable parameters for a PCM channel rtn = snd_pcm_plugin_params(hPcm_Spk.pDs, ¶ms); if (rtn < 0) { cli_print("snd_pcm_plugin_params (spk) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)snd_pcm_close(hPcm_Spk.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } // get file descriptor for use with the select() call hPcm_Spk.hFD = snd_pcm_file_descriptor(hPcm_Spk.pDs, SND_PCM_CHANNEL_PLAYBACK); if (hPcm_Spk.hFD < 0) { cli_print("snd_pcm_file_descriptor (spk) failed %s", snd_strerror(hPcm_Spk.hFD)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)snd_pcm_close(hPcm_Spk.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } // Signal the driver to ready the playback channel rtn = snd_pcm_plugin_prepare(hPcm_Spk.pDs, SND_PCM_CHANNEL_PLAYBACK); if (rtn < 0) { cli_print("snd_pcm_plugin_prepare (spk) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)snd_pcm_close(hPcm_Spk.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } fragsize = params.buf.block.frag_size; rtn = snd_pcm_capture_go(hPcm_Mic.pDs); if( rtn < 0) { cli_print("snd_pcm_capture_go (mic) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)snd_pcm_close(hPcm_Spk.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } rtn = snd_pcm_playback_go(hPcm_Spk.pDs); if (rtn < 0) { cli_print("snd_pcm_playback_go (spk) failed %s", snd_strerror(rtn)); (void)snd_pcm_close(hPcm_Mic.pDs); (void)snd_pcm_close(hPcm_Spk.pDs); (void)audio_manager_free_handle(hPcm_Mic.hAudioman); (void)audio_manager_free_handle(hPcm_Spk.hAudioman); return -1; } /******************* PLAYBACK/RECORD LOOP **************************/ while(!bQuit) { int width; struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 350000; // 350 ms FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(hPcm_Mic.hFD, &rfds); FD_SET(hPcm_Spk.hFD, &wfds); width = ((hPcm_Spk.hFD > hPcm_Mic.hFD) ? hPcm_Spk.hFD : hPcm_Mic.hFD) + 1; rtn = select(width, &rfds, &wfds, NULL, &timeout); if (rtn > 0) { if (FD_ISSET(hPcm_Spk.hFD, &wfds)) { bQuit = process_write(hPcm_Spk.pDs); } if (FD_ISSET(hPcm_Mic.hFD, &rfds)) { bQuit = process_read(hPcm_Mic.pDs); } } else if (rtn == 0){ cli_print("select: timed out"); bQuit = true; } else { // (rtn < 0) cli_print("select: %s", strerror(errno)); bQuit = true; } } // Ensure audio processing is stopped if ((rtn = snd_pcm_plugin_playback_drain(hPcm_Spk.pDs)) < 0) { cli_print("snd_pcm_plugin_playback_drain (spk) failed %s", snd_strerror(rtn)); } if ((rtn = snd_pcm_plugin_flush(hPcm_Mic.pDs, SND_PCM_CHANNEL_CAPTURE)) < 0) { cli_print("snd_pcm_plugin_flush (mic) failed %s", snd_strerror(rtn)); } if ((rtn = snd_pcm_close(hPcm_Spk.pDs)) < 0) { cli_print("snd_pcm_close (spk) failed %s", snd_strerror(rtn)); } if ((rtn = snd_pcm_close(hPcm_Mic.pDs)) < 0) { cli_print("snd_pcm_close (mic) failed %s", snd_strerror(rtn)); } if (hPcm_Spk.hAudioman) { (void)audio_manager_free_handle(hPcm_Spk.hAudioman); } if (hPcm_Mic.hAudioman) { (void)audio_manager_free_handle(hPcm_Mic.hAudioman); } return 0; }
/* * BB10 - tests loads the audio units and sets up the driver structure */ static pj_status_t bb10_add_dev (struct bb10_factory *af) { pjmedia_aud_dev_info *adi; int pb_result, ca_result; unsigned int handle; snd_pcm_t *pcm_handle; if (af->dev_cnt >= PJ_ARRAY_SIZE(af->devs)) return PJ_ETOOMANY; adi = &af->devs[af->dev_cnt]; TRACE_((THIS_FILE, "bb10_add_dev Enter")); if ((pb_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &pcm_handle, &handle, (char*)"voice", SND_PCM_OPEN_PLAYBACK)) >= 0) { snd_pcm_close (pcm_handle); audio_manager_free_handle(handle); } else { TRACE_((THIS_FILE, "Try to open the device for playback - failure")); } if ((ca_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, &pcm_handle, &handle, (char*)"voice", SND_PCM_OPEN_CAPTURE)) >= 0) { snd_pcm_close (pcm_handle); audio_manager_free_handle(handle); } else { TRACE_((THIS_FILE, "Try to open the device for capture - failure")); } if (pb_result < 0 && ca_result < 0) { TRACE_((THIS_FILE, "Unable to open sound device", "preferred")); return PJMEDIA_EAUD_NODEV; } /* Reset device info */ pj_bzero(adi, sizeof(*adi)); /* Set device name */ strcpy(adi->name, "preferred"); /* Check the number of playback channels */ adi->output_count = (pb_result >= 0) ? 1 : 0; /* Check the number of capture channels */ adi->input_count = (ca_result >= 0) ? 1 : 0; /* Set the default sample rate */ adi->default_samples_per_sec = 8000; /* Driver name */ strcpy(adi->driver, "BB10"); ++af->dev_cnt; PJ_LOG (4,(THIS_FILE, "Added sound device %s", adi->name)); return PJ_SUCCESS; }
/** * setup play based on the audio sample wave */ static int play(circular_buffer_t* circular_buffer) { // If there's nothing in the circular buffer play the sound of silence // In the real world you may well play the last frame you received. There are algorithms DSP experts know about apparently char* silence_buffer = (char*) malloc(g_frame_size_p); memset(silence_buffer, SILENCE, g_frame_size_p); // Data read from the circular buffer char* play_buffer = (char*) malloc(g_frame_size_p); memset(play_buffer, 0, g_frame_size_p); // Diagnostics int total_written = 0; int failed = 0; int capture_not_ready = 0; // Loop till stopAudio() flags us while (g_execute_audio) { int written; // Read the circular buffer // returns true only if there is data to satisfy frame_size if (!capture_ready) { ++capture_not_ready; written = snd_pcm_plugin_write(g_pcm_handle_p, play_buffer, g_frame_size_p); if (written < 0 || written != g_frame_size_p) { fprintf(stderr,"PLAY RESET 1\n"); resetPlay(); }else{ total_written += written; } } else if (readFromCircularBuffer(circular_buffer, play_buffer, g_frame_size_p)) { written = snd_pcm_plugin_write(g_pcm_handle_p, play_buffer, g_frame_size_p); if (written < 0 || written != g_frame_size_p) { fprintf(stderr,"PLAY RESET 2\n"); resetPlay(); }else{ total_written += written; } } else { // You would expect the jitter buffer to be possibly empty at startup because threads are not synchronized // increasing the frags_max reduces the occurrences of failure here // On the simulator it always fails written = 0 presumably meaning an overrun written = snd_pcm_plugin_write(g_pcm_handle_p, silence_buffer, g_frame_size_p); if (written < 0 || written != g_frame_size_p) { fprintf(stderr,"PLAY RESET 3\n"); resetPlay(); } failed++; } } fprintf(stderr,"PLAY EXIT BEGIN\n"); (void) snd_pcm_plugin_flush(g_pcm_handle_p, SND_PCM_CHANNEL_PLAYBACK); (void) snd_pcm_close(g_pcm_handle_p); audio_manager_free_handle(g_audio_manager_handle_p); free(play_buffer); free(silence_buffer); fprintf(stderr,"PLAY EXIT Total Bytes written = %d failed = %d capture_not_ready %d\n",total_written,failed,capture_not_ready); return 0; }
int initToneGenerator(void) { _int32 staticMemSize, scratchMemSize; int policy; struct sched_param param; int error; pthread_attr_t attr; if( live == RUNNING) { return 0; } else if( live == DEAD ) { return -EINVAL; } if( (error = pthread_mutex_init (&fillMutex, NULL) ) != 0 ) { return error; } tone_count = 0; if( (error = pthread_mutex_init( &toneMutex, NULL ) ) != 0 ) { return error; } if( (error = pthread_cond_init( &condvar_newtone, NULL ) ) != 0 ) { pthread_mutex_destroy( &toneMutex ); return error; } audio_manager_get_handle( AUDIO_TYPE_VOICE_TONES, getpid(), true, &audioman_handle ); if( (error = setupAudio( )) != 0 ) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to initialize audio %s\n", snd_strerror(error)); pthread_mutex_destroy( &toneMutex ); pthread_cond_destroy( &condvar_newtone ); if( audioman_handle ) { audio_manager_free_handle( audioman_handle ); } return error; } // Re-usable buffer for generation stage_buffer = malloc (frame_size); memset(stage_buffer, 0, frame_size); stage_samples = malloc (frame_size); memset(stage_samples, 0, frame_size); record_buffer = malloc (frame_size); memset(record_buffer, 0, frame_size); render_buffer = malloc (frame_size); memset(render_buffer, 0, frame_size); // Default tonegen volume is 75% to achieve a 16dB loss ( SW mixer uses 10%=6dB. ) setVolume(85); live = RUNNING; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED); pthread_getschedparam (pthread_self (), &policy, ¶m); param.sched_priority=12; pthread_attr_setschedparam (&attr, ¶m); pthread_attr_setschedpolicy (&attr, SCHED_RR); if( (error = pthread_create( &toneGeneratorThread, &attr, processTones, NULL ) ) != 0 ) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to create tone thread %s\n", strerror(error)); snd_pcm_close (playback_handle); //free( frag_buffer ); pthread_mutex_destroy( &toneMutex ); pthread_cond_destroy( &condvar_newtone ); live = STOPPED; if( audioman_handle ) { audio_manager_free_handle( audioman_handle ); } pthread_attr_destroy(&attr); return error; } pthread_attr_destroy(&attr); return 0; }