]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
Make the "microphone mutex" private (static)
authorc vw <dl1ycf@darc.de>
Thu, 27 May 2021 07:29:32 +0000 (09:29 +0200)
committerc vw <dl1ycf@darc.de>
Thu, 27 May 2021 07:29:32 +0000 (09:29 +0200)
audio.c
portaudio.c
pulseaudio.c

diff --git a/audio.c b/audio.c
index 49ff5eb83eac98056a308c9de551dbaf963a859e..7c54ed8e7b63c630052a06b80926627184a1869a 100644 (file)
--- a/audio.c
+++ b/audio.c
@@ -50,7 +50,7 @@
 
 int audio = 0;
 int mic_buffer_size = 720; // samples (both left and right)
-GMutex audio_mutex;
+static GMutex audio_mutex;
 
 static snd_pcm_t *record_handle=NULL;
 static snd_pcm_format_t record_audio_format;
index b0fed871a3f7afc2f2b05491ff6397a572e3f85d..9ef19ccab6bf4462c279f08dbd52c395627be6c1 100644 (file)
@@ -45,7 +45,7 @@ AUDIO_DEVICE input_devices[MAX_AUDIO_DEVICES];
 int n_output_devices;
 AUDIO_DEVICE output_devices[MAX_AUDIO_DEVICES];
 
-GMutex audio_mutex;
+static GMutex audio_mutex;
 int n_input_devices=0;
 int n_output_devices=0;
 
@@ -105,7 +105,7 @@ void audio_get_cards()
   err = Pa_Initialize();
   if( err != paNoError )
   {
-       fprintf(stderr, "PORTAUDIO ERROR: Pa_Initialize: %s\n", Pa_GetErrorText(err));
+       g_print("%s: init error %s\n", __FUNCTION__,Pa_GetErrorText(err));
        return;
   }
   numDevices = Pa_GetDeviceCount();
@@ -135,7 +135,7 @@ void audio_get_cards()
             input_devices[n_input_devices].index=i;
             n_input_devices++;
           }
-          fprintf(stderr,"PORTAUDIO INPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name);
+          g_print("%s: INPUT DEVICE, No=%d, Name=%s\n", __FUNCTION__, i, deviceInfo->name);
        }
 
        outputParameters.device = i;
@@ -150,7 +150,7 @@ void audio_get_cards()
             output_devices[n_output_devices].index=i;
             n_output_devices++;
           }
-          fprintf(stderr,"PORTAUDIO OUTPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name);
+          g_print("%s: OUTPUT DEVICE, No=%d, Name=%s\n", __FUNCTION__, i, deviceInfo->name);
         }
   }
 }
@@ -179,7 +179,6 @@ 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)) {
@@ -187,15 +186,16 @@ int audio_open_input()
        break;
     }
   }
-  fprintf(stderr,"audio_open_input: name=%s PADEV=%d\n",transmitter->microphone_name,padev);
+  g_print("%s: name=%s PADEV=%d\n", __FUNCTION__, transmitter->microphone_name, padev);
   //
-  // Should not occur, but possibly device name not found
+  // Device name possibly came from props file and device is no longer there
   //
   if (padev < 0) {
-    g_mutex_unlock(&audio_mutex);
     return -1;
   }
 
+  g_mutex_lock(&audio_mutex);
+
   bzero( &inputParameters, sizeof( inputParameters ) ); //not necessary if you are filling in all the fields
   inputParameters.channelCount = 1;   // MONO
   inputParameters.device = padev;
@@ -207,7 +207,7 @@ int audio_open_input()
   err = Pa_OpenStream(&record_handle, &inputParameters, NULL, 48000.0, (unsigned long) MY_AUDIO_BUFFER_SIZE,
                       paNoFlag, pa_mic_cb, NULL);
   if (err != paNoError) {
-    fprintf(stderr, "PORTAUDIO ERROR: AOI open stream: %s\n",Pa_GetErrorText(err));
+    g_print("%s: open stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
     record_handle=NULL;
     g_mutex_unlock(&audio_mutex);
     return -1;
@@ -215,22 +215,33 @@ int audio_open_input()
 
   mic_ring_buffer=(float *) g_new(float,MY_RING_BUFFER_SIZE);
   mic_ring_outpt = mic_ring_inpt=0;
+
   if (mic_ring_buffer == NULL) {
+    Pa_CloseStream(record_handle);
+    record_handle=NULL;
+    g_print("%s: alloc buffer failed.\n", __FUNCTION__);
     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_print("%s: start stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
+    Pa_CloseStream(record_handle);
+    record_handle=NULL;
+    g_free(mic_ring_buffer);
+    mic_ring_buffer=NULL;
     g_mutex_unlock(&audio_mutex);
-    audio_close_input();
     return -1;
   }
+
+  //
+  // Finished!
+  //
   g_mutex_unlock(&audio_mutex);
   return 0;
 }
+
 //
 // PortAudio call-back function for Audio output
 //
@@ -242,28 +253,34 @@ int pa_out_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP
   float *out = (float *)outputBuffer;
   RECEIVER *rx = (RECEIVER *)userdata;
   int i, newpt;
-  float *buffer=rx->local_audio_buffer;
   int avail;  // only used for debug
 
   if (out == NULL) {
-    fprintf(stderr,"PortAudio error: bogus audio buffer in callback\n");
+    g_print("%s: bogus audio buffer in callback\n", __FUNCTION__);
     return paContinue;
   }
-  // DEBUG: report water mark
-  //avail = rx->local_audio_buffer_inpt - rx->local_audio_buffer_outpt;
-  //if (avail < 0) avail += MY_RING_BUFFER_SIZE;
-  //fprintf(stderr,"AVAIL=%d\n", avail);
-  newpt=rx->local_audio_buffer_outpt;
-  for (i=0; i< framesPerBuffer; i++) {
-    if (rx->local_audio_buffer_inpt == newpt) {
-      // Ring buffer empty, send zero sample
-      *out++ = 0.0;
-    } else {
-      *out++ = buffer[newpt++];
-      if (newpt >= MY_RING_BUFFER_SIZE) newpt=0;
-      rx->local_audio_buffer_outpt=newpt;
+  g_mutex_lock(&rx->local_audio_mutex);
+  if (rx->local_audio_buffer != NULL) {
+    //
+    // Mutex protection: if the buffer is non-NULL it cannot vanish
+    // util callback is completed
+    // DEBUG: report water mark
+    //avail = rx->local_audio_buffer_inpt - rx->local_audio_buffer_outpt;
+    //if (avail < 0) avail += MY_RING_BUFFER_SIZE;
+    //g_print("%s: AVAIL=%d\n", __FUNCTION__, avail);
+    newpt=rx->local_audio_buffer_outpt;
+    for (i=0; i< framesPerBuffer; i++) {
+      if (rx->local_audio_buffer_inpt == newpt) {
+        // Ring buffer empty, send zero sample
+        *out++ = 0.0;
+      } else {
+        *out++ = rx->local_audio_buffer[newpt++];
+        if (newpt >= MY_RING_BUFFER_SIZE) newpt=0;
+        rx->local_audio_buffer_outpt=newpt;
+      }
     }
   }
+  g_mutex_unlock(&rx->local_audio_mutex);
   return paContinue;
 }
 
@@ -277,41 +294,29 @@ int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP
 {
   float *in = (float *)inputBuffer;
   int i, newpt;
-  float sample;
 
   if (in == NULL) {
     // This should not happen, so we do not send silence etc.
-    fprintf(stderr,"PortAudio error: bogus audio buffer in callback\n");
+    g_print("%s: bogus audio buffer in callback\n", __FUNCTION__);
     return paContinue;
   }
-  //
-  // send the samples in the buffer
-  //
   g_mutex_lock(&audio_mutex);
-  for (i=0; i<framesPerBuffer; i++) {
-    sample=in[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) {
-         newpt=mic_ring_inpt +1;
-         if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
-         if (newpt != mic_ring_outpt) {
-           // buffer space available, do the write
-           mic_ring_buffer[mic_ring_inpt]=sample;
-           // atomic update of mic_ring_inpt
-           mic_ring_inpt=newpt;
-         }
-       }
-       break;
-      default:
-       break;
+  if (mic_ring_buffer != NULL) {
+    //
+    // mutex protected: ring buffer cannot vanish
+    //
+    for (i=0; i<framesPerBuffer; i++) {
+      //
+      // put sample into ring buffer
+      //
+      newpt=mic_ring_inpt +1;
+      if (newpt == MY_RING_BUFFER_SIZE) newpt=0;
+      if (newpt != mic_ring_outpt) {
+        // buffer space available, do the write
+        mic_ring_buffer[mic_ring_inpt]=in[i];
+        // atomic update of mic_ring_inpt
+        mic_ring_inpt=newpt;
+      }
     }
   }
   g_mutex_unlock(&audio_mutex);
@@ -326,6 +331,10 @@ float audio_get_next_mic_sample() {
   int newpt;
   float sample;
   g_mutex_lock(&audio_mutex);
+  //
+  // mutex protected (for every single sample!):
+  // ring buffer cannot vanish while being processed here
+  //
   if ((mic_ring_buffer == NULL) || (mic_ring_outpt == mic_ring_inpt)) {
     // no buffer, or nothing in buffer: insert silence
     sample=0.0;
@@ -366,15 +375,16 @@ int audio_open_output(RECEIVER *rx)
         break;
     }
   }
-  fprintf(stderr,"audio_open_output: name=%s PADEV=%d\n",rx->audio_name,padev);
+  g_print("%s: name=%s PADEV=%d\n", __FUNCTION__, rx->audio_name, padev); 
   //
-  // Should not occur, but possibly device name not found
+  // Device name possibly came from props file and device is no longer there
   //
   if (padev < 0) {
     return -1;
   }
 
   g_mutex_lock(&rx->local_audio_mutex);
+
   bzero( &outputParameters, sizeof( outputParameters ) ); //not necessary if you are filling in all the fields
   outputParameters.channelCount = 1;   // Always MONO
   outputParameters.device = padev;
@@ -384,6 +394,15 @@ int audio_open_output(RECEIVER *rx)
   outputParameters.suggestedLatency = 0.0; //Pa_GetDeviceInfo(padev)->defaultLowOutputLatency ;
   outputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
 
+  err = Pa_OpenStream(&(rx->playstream), NULL, &outputParameters, 48000.0, (unsigned long) MY_AUDIO_BUFFER_SIZE,
+                      paNoFlag, pa_out_cb, rx);
+  if (err != paNoError) {
+    g_print("%s: open stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
+    rx->playstream = NULL;
+    g_mutex_unlock(&rx->local_audio_mutex);
+    return -1;
+  }
+
   //
   // This is now a ring buffer much larger than a single audio buffer
   //
@@ -392,26 +411,27 @@ int audio_open_output(RECEIVER *rx)
   rx->local_audio_buffer_outpt=0;
   rx->local_audio_cw=0;
 
-  err = Pa_OpenStream(&(rx->playback_handle), NULL, &outputParameters, 48000.0, (unsigned long) MY_AUDIO_BUFFER_SIZE,
-                      paNoFlag, pa_out_cb, rx);
-  if (err != paNoError || rx->local_audio_buffer == NULL) {
-    fprintf(stderr,"PORTAUDIO ERROR: out open stream: %s\n",Pa_GetErrorText(err));
-    rx->playback_handle = NULL;
-    if (rx->local_audio_buffer) g_free(rx->local_audio_buffer);
-    rx->local_audio_buffer = NULL;
+  if (rx->local_audio_buffer == NULL) {
+    g_print("%s: allocate buffer failed\n", __FUNCTION__);
+    Pa_CloseStream(rx->playstream);
+    rx->playstream=NULL;
     g_mutex_unlock(&rx->local_audio_mutex);
     return -1;
   }
 
-  err = Pa_StartStream(rx->playback_handle);
+  err = Pa_StartStream(rx->playstream);
   if (err != paNoError) {
-    fprintf(stderr,"PORTAUDIO ERROR: out start stream:%s\n",Pa_GetErrorText(err));
-    rx->playback_handle=NULL;
-    if (rx->local_audio_buffer) g_free(rx->local_audio_buffer);
+    g_print("%s: error starting stream:%s\n",__FUNCTION__,Pa_GetErrorText(err));
+    Pa_CloseStream(rx->playstream);
+    rx->playstream=NULL;
+    g_free(rx->local_audio_buffer);
     rx->local_audio_buffer = NULL;
     g_mutex_unlock(&rx->local_audio_mutex);
     return -1;
   }
+  //
+  // Finished!
+  //
   g_mutex_unlock(&rx->local_audio_mutex);
   return 0;
 }
@@ -424,34 +444,25 @@ int audio_open_output(RECEIVER *rx)
 void audio_close_input()
 {
   PaError err;
-  void *p;
 
-  fprintf(stderr,"AudioCloseInput: %s\n", transmitter->microphone_name);
+  g_print("%s: micname=%s\n", __FUNCTION__,transmitter->microphone_name);
 
+  g_mutex_lock(&audio_mutex);
   if(record_handle!=NULL) {
     err = Pa_StopStream(record_handle);
     if (err != paNoError) {
-      fprintf(stderr,"PORTAUDIO ERROR: in stop stream: %s\n",Pa_GetErrorText(err));
+      g_print("%s: error stopping stream: %s\n",__FUNCTION__,Pa_GetErrorText(err));
     }
     err = Pa_CloseStream(record_handle);
     if (err != paNoError) {
-      fprintf(stderr,"PORTAUDIO ERROR: in close stream: %s\n",Pa_GetErrorText(err));
+      g_print("%s: %s\n",__FUNCTION__,Pa_GetErrorText(err));
     }
     record_handle=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 callback" function,
-  // 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);
 }
 
 //
@@ -462,7 +473,7 @@ void audio_close_input()
 void audio_close_output(RECEIVER *rx) {
   PaError err;
 
-  fprintf(stderr,"AudioCloseOutput: %s\n", rx->audio_name);
+  g_print("%s: device=%sn", __FUNCTION__,rx->audio_name);
 
   g_mutex_lock(&rx->local_audio_mutex);
   if(rx->local_audio_buffer!=NULL) {
@@ -470,16 +481,16 @@ void audio_close_output(RECEIVER *rx) {
     rx->local_audio_buffer=NULL;
   }
 
-  if(rx->playback_handle!=NULL) {
-    err = Pa_StopStream(rx->playback_handle);
+  if(rx->playstream!=NULL) {
+    err = Pa_StopStream(rx->playstream);
     if (err != paNoError) {
-      fprintf(stderr,"PORTAUDIO ERROR: out stop stream: %s\n",Pa_GetErrorText(err));
+      g_print("%s: stop stream error %s\n", __FUNCTION__, Pa_GetErrorText(err));
     }
-    err = Pa_CloseStream(rx->playback_handle);
+    err = Pa_CloseStream(rx->playstream);
     if (err != paNoError) {
-      fprintf(stderr,"PORTAUDIO ERROR: out close stream: %s\n",Pa_GetErrorText(err));
+      g_print("%s: close stream error %s\n",__FUNCTION__,Pa_GetErrorText(err));
     }
-    rx->playback_handle=NULL;
+    rx->playstream=NULL;
   }
   g_mutex_unlock(&rx->local_audio_mutex);
 }
@@ -516,7 +527,7 @@ int audio_write (RECEIVER *rx, float left, float right)
   }
 
   g_mutex_lock(&rx->local_audio_mutex);
-  if (rx->playback_handle != NULL && buffer != NULL) {
+  if (rx->playstream != NULL && buffer != NULL) {
     if (rx->local_audio_cw == 1) {
       //
       // We come from a TX->RX transition:
@@ -590,21 +601,20 @@ int audio_write (RECEIVER *rx, float left, float right)
 // Thus we have an active latency management.
 //
 int cw_audio_write(RECEIVER *rx, float sample) {
-  float *buffer = rx->local_audio_buffer;
   int oldpt, newpt;
   static int count=0;
   int avail;
   int adjust;
 
   g_mutex_lock(&rx->local_audio_mutex);
-  if (rx->playback_handle != NULL && buffer != NULL) {
+  if (rx->playstream != NULL && rx->local_audio_buffer != NULL) {
     if (rx->local_audio_cw == 0 && cw_keyer_sidetone_volume > 0) {
       //
       // First time producing CW audio after RX/TX transition:
       // empty audio buffer and insert 512 samples of silence
       //
       rx->local_audio_cw=1;
-      bzero(buffer, 512*sizeof(float));
+      bzero(rx->local_audio_buffer, 512*sizeof(float));
       rx->local_audio_buffer_inpt=512;
       rx->local_audio_buffer_outpt=0;
       count=0;
@@ -637,7 +647,7 @@ int cw_audio_write(RECEIVER *rx, float sample) {
           //
           // buffer space available
           //
-          buffer[oldpt] = sample;
+          rx->local_audio_buffer[oldpt] = sample;
           rx->local_audio_buffer_inpt=newpt;
         }
         break;
@@ -647,9 +657,9 @@ int cw_audio_write(RECEIVER *rx, float sample) {
         // insert two samples of silence. No check on "buffer full" needed
         //
         oldpt=rx->local_audio_buffer_inpt;
-        buffer[oldpt++]=0.0;
+        rx->local_audio_buffer[oldpt++]=0.0;
         if (oldpt == MY_RING_BUFFER_SIZE) oldpt=0;
-        buffer[oldpt++]=0.0;
+        rx->local_audio_buffer[oldpt++]=0.0;
         if (oldpt == MY_RING_BUFFER_SIZE) oldpt=0;
         rx->local_audio_buffer_inpt=oldpt;
         break;
index 6c13ff86dd310c374197f012b4b3a52a56eb751f..3ea44574f5bce70b9e94d617fd39eddb49259896 100644 (file)
@@ -21,7 +21,7 @@ AUDIO_DEVICE output_devices[MAX_AUDIO_DEVICES];
 
 //
 // Ring buffer for "local microphone" samples
-// NOTE: lead large buffer for some "loopback" devices which produce
+// NOTE: need large buffer for some "loopback" devices which produce
 //       samples in large chunks if fed from digimode programs.
 //
 #define MICRINGLEN 6000
@@ -36,11 +36,11 @@ static pa_context *pa_ctx;
 static pa_simple* microphone_stream;
 static gint local_microphone_buffer_offset;
 static float *local_microphone_buffer=NULL;
-static GThread *mic_read_thread_id;
+static GThread *mic_read_thread_id=0;
 static gboolean running;
 
 gint local_microphone_buffer_size=720;
-GMutex audio_mutex;
+static GMutex audio_mutex;
 
 static void source_list_cb(pa_context *context,const pa_source_info *s,int eol,void *data) {
   int i;
@@ -122,7 +122,7 @@ void audio_get_cards() {
   g_mutex_lock(&audio_mutex);
   main_loop=pa_glib_mainloop_new(NULL);
   main_loop_api=pa_glib_mainloop_get_api(main_loop);
-  pa_ctx=pa_context_new(main_loop_api,"linhpsdr");
+  pa_ctx=pa_context_new(main_loop_api,"piHPSDR");
   pa_context_connect(pa_ctx,NULL,0,NULL);
   pa_context_set_state_callback(pa_ctx, state_cb, NULL);
 }
@@ -144,7 +144,7 @@ int audio_open_output(RECEIVER *rx) {
     char stream_id[16];
     sprintf(stream_id,"RX-%d",rx->id);
 
-    rx->playback_handle=pa_simple_new(NULL,               // Use the default server.
+    rx->playstream=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->playback_handle!=NULL) {
+    if(rx->playstream!=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));
@@ -177,7 +177,7 @@ static void *mic_read_thread(gpointer arg) {
   while(running) {
     //
     // 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)
+    // will not be destroyed until this thread has terminated (and waited for via thread joining)
     //
     rc=pa_simple_read(microphone_stream,
             local_microphone_buffer,
@@ -276,9 +276,9 @@ int audio_open_input() {
 
 void audio_close_output(RECEIVER *rx) {
   g_mutex_lock(&rx->local_audio_mutex);
-  if(rx->playback_handle!=NULL) {
-    pa_simple_free(rx->playback_handle);
-    rx->playback_handle=NULL;
+  if(rx->playstream!=NULL) {
+    pa_simple_free(rx->playstream);
+    rx->playstream=NULL;
   }
   if(rx->local_audio_buffer!=NULL) {
     g_free(rx->local_audio_buffer);
@@ -289,12 +289,18 @@ void audio_close_output(RECEIVER *rx) {
 
 void audio_close_input() {
   running=FALSE;
+  g_mutex_lock(&audio_mutex);
+
   if(mic_read_thread_id!=NULL) {
 g_print("audio_close_input: wait for thread to complete\n");
+    //
+    // wait for the mic read thread to terminate,
+    // then destroy the stream and the buffers
+    // This way, the buffers cannot "vanish" in the mic read thread
+    //
     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;
@@ -337,17 +343,13 @@ int cw_audio_write(RECEIVER *rx,float sample) {
   int err;
 
   g_mutex_lock(&rx->local_audio_mutex);
-  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);
-    }
 
+  if (rx->playstream != NULL && rx->local_audio_buffer != NULL) {  // Note this test must be done "mutex-protected"
     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,
+      rc=pa_simple_write(rx->playstream,
                          rx->local_audio_buffer,
                          rx->local_audio_buffer_size*sizeof(float)*2,
                          &err);
@@ -368,17 +370,13 @@ int audio_write(RECEIVER *rx,float left_sample,float right_sample) {
   int err;
 
   g_mutex_lock(&rx->local_audio_mutex);
-  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);
-    }
 
+  if (rx->playstream != NULL && rx->local_audio_buffer != NULL) {  // Note this test must be done "mutex-protected"
     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,
+      rc=pa_simple_write(rx->playstream,
                          rx->local_audio_buffer,
                          rx->local_audio_buffer_size*sizeof(float)*2,
                          &err);