From 50d707a8e3886b36fef0afec9c49b29b37864a73 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Fri, 28 Jul 2023 16:06:58 -0400 Subject: [PATCH] Rewrite OSS Handling (depending on use case); --- src/dsd_audio.c | 6 +- src/dsd_audio2.c | 8 +- src/dsd_main.c | 186 ++++++++++++++++++++++++++++++---------------- src/dsd_mbe.c | 70 ++++++++--------- src/dsd_ncurses.c | 25 ++----- src/nxdn_voice.c | 2 +- 6 files changed, 170 insertions(+), 127 deletions(-) diff --git a/src/dsd_audio.c b/src/dsd_audio.c index d94a68f..46fa644 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -460,7 +460,7 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) { if (opts->audio_out_type == 5) //OSS { - //OSS + //OSS 48k/1 result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); state->audio_out_idx = 0; } @@ -496,8 +496,8 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) // output synthesized speech to sound card if (opts->audio_out_type == 5) //OSS { - //OSS - result = write (opts->audio_out_fdR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2)); + //OSS 48k/1 + result = write (opts->audio_out_fd, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2)); state->audio_out_idxR = 0; } else if (opts->audio_out_type == 0) diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c index b6b8cbb..199f131 100644 --- a/src/dsd_audio2.c +++ b/src/dsd_audio2.c @@ -903,7 +903,7 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state) if (opts->audio_out_type == 0) //Pulse Audio pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2, NULL); - if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2 write (opts->audio_out_fd, stereo_samp1, 320*2); @@ -1042,7 +1042,7 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) } - if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel { write (opts->audio_out_fd, stereo_samp1, 320*2); write (opts->audio_out_fd, stereo_samp2, 320*2); @@ -1192,11 +1192,11 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) } - if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel { write (opts->audio_out_fd, stereo_samp1, 320*2); write (opts->audio_out_fd, stereo_samp2, 320*2); - //only play these two if not a single 2v or double 2v (minor skip can still occur on a 4v and 2v combo, but will probably only be perceivable if one is a tone) + //only play these two if not a single 2v or double 2v if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) write (opts->audio_out_fd, stereo_samp3, 320*2); if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) diff --git a/src/dsd_main.c b/src/dsd_main.c index bdda14f..60f7509 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -2594,22 +2594,39 @@ main (int argc, char **argv) #endif } + //moved these to be checked prior to checking OSS for the split for 1-48k, or variable configurations + if((strncmp(opts.audio_in_dev, "pulse", 5) == 0)) + { + opts.audio_in_type = 0; + } + + if((strncmp(opts.audio_out_dev, "pulse", 5) == 0)) + { + opts.audio_out_type = 0; + } + + if((strncmp(opts.audio_out_dev, "null", 4) == 0)) + { + opts.audio_out_type = 9; //9 for NULL, or mute output + opts.audio_out = 0; //turn off so we won't playSynthesized + } + + if((strncmp(opts.audio_out_dev, "-", 1) == 0)) + { + opts.audio_out_fd = fileno(stdout); //STDOUT_FILENO; + opts.audio_out_type = 1; //using 1 for stdout to match input stdin as 1 + fprintf(stderr, "Audio Out Device: -\n"); + } + int fmt; int speed; //The long of the short is that PADSP can open multiple virtual /dev/dsp devices each with different sampling rates and channel configurations //but the instance inside of Cygwin is a single instance tied to one sample rate AND one channel configuration, so if you change it on the output, it - //also changes on the input, and the way dsd handles this is to upsample output to make it work correctly, so if we were to make a true short stereo mix, - //we would have to handle upsampling for it as well in Cygwin (alternatively, find another output method, like RTAudio, or something else) + //also changes on the input, and the way dsd handles this is to upsample output to make it work correctly, so in order to be able to change the output + //to a variable config, it cannot be the input as well - //It should be noted that Pulse Audio instances do not have this same issue, and can run at different input/rate and output/rate/channel configurations - //TL:DR; the only reason /dev/dsp works as both input and output in Cygwin is because both input and output are exactly 1 channel - 48k - - //TODO: Test opening OSS input as 2-channel 48k, and see if we can read it in, if not, then double samplespersymble and center - //doing so will break the filters though - - speed = 48000; if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0)) { sprintf (opts.audio_in_dev, "%s", "/dev/dsp"); @@ -2622,6 +2639,7 @@ main (int argc, char **argv) fprintf (stderr, "Switching to /dev/dsp.\n"); } + speed = 48000; //hardset to 48000 if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0)) { fprintf (stderr, "OSS Input %s.\n", opts.audio_in_dev); @@ -2668,72 +2686,108 @@ main (int argc, char **argv) fprintf (stderr, "Switching to /dev/dsp.\n"); } - if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0)) + if (opts.audio_in_type == 5) //if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0)) or 'split' == 0 { - fprintf (stderr, "OSS Output %s.\n", opts.audio_out_dev); - opts.audio_out_fd = open (opts.audio_out_dev, O_RDWR); - if (opts.audio_out_fd == -1) + + if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0)) { - fprintf (stderr, "Error, couldn't open #1 %s\n", opts.audio_out_dev); - opts.audio_out = 0; - exit(1); + fprintf (stderr, "OSS Output %s.\n", opts.audio_out_dev); + opts.audio_out_fd = open (opts.audio_out_dev, O_RDWR); + if (opts.audio_out_fd == -1) + { + fprintf (stderr, "Error, couldn't open #1 %s\n", opts.audio_out_dev); + opts.audio_out = 0; + exit(1); + } + + fmt = 0; + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_RESET) < 0) + { + fprintf (stderr, "ioctl reset error \n"); + } + + fmt = speed; + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) + { + fprintf (stderr, "ioctl speed error \n"); + } + + fmt = 0; //this seems okay to be 1 or 0, not sure what the difference really is (works in stereo on 0) + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) + { + fprintf (stderr, "ioctl stereo error \n"); + } + + fmt = AFMT_S16_LE; + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + { + fprintf (stderr, "ioctl setfmt error \n"); + } + + opts.audio_out_type = 5; //5 for 1 channel - 48k OSS 16-bit short output (matching with input) + opts.pulse_digi_rate_out = 48000; //this is used to force to upsample + opts.pulse_digi_out_channels = 1; + opts.audio_gain = 0; } - - fmt = 0; - if (ioctl (opts.audio_out_fd, SNDCTL_DSP_RESET) < 0) - { - fprintf (stderr, "ioctl reset error \n"); - } - - fmt = speed; - if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) - { - fprintf (stderr, "ioctl speed error \n"); - } - - fmt = 0; //this seems okay to be 1 or 0, not sure what the difference really is (works in stereo on 0) - if (ioctl (opts.audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) - { - fprintf (stderr, "ioctl stereo error \n"); - } - - fmt = AFMT_S16_LE; - if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) - { - fprintf (stderr, "ioctl setfmt error \n"); - } - - //setup for one or two-channel configuration -- OSS -- cygwin OSS does not like this at all, even when set to 1 - // fmt = opts.pulse_digi_out_channels; //number of channels is also be a problem for Cygwin... - // if (ioctl (opts.audio_out_fd, SNDCTL_DSP_CHANNELS, &fmt) < 0) - // { - // fprintf (stderr, "ioctl channels error \n"); - // } - - opts.audio_out_type = 5; //5 will become OSS output type } - if((strncmp(opts.audio_in_dev, "pulse", 5) == 0)) + if (opts.audio_in_type != 5) //split == 1 { - opts.audio_in_type = 0; - } - if((strncmp(opts.audio_out_dev, "pulse", 5) == 0)) - { - opts.audio_out_type = 0; - } + if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0)) + { + fprintf (stderr, "OSS Output %s.\n", opts.audio_out_dev); + opts.audio_out_fd = open (opts.audio_out_dev, O_WRONLY); + if (opts.audio_out_fd == -1) + { + fprintf (stderr, "Error, couldn't open %s\n", opts.audio_out_dev); + opts.audio_out = 0; + exit(1); + } - if((strncmp(opts.audio_out_dev, "null", 4) == 0)) - { - opts.audio_out_type = 9; //9 for NULL, or mute output - opts.audio_out = 0; //turn off so we won't playSynthesized - } + //Setup the device. Note that it's important to set the sample format, number of channels and sample rate exactly in this order. Some devices depend on the order. - if((strncmp(opts.audio_out_dev, "-", 1) == 0)) - { - opts.audio_out_fd = fileno(stdout); //STDOUT_FILENO; - opts.audio_out_type = 1; //using 1 for stdout to match input stdin as 1 - fprintf(stderr, "Audio Out Device: -\n"); + fmt = 0; + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_RESET) < 0) + { + fprintf (stderr, "ioctl reset error \n"); + } + + fmt = AFMT_S16_LE; //Sample Format + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + { + fprintf (stderr, "ioctl setfmt error \n"); + } + + fmt = opts.pulse_digi_out_channels; //number of channels //was 2 + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_CHANNELS, &fmt) < 0) + { + fprintf (stderr, "ioctl channel error \n"); + } + + speed = opts.pulse_digi_rate_out; //since we have split input/output, we want 2-channel/8k //8000 -- mirror pulse rate instead + fmt = speed; //output rate + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) + { + fprintf (stderr, "ioctl speed error \n"); + } + if (opts.pulse_digi_out_channels == 2) + fmt = 1; + else fmt = 0; + + if (ioctl (opts.audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) + { + fprintf (stderr, "ioctl stereo error \n"); + } + + //TODO: Multiple output returns based on 8k/1, 8k/2, or maybe 48k/1? (2,3,5)?? + if (opts.pulse_digi_out_channels == 2) + opts.audio_out_type = 2; //2 for 2 channel 8k OSS 16-bit short output + else opts.audio_out_type = 5; + + //debug + fprintf (stderr, "Using OSS Output with %dk/%d channel configuration.\n", opts.pulse_digi_rate_out, opts.pulse_digi_out_channels); + } } if (opts.playfiles == 1) //redo? diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index aa653d3..8baa25c 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -245,8 +245,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } } - //set flag to not play audio this time, but won't prevent writing to wav files - if (strcmp(mode, "B") == 0) opts->audio_out = 0; + //set flag to not play audio this time, but won't prevent writing to wav files -- disabled for now + // if (strcmp(mode, "B") == 0) opts->audio_out = 0; //causes a buzzing now (probably due to not running processAudio before the SS3 or SS4) //end set playback mode for this frame @@ -1058,30 +1058,29 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } //end reverse mute test - //No more Slot Pre-emption...ever - // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - // //OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other - // if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) ) - // { - // opts->audio_out = 0; - // preempt = 1; - // if (opts->payload == 0) - // fprintf (stderr, " *MUTED*"); - // } - // #endif + //OSS 48k/1 Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other + if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) ) + { + opts->audio_out = 0; + preempt = 1; + if (opts->payload == 0 && opts->slot1_on == 1) + fprintf (stderr, " *MUTED*"); + else if (opts->payload == 0 && opts->slot1_on == 0) + fprintf (stderr, " *OFF*"); + } state->debug_audio_errors += state->errs2 + state->errs; if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) { - if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000 + if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->slot1_on == 1 { processAudio(opts, state); } - // if (opts->audio_out == 1) - // { - // playSynthesizedVoice (opts, state); - // } + if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot1_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible + { + playSynthesizedVoice (opts, state); //it may be more beneficial to move this to each individual decoding type to handle, but ultimately, let's just simpifly mbe handling instead + } } memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); //these are for mono or FDMA where we don't need to buffer and wait for a stereo mix @@ -1134,29 +1133,29 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } //end reverse mute test - // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - // //OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other - // if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) ) - // { - // opts->audio_out = 0; - // preempt = 1; - // if (opts->payload == 0) - // fprintf (stderr, " *MUTED*"); - // } - // #endif + //OSS 48k/1 Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other + if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) ) + { + opts->audio_out = 0; + preempt = 1; + if (opts->payload == 0 && opts->slot2_on == 1) + fprintf (stderr, " *MUTED*"); + else if (opts->payload == 0 && opts->slot2_on == 0) + fprintf (stderr, " *OFF*"); + } state->debug_audio_errorsR += state->errs2R + state->errsR; if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) { - if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000 + if (opts->audio_out == 1 && opts->floating_point == 0) //&& opts->slot2_on == 1 { processAudioR(opts, state); } - // if (opts->audio_out == 1) - // { - // playSynthesizedVoiceR (opts, state); - // } + if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot2_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible + { + playSynthesizedVoiceR (opts, state); + } } memcpy (state->f_r, state->audio_out_temp_bufR, sizeof(state->f_r)); @@ -1215,8 +1214,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a preempt = 0; } - //reset audio out flag for next repitition - if (strcmp(mode, "B") == 0) opts->audio_out = 1; + //reset audio out flag for next repitition --disabled for now + // if (strcmp(mode, "B") == 0) opts->audio_out = 1; + //restore flag for null output type if (opts->audio_out_type == 9) opts->audio_out = 0; } diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index ada3670..b2ba585 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -2320,9 +2320,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw (" \n"); } - if (opts->audio_out_type == 5) + if (opts->audio_out_type == 5 || opts->audio_out_type == 2) { - printw ("| Pulse Audio Output: %i kHz; %i Channel; G: %.1f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); + printw ("| OSS Audio Output: %i kHz; %i Channel; G: %.1f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); if (opts->pulse_digi_out_channels == 2) printw (" G: %.1f%%", state->aout_gainR*2); if (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //nly on short if (opts->floating_point == 1) printw (" Floating Point;"); @@ -2839,17 +2839,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } - //REMUS! THIS IS THE OLD ONE - // printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fid, state->dmr_so); - //This is the new one printw ("%s | ", state->call_string[0]); printw ("%s ", DMRBusrtTypes[state->dmrburstL]); - // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - // // - // if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21)) printw ("*M*"); - // // - // #endif + if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21)) printw ("*M*"); + printw ("\n"); @@ -3043,16 +3037,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } - //REMUS! THIS IS THE OLD ONE - // printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fidR, state->dmr_soR); - //THIS IS THE NEW ONE printw ("%s | ", state->call_string[1]); printw ("%s ", DMRBusrtTypes[state->dmrburstR]); - // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - // // - // if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*"); - // // - // #endif + + if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*"); + printw ("\n"); printw ("| V XTRA | "); //10 spaces diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c index 5041dbf..927ff65 100644 --- a/src/nxdn_voice.c +++ b/src/nxdn_voice.c @@ -92,7 +92,7 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182 memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); - if (opts->floating_point == 0) + if (opts->floating_point == 0 ) playSynthesizedVoice(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state);