From cb5d1a5ad764ab54b68ad5de4097a4ee3be5c606 Mon Sep 17 00:00:00 2001 From: c vw Date: Fri, 17 May 2019 13:36:51 +0200 Subject: [PATCH] a) added LINUX ALSA sound output to hpsdrsim b) wait for WDSP on TX/RX transitions --- Makefile | 4 +- hpsdrsim.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++-- radio.c | 20 +++++ 3 files changed, 235 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 9070658..a6a0f1d 100644 --- a/Makefile +++ b/Makefile @@ -455,7 +455,7 @@ release: $(PROGRAM) ############################################################################# hpsdrsim.o: hpsdrsim.c - $(CC) -c -O -DPORTAUDIO hpsdrsim.c + $(CC) -c -O hpsdrsim.c hpsdrsim: hpsdrsim.o - $(LINK) -o hpsdrsim hpsdrsim.o -lm -lpthread -lportaudio + $(LINK) -o hpsdrsim hpsdrsim.o $(AUDIO_LIBS) -lm -lpthread diff --git a/hpsdrsim.c b/hpsdrsim.c index 667db75..31e6903 100644 --- a/hpsdrsim.c +++ b/hpsdrsim.c @@ -50,12 +50,17 @@ #include #include #include + #ifdef PORTAUDIO #include "portaudio.h" +#else +#include +#endif + +// Forward declarations for the audio functions void audio_get_cards(void); void audio_open_output(); void audio_write(short, short); -#endif #ifndef __APPLE__ @@ -199,10 +204,8 @@ int main(int argc, char *argv[]) int bytes_read, bytes_left; uint32_t *code0 = (uint32_t *) buffer; // fast access to code of first buffer -#ifdef PORTAUDIO audio_get_cards(); audio_open_output(); -#endif /* * Examples for METIS: Mercury/Penelope boards * Examples for HERMES: ANAN10, ANAN100 @@ -430,16 +433,12 @@ int main(int argc, char *argv[]) double disample,dqsample,idelta,qdelta; bp=buffer+16; // skip 8 header and 8 SYNC/C&C bytes for (j=0; j<126; j++) { -#ifdef PORTAUDIO // write audio samples r = (int)((signed char) *bp++)<<8; r |= (int)((signed char) *bp++ & 0xFF); l = (int)((signed char) *bp++)<<8; l |= (int)((signed char) *bp++ & 0xFF); audio_write(r,l); -#else - bp += 4; -#endif sample = (int)((signed char) *bp++)<<8; sample |= (int) ((signed char) *bp++ & 0xFF); disample=(double) sample / 32768.0; @@ -1174,4 +1173,211 @@ void audio_write (short l, short r) } } +#else +// +// Audio functions based on LINUX ALSA +// + +static snd_pcm_t *playback_handle = NULL; +static unsigned char playback_buffer[1024]; // 256 samples, left-and-right, two bytes per sample +static int playback_offset; + +static char *device_id = NULL; + +void audio_get_cards() { + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + int i; + int card = -1; + + + while (snd_card_next(&card) >= 0 && card >= 0) { + int err = 0; + snd_ctl_t *handle; + char name[20]; + snprintf(name, sizeof(name), "hw:%d", card); + if ((err = snd_ctl_open(&handle, name, 0)) < 0) { + continue; + } + + if ((err = snd_ctl_card_info(handle, info)) < 0) { + snd_ctl_close(handle); + continue; + } + + int dev = -1; + + while (snd_ctl_pcm_next_device(handle, &dev) >= 0 && dev >= 0 && device_id == NULL) { + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + + // ouput devices + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); + if ((err = snd_ctl_pcm_info(handle, pcminfo)) == 0) { + device_id=malloc(64); + snprintf(device_id, 64, "plughw:%d,%d %s", card, dev, snd_ctl_card_info_get_name(info)); + fprintf(stderr,"ALSA output_device: %s\n",device_id); + } + } + + snd_ctl_close(handle); + + } + + if (device_id != NULL) return; // found one + + // look for dmix + void **hints, **n; + char *name, *descr, *io; + + if (snd_device_name_hint(-1, "pcm", &hints) < 0) + return; + n = hints; + while (*n != NULL && device_id == NULL) { + name = snd_device_name_get_hint(*n, "NAME"); + descr = snd_device_name_get_hint(*n, "DESC"); + io = snd_device_name_get_hint(*n, "IOID"); + + if(strncmp("dmix:", name, 5)==0/* || strncmp("pulse", name, 5)==0*/) { + fprintf(stderr,"name=%s descr=%s io=%s\n",name, descr, io); + device_id=malloc(64); + + snprintf(device_id, 64, "%s", name); + fprintf(stderr,"ALSA output_device: %s\n",device_id); + } + + if (name != NULL) + free(name); + if (descr != NULL) + free(descr); + if (io != NULL) + free(io); + n++; + } + snd_device_name_free_hint(hints); +} + + +void audio_open_output() { + int err; + snd_pcm_hw_params_t *hw_params; + int rate=48000; + int dir=0; + + int i; + char hw[64]; + char *selected=device_id; + + i=0; + while(selected[i]!=' ') { + hw[i]=selected[i]; + i++; + } + hw[i]='\0'; + + if ((err = snd_pcm_open (&playback_handle, hw, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + fprintf (stderr, "audio_open_output: cannot open audio device %s (%s)\n", + hw, + snd_strerror (err)); + playback_handle = NULL; + return; + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "audio_open_output: cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) { + fprintf (stderr, "audio_open_output: cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "audio_open_output: cannot set access type (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "audio_open_output: cannot set sample format (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + + if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &rate, &dir)) < 0) { + fprintf (stderr, "audio_open_output: cannot set sample rate (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) { + fprintf (stderr, "audio_open_output: cannot set channel count (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) { + fprintf (stderr, "audio_open_output: cannot set parameters (%s)\n", + snd_strerror (err)); + playback_handle=NULL; + return; + } + + snd_pcm_hw_params_free (hw_params); + + playback_offset=0; + + return; +} + +void audio_write(short left_sample,short right_sample) { + snd_pcm_sframes_t delay; + int error; + long trim; + + if(playback_handle!=NULL) { + playback_buffer[playback_offset++]=right_sample; + playback_buffer[playback_offset++]=right_sample>>8; + playback_buffer[playback_offset++]=left_sample; + playback_buffer[playback_offset++]=left_sample>>8; + + if(playback_offset==1024) { + trim=0; + + if(snd_pcm_delay(playback_handle,&delay)==0) { + if(delay>2048) { + trim=delay-2048; + } + } + + if ((error = snd_pcm_writei (playback_handle, playback_buffer, 256-trim)) != 256-trim) { + if(error==-EPIPE) { + if ((error = snd_pcm_prepare (playback_handle)) < 0) { + fprintf (stderr, "audio_write: cannot prepare audio interface for use (%s)\n", + snd_strerror (error)); + return; + } + if ((error = snd_pcm_writei (playback_handle, playback_buffer, 256-trim)) != 256) { + fprintf (stderr, "audio_write: write to audio interface failed (%s)\n", + snd_strerror (error)); + return; + } + } + } + playback_offset=0; + } + } +} #endif diff --git a/radio.c b/radio.c index 983cfbf..850e271 100644 --- a/radio.c +++ b/radio.c @@ -727,7 +727,17 @@ static void rxtx(int state) { #endif for(i=0;iid,0,1); +#else + // Original code: wait for WDSP only for the last RX SetChannelState(receiver[i]->id,0,i==(receivers-1)); +#endif set_displaying(receiver[i],0); if(protocol==NEW_PROTOCOL) { schedule_high_priority(); @@ -839,7 +849,17 @@ void setTune(int state) { } if(state) { for(i=0;iid,0,1); +#else + // wait only for the last RX SetChannelState(receiver[i]->id,0,i==(receivers-1)); +#endif set_displaying(receiver[i],0); if(protocol==NEW_PROTOCOL) { schedule_high_priority(); -- 2.45.2