From: c vw Date: Mon, 24 May 2021 17:09:41 +0000 (+0200) Subject: Unified the audio modules a bit (same name for handle, re-worked "microphone mutex") X-Git-Url: https://git.rkrishnan.org/listings/vdrive/index.php?a=commitdiff_plain;h=330ad8a82ebf1ba695bfa63b5e5bdad6aae0689d;p=pihpsdr.git Unified the audio modules a bit (same name for handle, re-worked "microphone mutex") --- diff --git a/audio.c b/audio.c index ff200fa..49ff5eb 100644 --- a/audio.c +++ b/audio.c @@ -50,6 +50,7 @@ int audio = 0; int mic_buffer_size = 720; // samples (both left and right) +GMutex audio_mutex; static snd_pcm_t *record_handle=NULL; static snd_pcm_format_t record_audio_format; @@ -193,10 +194,13 @@ g_print("audio_open_input: %s\n",transmitter->microphone_name); g_print("audio_open_input: hw=%s\n",hw); for(i=0;i=FORMATS) { g_print("audio_open_input: cannot find usable format\n"); + g_mutex_unlock(&audio_mutex); audio_close_input(); return err; } @@ -240,6 +246,7 @@ g_print("audio_open_input: allocating ring buffer\n"); mic_ring_buffer=(float *) g_new(float,MICRINGLEN); mic_ring_read_pt = mic_ring_write_pt=0; if (mic_ring_buffer == NULL) { + g_mutex_unlock(&audio_mutex); audio_close_input(); return -1; } @@ -249,10 +256,12 @@ g_print("audio_open_input: creating mic_read_thread\n"); mic_read_thread_id = g_thread_try_new("microphone",mic_read_thread,NULL,&error); if(!mic_read_thread_id ) { g_print("g_thread_new failed on mic_read_thread: %s\n",error->message); + g_mutex_unlock(&audio_mutex); audio_close_input(); return -1; } + g_mutex_unlock(&audio_mutex); return 0; } @@ -271,14 +280,15 @@ g_print("audio_close_output: rx=%d handle=%p buffer=%p\n",rx->id,rx->playback_ha } void audio_close_input() { - void *p; g_print("audio_close_input\n"); running=FALSE; + g_mutex_lock(&audio_mutex); if(mic_read_thread_id!=NULL) { g_print("audio_close_input: wait for thread to complete\n"); g_thread_join(mic_read_thread_id); mic_read_thread_id=NULL; } + g_mutex_lock(&audio_mutex); if(record_handle!=NULL) { g_print("audio_close_input: snd_pcm_close\n"); snd_pcm_close (record_handle); @@ -289,19 +299,10 @@ g_print("audio_close_input: free mic buffer\n"); g_free(mic_buffer); mic_buffer=NULL; } - // - // We do not want to do a mutex lock/unlock for every single mic sample - // accessed. Since only the ring buffer is maintained by the functions - // audio_get_next_mic_sample() and in the "mic read thread", - // it is more than enough to wait 2 msec after setting mic_ring_buffer to NULL - // before actually releasing the storage. - // if (mic_ring_buffer != NULL) { - p=mic_ring_buffer; - mic_ring_buffer=NULL; - usleep(2); - g_free(p); + g_free(mic_ring_buffer); } + g_mutex_unlock(&audio_mutex); } // @@ -641,18 +642,18 @@ g_print("mic_read_thread: exiting\n"); float audio_get_next_mic_sample() { int newpt; float sample; + g_mutex_lock(&audio_mutex); if ((mic_ring_buffer == NULL) || (mic_ring_read_pt == mic_ring_write_pt)) { // no buffer, or nothing in buffer: insert silence sample=0.0; } else { - // the "existence" of the ring buffer is now guaranteed for 1 msec, - // see audio_close_input(), newpt = mic_ring_read_pt+1; if (newpt == MICRINGLEN) newpt=0; sample=mic_ring_buffer[mic_ring_read_pt]; // atomic update of read pointer mic_ring_read_pt=newpt; } + g_mutex_unlock(&audio_mutex); return sample; } @@ -667,6 +668,7 @@ void audio_get_cards() { g_print("audio_get_cards\n"); + g_mutex_init(&audio_mutex); n_input_devices=0; n_output_devices=0; diff --git a/portaudio.c b/portaudio.c index c68d1f7..b0fed87 100644 --- a/portaudio.c +++ b/portaudio.c @@ -39,11 +39,13 @@ static PaStream *record_handle=NULL; + int n_input_devices; AUDIO_DEVICE input_devices[MAX_AUDIO_DEVICES]; int n_output_devices; AUDIO_DEVICE output_devices[MAX_AUDIO_DEVICES]; +GMutex audio_mutex; int n_input_devices=0; int n_output_devices=0; @@ -99,6 +101,7 @@ void audio_get_cards() PaError err; + g_mutex_init(&audio_mutex); err = Pa_Initialize(); if( err != paNoError ) { @@ -176,6 +179,7 @@ int audio_open_input() // // Look up device name and determine device ID // + g_mutex_lock(&audio_mutex); padev=-1; for (i=0; imicrophone_name, input_devices[i].name)) { @@ -188,6 +192,7 @@ int audio_open_input() // Should not occur, but possibly device name not found // if (padev < 0) { + g_mutex_unlock(&audio_mutex); return -1; } @@ -203,20 +208,27 @@ int audio_open_input() paNoFlag, pa_mic_cb, NULL); if (err != paNoError) { fprintf(stderr, "PORTAUDIO ERROR: AOI open stream: %s\n",Pa_GetErrorText(err)); + record_handle=NULL; + g_mutex_unlock(&audio_mutex); return -1; } mic_ring_buffer=(float *) g_new(float,MY_RING_BUFFER_SIZE); mic_ring_outpt = mic_ring_inpt=0; if (mic_ring_buffer == NULL) { + g_mutex_unlock(&audio_mutex); + audio_close_input(); return -1; } err = Pa_StartStream(record_handle); if (err != paNoError) { fprintf(stderr, "PORTAUDIO ERROR: AOI start stream:%s\n",Pa_GetErrorText(err)); + g_mutex_unlock(&audio_mutex); + audio_close_input(); return -1; } + g_mutex_unlock(&audio_mutex); return 0; } // @@ -275,6 +287,7 @@ int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP // // send the samples in the buffer // + g_mutex_lock(&audio_mutex); for (i=0; iid); - rx->playstream=pa_simple_new(NULL, // Use the default server. + rx->playback_handle=pa_simple_new(NULL, // Use the default server. "piHPSDR", // Our application's name. PA_STREAM_PLAYBACK, rx->audio_name, @@ -155,7 +155,7 @@ int audio_open_output(RECEIVER *rx) { &err // error code if returns NULL ); - if(rx->playstream!=NULL) { + if(rx->playback_handle!=NULL) { rx->local_audio_buffer_offset=0; rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size); g_print("%s: allocated local_audio_buffer %p size %ld bytes\n",__FUNCTION__,rx->local_audio_buffer,2*rx->local_audio_buffer_size*sizeof(float)); @@ -175,50 +175,34 @@ static void *mic_read_thread(gpointer arg) { g_print("%s: running=%d\n",__FUNCTION__,running); while(running) { - g_mutex_lock(&audio_mutex); - if(local_microphone_buffer==NULL) { - running=0; - } else { - rc=pa_simple_read(microphone_stream, + // + // It is guaranteed that local_microphone_buffer, mic_ring_buffer, and microphone_stream + // will not be destroyes until this thread has terminated (and waited for via pthread_join) + // + rc=pa_simple_read(microphone_stream, local_microphone_buffer, local_microphone_buffer_size*sizeof(float), &err); - if(rc<0) { - running=0; - g_print("%s: returned %d error=%d (%s)\n",__FUNCTION__,rc,err,pa_strerror(err)); - } else { - gint newpt; - for(gint i=0;ilocal_audio_mutex); - if(rx->playstream!=NULL) { - pa_simple_free(rx->playstream); - rx->playstream=NULL; + if(rx->playback_handle!=NULL) { + pa_simple_free(rx->playback_handle); + rx->playback_handle=NULL; } if(rx->local_audio_buffer!=NULL) { g_free(rx->local_audio_buffer); @@ -303,13 +288,24 @@ void audio_close_output(RECEIVER *rx) { } void audio_close_input() { + running=FALSE; + if(mic_read_thread_id!=NULL) { +g_print("audio_close_input: wait for thread to complete\n"); + g_thread_join(mic_read_thread_id); + mic_read_thread_id=NULL; + } g_mutex_lock(&audio_mutex); if(microphone_stream!=NULL) { pa_simple_free(microphone_stream); microphone_stream=NULL; + } + if (local_microphone_buffer != NULL) { g_free(local_microphone_buffer); local_microphone_buffer=NULL; } + if (mic_ring_buffer != NULL) { + g_free(mic_ring_buffer); + } g_mutex_unlock(&audio_mutex); } @@ -320,20 +316,18 @@ void audio_close_input() { float audio_get_next_mic_sample() { int newpt; float sample; - + g_mutex_lock(&audio_mutex); if ((mic_ring_buffer == NULL) || (mic_ring_read_pt == mic_ring_write_pt)) { // no buffer, or nothing in buffer: insert silence - g_print("%s: no samples\n",__FUNCTION__); sample=0.0; } else { - // the "existence" of the ring buffer is now guaranteed for 1 msec, - // see audio_close_input(), newpt = mic_ring_read_pt+1; if (newpt == MICRINGLEN) newpt=0; sample=mic_ring_buffer[mic_ring_read_pt]; // atomic update of read pointer mic_ring_read_pt=newpt; } + g_mutex_unlock(&audio_mutex); return sample; } @@ -343,23 +337,25 @@ int cw_audio_write(RECEIVER *rx,float sample) { int err; g_mutex_lock(&rx->local_audio_mutex); - if(rx->local_audio_buffer==NULL) { - rx->local_audio_buffer_offset=0; - rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size); - } + if (rx->playback_handle != NULL) { // Note this test must be done "mutex-protected" + if(rx->local_audio_buffer==NULL) { + rx->local_audio_buffer_offset=0; + rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size); + } - rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=sample; - rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=sample; - rx->local_audio_buffer_offset++; - if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) { - rc=pa_simple_write(rx->playstream, - rx->local_audio_buffer, - rx->local_audio_buffer_size*sizeof(float)*2, - &err); - if(rc!=0) { - fprintf(stderr,"audio_write failed err=%d\n",err); + rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=sample; + rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=sample; + rx->local_audio_buffer_offset++; + if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) { + rc=pa_simple_write(rx->playback_handle, + rx->local_audio_buffer, + rx->local_audio_buffer_size*sizeof(float)*2, + &err); + if(rc!=0) { + fprintf(stderr,"cw_audio_write failed err=%d\n",err); + } + rx->local_audio_buffer_offset=0; } - rx->local_audio_buffer_offset=0; } g_mutex_unlock(&rx->local_audio_mutex); @@ -372,23 +368,25 @@ int audio_write(RECEIVER *rx,float left_sample,float right_sample) { int err; g_mutex_lock(&rx->local_audio_mutex); - if(rx->local_audio_buffer==NULL) { - rx->local_audio_buffer_offset=0; - rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size); - } + if (rx->playback_handle != NULL) { // Note this test must be done "mutex-protected" + if(rx->local_audio_buffer==NULL) { + rx->local_audio_buffer_offset=0; + rx->local_audio_buffer=g_new0(float,2*rx->local_audio_buffer_size); + } - rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=left_sample; - rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=right_sample; - rx->local_audio_buffer_offset++; - if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) { - rc=pa_simple_write(rx->playstream, - rx->local_audio_buffer, - rx->local_audio_buffer_size*sizeof(float)*2, - &err); - if(rc!=0) { - fprintf(stderr,"audio_write failed err=%d\n",err); + rx->local_audio_buffer[rx->local_audio_buffer_offset*2]=left_sample; + rx->local_audio_buffer[(rx->local_audio_buffer_offset*2)+1]=right_sample; + rx->local_audio_buffer_offset++; + if(rx->local_audio_buffer_offset>=rx->local_audio_buffer_size) { + rc=pa_simple_write(rx->playback_handle, + rx->local_audio_buffer, + rx->local_audio_buffer_size*sizeof(float)*2, + &err); + if(rc!=0) { + fprintf(stderr,"audio_write failed err=%d\n",err); + } + rx->local_audio_buffer_offset=0; } - rx->local_audio_buffer_offset=0; } g_mutex_unlock(&rx->local_audio_mutex); diff --git a/receiver.c b/receiver.c index 80d44ce..cf60abc 100644 --- a/receiver.c +++ b/receiver.c @@ -925,6 +925,7 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s rx->agc_hang_threshold=0.0; rx->local_audio_buffer=NULL; + rx->playback_handle=NULL; rx->local_audio_buffer_size=2048; rx->local_audio=0; g_mutex_init(&rx->local_audio_mutex); @@ -1058,6 +1059,7 @@ fprintf(stderr,"create_receiver: id=%d default adc=%d\n",rx->id, rx->adc); rx->local_audio=0; g_mutex_init(&rx->local_audio_mutex); + rx->playback_handle=NULL; rx->local_audio_buffer=NULL; rx->local_audio_buffer_size=2048; rx->audio_name=NULL; diff --git a/receiver.h b/receiver.h index 1fc1057..8509a69 100644 --- a/receiver.h +++ b/receiver.h @@ -135,7 +135,7 @@ typedef struct _receiver { gint local_audio_cw; // flag for latency switching #endif #ifdef PULSEAUDIO - pa_simple *playstream; + pa_simple *playback_handle; gboolean output_started; float *local_audio_buffer; #endif