}
void audio_close_input() {
+ void *p;
g_print("audio_close_input\n");
running=FALSE;
if(mic_read_thread_id!=NULL) {
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) {
- free(mic_ring_buffer);
+ p=mic_ring_buffer;
mic_ring_buffer=NULL;
+ usleep(2);
+ g_free(p);
}
}
RECEIVER *rx = active_receiver;
+ g_mutex_lock(&rx->local_audio_mutex);
if(rx->playback_handle!=NULL && rx->local_audio_buffer!=NULL) {
switch(rx->local_audio_format) {
if(rc==-EPIPE) {
if ((rc = snd_pcm_prepare (rx->playback_handle)) < 0) {
g_print("audio_write: cannot prepare audio interface for use %ld (%s)\n", rc, snd_strerror (rc));
+ g_mutex_unlock(&rx->local_audio_mutex);
return rc;
} else {
// ignore short write
rx->local_audio_buffer_offset=0;
}
}
+ g_mutex_unlock(&rx->local_audio_mutex);
return 0;
}
gint32 *long_buffer;
gint16 *short_buffer;
- g_mutex_lock(&rx->local_audio_mutex);
-
if(can_transmit) {
mode=transmitter->mode;
}
//
if (rx == active_receiver && isTransmitting() && (mode==modeCWU || mode==modeCWL)) {
- g_mutex_unlock(&rx->local_audio_mutex);
return 0;
}
+ // lock AFTER checking the "quick return" condition but BEFORE checking the pointers
+ g_mutex_lock(&rx->local_audio_mutex);
+
if(rx->playback_handle!=NULL && rx->local_audio_buffer!=NULL) {
switch(rx->local_audio_format) {
case SND_PCM_FORMAT_S16_LE:
//
// put sample into ring buffer
//
- if (mic_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) {
// 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];
#endif
}
+//
+// For these three items, use free() instead of g_free(),
+// since these have been allocated by ALSA via
+// snd_device_name_get_hint()
+//
if (name != NULL)
free(name);
if (descr != NULL)
#include "filter.h"
#include "band.h"
#include "bandstack.h"
+#include "noise_menu.h"
#include "wdsp.h"
// The following calls functions can be called usig g_idle_add
return 0;
}
+int ext_update_noise(void *data) {
+ update_noise();
+ return 0;
+}
int ext_sat_update(void *data);
int ext_set_rf_gain(void *data);
+int ext_update_noise(void *data);
active_receiver->nr = 1;
active_receiver->nr2= 0;
}
+ g_idle_add(ext_update_noise, NULL);
g_idle_add(ext_vfo_update, NULL);
}
break;
// 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) {
// 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];
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;
rx->playback_handle = NULL;
if (rx->local_audio_buffer) g_free(rx->local_audio_buffer);
rx->local_audio_buffer = NULL;
+ g_mutex_unlock(&rx->local_audio_mutex);
return -1;
}
rx->playback_handle=NULL;
if (rx->local_audio_buffer) g_free(rx->local_audio_buffer);
rx->local_audio_buffer = NULL;
+ g_mutex_unlock(&rx->local_audio_mutex);
return -1;
}
// Write one buffer to avoid under-flow errors
// (this gives us 5 msec to pass before we have to call audio_write the first time)
bzero(rx->local_audio_buffer, (size_t) BUFFER_SIZE*sizeof(float));
err=Pa_WriteStream(rx->playback_handle, rx->local_audio_buffer, (unsigned long) BUFFER_SIZE);
+ g_mutex_unlock(&rx->local_audio_mutex);
return 0;
}
void audio_close_input()
{
PaError err;
+ void *p;
fprintf(stderr,"AudioCloseInput: %s\n", transmitter->microphone_name);
}
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) {
- g_free(mic_ring_buffer);
+ p=mic_ring_buffer;
mic_ring_buffer=NULL;
+ usleep(2);
+ g_free(p);
}
}
fprintf(stderr,"AudioCloseOutput: %s\n", rx->audio_name);
-// free the buffer first, this then indicates to audio_write to do nothing
+ g_mutex_lock(&rx->local_audio_mutex);
if(rx->local_audio_buffer!=NULL) {
g_free(rx->local_audio_buffer);
rx->local_audio_buffer=NULL;
}
rx->playback_handle=NULL;
}
+ g_mutex_unlock(&rx->local_audio_mutex);
}
//
int audio_write (RECEIVER *rx, float left, float right)
{
PaError err;
- int mode=transmitter->mode;
+ int mode=modeUSB;
float *buffer = rx->local_audio_buffer;
+
+ if (can_transmit) {
+ mode=transmitter->mode;
+ }
//
// We have to stop the stream here if a CW side tone may occur.
// This might cause underflows, but we cannot use audio_write
// If *not* doing CW, the stream continues because we might wish
// to listen to this rx while transmitting.
//
- if (rx == active_receiver && isTransmitting() && (mode==modeCWU || mode==modeCWL)) return 0;
+ if (rx == active_receiver && isTransmitting() && (mode==modeCWU || mode==modeCWL)) {
+ return 0;
+ }
+ g_mutex_lock(&rx->local_audio_mutex);
if (rx->playback_handle != NULL && rx->local_audio_buffer != NULL) {
buffer[rx->local_audio_buffer_offset++] = (left+right)*0.5; // mix to MONO
if (rx->local_audio_buffer_offset == BUFFER_SIZE) {
// do not check on errors, there will be underflows every now and then
}
}
+ g_mutex_unlock(&rx->local_audio_mutex);
return 0;
}
//
// need a buffer for pixels for the spectrum of the feedback
// signal (MON button).
- // NewProtocol: Since we want to display only 48 kHz instead of
- // 192 kHz, we make a spectrum with four times the pixels and then
+ // NewProtocol: Since we want to display only 24 kHz instead of
+ // 192 kHz, we make a spectrum with eight times the pixels and then
// display only the central part.
+ //
+ // Also need a mutex, when changing sample rate
//
+ g_mutex_init(&rx->mutex);
if (protocol == ORIGINAL_PROTOCOL) {
rx->pixels=(sample_rate/24000) * width;
} else {
rx->iq_input_buffer=g_new(double,2*rx->buffer_size);
//rx->audio_buffer=NULL;
rx->audio_sequence=0L;
- rx->pixel_samples=malloc(sizeof(float)*(rx->pixels));
+ rx->pixel_samples=g_new(float,rx->pixels);
rx->samples=0;
rx->displaying=0;
rx->sample_rate=sample_rate;
int scale=rx->sample_rate/48000;
rx->output_samples=rx->buffer_size/scale;
- rx->audio_output_buffer=g_new(gdouble,2*rx->output_samples);
rx->hz_per_pixel=(double)rx->sample_rate/(double)rx->width;
g_print("receiver_change_sample_rate: id=%d rate=%d scale=%d buffer_size=%d output_samples=%d\n",rx->id,sample_rate,scale,rx->buffer_size,rx->output_samples);
#ifdef PURESIGNAL
if (rx->id == PS_RX_FEEDBACK) {
- float *fp, *ofp;
if (protocol == ORIGINAL_PROTOCOL) {
rx->pixels = 2* scale * rx->width;
} else {
// PS feedback receiver is fixed.
rx->pixels = 8 * rx->width;
}
- // make sure pixel_samples is always a valid pointer
- // ... probably pure DL1YCF's paranoia
- fp=malloc(sizeof(float)*rx->pixels);
- ofp=rx->pixel_samples;
- rx->pixel_samples=fp;
- free(ofp);
+ g_free(rx->pixel_samples);
+ rx->pixel_samples=g_new(float,rx->pixels);
init_analyzer(rx);
fprintf(stderr,"PS FEEDBACK change sample rate:id=%d rate=%d buffer_size=%d output_samples=%d\n",
rx->id, rx->sample_rate, rx->buffer_size, rx->output_samples);
return;
}
#endif
+ if (rx->audio_output_buffer != NULL) {
+ g_free(rx->audio_output_buffer);
+ }
+ rx->audio_output_buffer=g_new(gdouble,2*rx->output_samples);
SetChannelState(rx->id,0,1);
init_analyzer(rx);
g_mutex_lock(&rx->mutex);
- // noise blanker works on origianl IQ samples
+ // noise blanker works on original IQ samples
if(rx->nb) {
xanbEXT (rx->id, rx->iq_input_buffer, rx->iq_input_buffer);
}
#ifdef PURESIGNAL
if(tx->puresignal && tx->feedback) {
RECEIVER *rx_feedback=receiver[PS_RX_FEEDBACK];
+ g_mutex_lock(&rx_feedback->mutex);
GetPixels(rx_feedback->id,0,rx_feedback->pixel_samples,&rc);
int full = rx_feedback->pixels; // number of pixels in the feedback spectrum
int width = tx->pixels; // number of pixels to copy from the feedback spectrum
float *rfp=rx_feedback->pixel_samples+start;
// if full == width, then we just copy all samples
memcpy(tfp, rfp, width*sizeof(float));
+ g_mutex_unlock(&rx_feedback->mutex);
} else {
#endif
GetPixels(tx->id,0,tx->pixel_samples,&rc);
#include "new_menu.h"
#include "rigctl.h"
#include "ext.h"
-#include "noise_menu.h"
#ifdef FREEDV
#include "freedv.h"
#endif
active_receiver->snb=mode_settings[m].snb;
// make changes effective
- update_noise();
+ g_idle_add(ext_update_noise, NULL);
switch(id) {
case 0:
receiver_mode_changed(receiver[0]);