diff --git a/dsd.h b/dsd.h index 831bc71..22ef3e9 100644 --- a/dsd.h +++ b/dsd.h @@ -45,10 +45,17 @@ #define SAMPLE_RATE_IN 48000 #define SAMPLE_RATE_OUT 8000 -#define PA_FRAMES_PER_BUFFER 64 #ifdef USE_PORTAUDIO #include "portaudio.h" +#define PA_FRAMES_PER_BUFFER 64 +//Buffer needs to be large enough to prevent input buffer overruns while DSD is doing other struff (like outputting voice) +//else you get skipped samples which result in incomplete/erronous decodes and a mountain of error messages. +#define PA_LATENCY_IN 0.500 +//Buffer needs to be large enough to prevent output buffer underruns while DSD is doing other stuff (like decoding input) +//else you get choppy audio and in 'extreme' cases errors. +//Buffer also needs to be as small as possible so we don't have a lot of audio delay. +#define PA_LATENCY_OUT 0.100 #endif /* diff --git a/dsd_audio.c b/dsd_audio.c index d46fee0..2497919 100644 --- a/dsd_audio.c +++ b/dsd_audio.c @@ -235,8 +235,11 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) //printf("Frames available: %d\n", available); if( err != paNoError ) break; - if(available > SAMPLE_RATE_OUT / 2) + if(available > SAMPLE_RATE_OUT * PA_LATENCY_OUT) { + //It looks like this might not be needed for very small latencies. However, it's definitely needed for a bit larger ones. + //When PA_LATENCY_OUT == 0.500 I get output buffer underruns if I don't use this. With PA_LATENCY_OUT <= 0.100 I don't see those happen. + //But with PA_LATENCY_OUT < 0.100 I run the risk of choppy audio and stream errors. printf("\nSyncing voice output stream\n"); err = Pa_StopStream( opts->audio_out_pa_stream ); if( err != paNoError ) @@ -335,7 +338,7 @@ int getPADevice(char* dev, int input, PaStream** stream) parameters.device = devnum; parameters.channelCount = 1; /* mono */ parameters.sampleFormat = paInt16; //Shorts - parameters.suggestedLatency = 0.500; //0.050; // Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + parameters.suggestedLatency = (input == 1) ? PA_LATENCY_IN : PA_LATENCY_OUT; parameters.hostApiSpecificStreamInfo = NULL; //Open stream diff --git a/dsd_main.c b/dsd_main.c index 9cad25f..fe45a78 100644 --- a/dsd_main.c +++ b/dsd_main.c @@ -98,8 +98,14 @@ initOpts (dsd_opts * opts) opts->scoperate = 15; sprintf (opts->audio_in_dev, "/dev/audio"); opts->audio_in_fd = -1; +#ifdef USE_PORTAUDIO + opts->audio_in_pa_stream = NULL; +#endif sprintf (opts->audio_out_dev, "/dev/audio"); opts->audio_out_fd = -1; +#ifdef USE_PORTAUDIO + opts->audio_out_pa_stream = NULL; +#endif opts->split = 0; opts->playoffset = 0; opts->mbe_out_dir[0] = 0; @@ -364,20 +370,33 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) printf("Terminating portaudio.\n"); PaError err = paNoError; if(opts->audio_in_pa_stream != NULL) - err = Pa_CloseStream( opts->audio_in_pa_stream ); - if( err != paNoError ) { - fprintf( stderr, "An error occured while closing the portaudio input stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + err = Pa_CloseStream( opts->audio_in_pa_stream ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while closing the portaudio input stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + } } if(opts->audio_out_pa_stream != NULL) - err = Pa_CloseStream( opts->audio_out_pa_stream ); - if( err != paNoError ) { - fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + err = Pa_IsStreamActive( opts->audio_out_pa_stream ); + if(err == 1) + err = Pa_StopStream( opts->audio_out_pa_stream ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + } + err = Pa_CloseStream( opts->audio_out_pa_stream ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while closing the portaudio output stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + } } err = Pa_Terminate(); if( err != paNoError )