]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
Unified the audio modules a bit (same name for handle, re-worked "microphone mutex")
authorc vw <dl1ycf@darc.de>
Mon, 24 May 2021 17:09:41 +0000 (19:09 +0200)
committerc vw <dl1ycf@darc.de>
Mon, 24 May 2021 17:09:41 +0000 (19:09 +0200)
audio.c
portaudio.c
pulseaudio.c
receiver.c
receiver.h

diff --git a/audio.c b/audio.c
index ff200fabe6c587d352882dc07309e018ca15879e..49ff5eb83eac98056a308c9de551dbaf963a859e 100644 (file)
--- 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;i++) {
+    g_mutex_lock(&audio_mutex);
     if ((err = snd_pcm_open (&record_handle, hw, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC)) < 0) {
       g_print("audio_open_input: cannot open audio device %s (%s)\n",
               hw,
               snd_strerror (err));
+      record_handle=NULL;
+      g_mutex_unlock(&audio_mutex);
       return err;
     }
 g_print("audio_open_input: handle=%p\n",record_handle);
@@ -204,6 +208,7 @@ g_print("audio_open_input: handle=%p\n",record_handle);
 g_print("audio_open_input: trying format %s (%s)\n",snd_pcm_format_name(formats[i]),snd_pcm_format_description(formats[i]));
     if ((err = snd_pcm_set_params (record_handle,formats[i],SND_PCM_ACCESS_RW_INTERLEAVED,channels,rate,soft_resample,latency)) < 0) {
       g_print("audio_open_input: snd_pcm_set_params failed: %s\n",snd_strerror(err));
+      g_mutex_unlock(&audio_mutex);
       audio_close_input();
       continue;
     } else {
@@ -215,6 +220,7 @@ g_print("audio_open_input: using format %s (%s)\n",snd_pcm_format_name(formats[i
 
   if(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;
 
index c68d1f718c169002594c52f86c9b66bd16e9d4cb..b0fed871a3f7afc2f2b05491ff6397a572e3f85d 100644 (file)
 
 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; i<n_input_devices; i++) {
     if (!strcmp(transmitter->microphone_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; i<framesPerBuffer; i++) {
     sample=in[i];
     switch(protocol) {
@@ -287,8 +300,6 @@ int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP
        // put sample into ring buffer
        //
        if (mic_ring_buffer != NULL) {
-          // the "existence" of the ring buffer is now guaranteed for 1 msec,
-          // see audio_close_input(),
          newpt=mic_ring_inpt +1;
          if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
          if (newpt != mic_ring_outpt) {
@@ -303,6 +314,7 @@ int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP
        break;
     }
   }
+  g_mutex_unlock(&audio_mutex);
   return paContinue;
 }
 
@@ -313,18 +325,18 @@ int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP
 float audio_get_next_mic_sample() {
   int newpt;
   float sample;
+  g_mutex_lock(&audio_mutex);
   if ((mic_ring_buffer == NULL) || (mic_ring_outpt == mic_ring_inpt)) {
     // 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_outpt+1;
     if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
     sample=mic_ring_buffer[mic_ring_outpt];
     // atomic update of read pointer
     mic_ring_outpt=newpt;
   }
+  g_mutex_unlock(&audio_mutex);
   return sample;
 }
 
@@ -644,7 +656,7 @@ int cw_audio_write(RECEIVER *rx, float sample) {
       case 2:
         //
         // buffer becomes too full, and we just saw
-        // 16 samples of silence: just skip it
+        // 16 samples of silence: just skip the last "silent" sample
         //
         break;
     }
index 2435907e6c13ff12805b43a67690d2de6b2fd0e2..6c13ff86dd310c374197f012b4b3a52a56eb751f 100644 (file)
@@ -35,7 +35,7 @@ static pa_operation *op;
 static pa_context *pa_ctx;
 static pa_simple* microphone_stream;
 static gint local_microphone_buffer_offset;
-static float *local_microphone_buffer;
+static float *local_microphone_buffer=NULL;
 static GThread *mic_read_thread_id;
 static gboolean running;
 
@@ -144,7 +144,7 @@ int audio_open_output(RECEIVER *rx) {
     char stream_id[16];
     sprintf(stream_id,"RX-%d",rx->id);
 
-    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;i<local_microphone_buffer_size;i++) {
-          gfloat sample=local_microphone_buffer[i];
-          switch(protocol) {
-            case ORIGINAL_PROTOCOL:
-            case NEW_PROTOCOL:
-#ifdef SOAPYSDR
-            case SOAPYSDR_PROTOCOL:
-#endif
-              //
-              // put sample into ring buffer
-              //
-              if (mic_ring_buffer != NULL) {
-                // the "existence" of the ring buffer is now guaranteed for 1 msec,
-                // see audio_close_input().
-                newpt=mic_ring_write_pt +1;
-                if (newpt == MICRINGLEN) newpt=0;
-                if (newpt != mic_ring_read_pt) {
-                  // buffer space available, do the write
-                  mic_ring_buffer[mic_ring_write_pt]=sample;
-                  // atomic update of mic_ring_write_pt
-                  mic_ring_write_pt=newpt;
-                }
-              }
-              break;
-            default:
-              break;
-          }
+    if(rc<0) {
+      running=FALSE;
+      g_print("%s: returned %d error=%d (%s)\n",__FUNCTION__,rc,err,pa_strerror(err));
+    } else {
+      int newpt;
+      for(gint i=0;i<local_microphone_buffer_size;i++) {
+        gfloat sample=local_microphone_buffer[i];
+        //
+        // put sample into ring buffer
+        //
+        newpt=mic_ring_write_pt +1;
+        if (newpt == MICRINGLEN) newpt=0;
+        if (newpt != mic_ring_read_pt) {
+          // buffer space available, do the write
+          mic_ring_buffer[mic_ring_write_pt]=sample;
+          // atomic update of mic_ring_write_pt
+          mic_ring_write_pt=newpt;
         }
       }
     }
-    g_mutex_unlock(&audio_mutex);
   }
   g_print("%s: exit\n",__FUNCTION__);
 }
@@ -267,6 +251,7 @@ int audio_open_input() {
     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;
     }
@@ -291,9 +276,9 @@ int audio_open_input() {
 
 void audio_close_output(RECEIVER *rx) {
   g_mutex_lock(&rx->local_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);
 
index 80d44ce0d5acf468d5ad84419cfadbad113a62de..cf60abcc241f016562ce9ddcc33a4d1803c4d568 100644 (file)
@@ -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;
index 1fc1057404c426434a9d1fb9495d2fe86151b2c3..8509a69e8b43a3c6610b3f7b6736b7353ba8ab2a 100644 (file)
@@ -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