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;
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);
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 {
if(i>=FORMATS) {
g_print("audio_open_input: cannot find usable format\n");
+ g_mutex_unlock(&audio_mutex);
audio_close_input();
return err;
}
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;
}
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;
}
}
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);
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);
}
//
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;
}
g_print("audio_get_cards\n");
+ g_mutex_init(&audio_mutex);
n_input_devices=0;
n_output_devices=0;
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;
PaError err;
+ g_mutex_init(&audio_mutex);
err = Pa_Initialize();
if( err != paNoError )
{
//
// 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)) {
// Should not occur, but possibly device name not found
//
if (padev < 0) {
+ g_mutex_unlock(&audio_mutex);
return -1;
}
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;
}
//
//
// send the samples in the buffer
//
+ g_mutex_lock(&audio_mutex);
for (i=0; i<framesPerBuffer; i++) {
sample=in[i];
switch(protocol) {
// 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) {
break;
}
}
+ g_mutex_unlock(&audio_mutex);
return paContinue;
}
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;
}
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;
}
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;
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,
&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));
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__);
}
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;
}
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);
}
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);
}
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;
}
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);
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);