From c72eca2ad87bf62283b676ebcdd69472f8d8501e Mon Sep 17 00:00:00 2001 From: "Alexander \"Arav\" Andreev" Date: Mon, 25 Mar 2024 01:05:29 +0400 Subject: [PATCH] Made separate streams for in and out sound. WIll be very handy for muting a microphone and your companion. --- src/audio.c | 131 ++++++++++++++++++++++++++++++++++++++++------------ src/audio.h | 10 +++- src/main.c | 30 +++++++++--- 3 files changed, 133 insertions(+), 38 deletions(-) diff --git a/src/audio.c b/src/audio.c index d3bcb82..7da740f 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1,17 +1,52 @@ #include "audio.h" +#include #include #include -int audio_init(audio_t *aud, int channels, int sample_rate, int frame_size) { +int audio_init_soundsystem(void) { PaError pa_err; - int opus_err; if ((pa_err = Pa_Initialize()) != paNoError) { fprintf(stderr, "Cannot initialise PortAudio: %s\n", Pa_GetErrorText(pa_err)); return -1; } + return 0; +} + +int audio_terminate_soundsystem(void) { + PaError pa_err; + + if ((pa_err = Pa_Terminate()) != paNoError) { + fprintf(stderr, "Cannot terminate PortAudio: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + + return 0; +} + +int audio_init_default(audio_t *aud, int channels, int sample_rate, int frame_size) { + PaError pa_err; + int opus_err; + + if ((pa_err = Pa_OpenDefaultStream(&aud->stream_in, channels, 0, AUDIO_SAMPLE_FORMAT, + sample_rate, frame_size, NULL, NULL)) != paNoError) { + fprintf(stderr, "Cannot open an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + + if ((pa_err = Pa_OpenDefaultStream(&aud->stream_out, 0, channels, AUDIO_SAMPLE_FORMAT, + sample_rate, frame_size, NULL, NULL)) != paNoError) { + fprintf(stderr, "Cannot open an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + + aud->buffer_size = frame_size * channels; + aud->buffer = (audio_sample_t *)malloc(aud->buffer_size * sizeof(audio_sample_t)); + if (aud->buffer == NULL) + return -1; + aud->opus_enc = opus_encoder_create(sample_rate, channels, OPUS_APPLICATION_VOIP, &opus_err); if (opus_err != OPUS_OK) { fprintf(stderr, "An Opus encoder cannot be created: %s\n", opus_strerror(opus_err)); @@ -24,44 +59,34 @@ int audio_init(audio_t *aud, int channels, int sample_rate, int frame_size) { return -1; } - if ((pa_err = Pa_OpenDefaultStream(&aud->stream, channels, channels, AUDIO_SAMPLE_FORMAT, - sample_rate, frame_size, NULL, NULL)) != paNoError) { - fprintf(stderr, "Cannot open a PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); - return -1; - } - - aud->buffer_size = frame_size * channels; - aud->buffer = (audio_sample_t *)malloc(aud->buffer_size * sizeof(audio_sample_t)); - if (aud->buffer == NULL) - return -1; - - if ((pa_err = Pa_StartStream(aud->stream)) != paNoError) { - fprintf(stderr, "Cannot start a PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); - free(aud->buffer); - return -1; - } - return 0; } int audio_destroy(audio_t *aud) { PaError pa_err; - if (aud->stream) { - if ((pa_err = Pa_StopStream(aud->stream)) != paNoError) { - fprintf(stderr, "Cannot stop a PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + if (aud->stream_in != NULL) { + if ((pa_err = Pa_StopStream(aud->stream_in)) != paNoError && pa_err != paStreamIsStopped) { + fprintf(stderr, "Cannot stop an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); return -1; } - if ((pa_err = Pa_CloseStream(aud->stream)) != paNoError) { - fprintf(stderr, "Cannot close a PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + if ((pa_err = Pa_CloseStream(aud->stream_in)) != paNoError) { + fprintf(stderr, "Cannot close an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); return -1; } } - if ((pa_err = Pa_Terminate()) != paNoError) { - fprintf(stderr, "Cannot terminate PortAudio: %s\n", Pa_GetErrorText(pa_err)); - return -1; + if (aud->stream_out != NULL) { + if ((pa_err = Pa_StopStream(aud->stream_out)) != paNoError) { + fprintf(stderr, "Cannot stop an output PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + + if ((pa_err = Pa_CloseStream(aud->stream_out)) != paNoError) { + fprintf(stderr, "Cannot close an output PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } } if (aud->buffer) @@ -76,10 +101,58 @@ int audio_destroy(audio_t *aud) { return 0; } +int audio_stream_input_toggle(audio_t *aud) { + PaError pa_err; + + if ((pa_err = Pa_IsStreamStopped(aud->stream_in)) != 0) { + if (pa_err < 0 && pa_err != paStreamIsStopped) { + fprintf(stderr, "Cannot get state of an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + + if ((pa_err = Pa_StartStream(aud->stream_in)) != paNoError) { + fprintf(stderr, "Cannot start an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + free(aud->buffer); + return -1; + } + } else { + if ((pa_err = Pa_StopStream(aud->stream_in)) != paNoError) { + fprintf(stderr, "Cannot stop an input PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + } + + return 0; +} + +int audio_stream_output_toggle(audio_t *aud) { + PaError pa_err; + + if ((pa_err = Pa_IsStreamStopped(aud->stream_out)) != 0) { + if (pa_err < 0) { + fprintf(stderr, "Cannot get state of an output PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + + if ((pa_err = Pa_StartStream(aud->stream_out)) != paNoError) { + fprintf(stderr, "Cannot start an output PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + free(aud->buffer); + return -1; + } + } else { + if ((pa_err = Pa_StopStream(aud->stream_out)) != paNoError) { + fprintf(stderr, "Cannot stop an output PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); + return -1; + } + } + + return 0; +} + int audio_read(audio_t *aud, unsigned char *output, int output_len) { PaError pa_err; - if ((pa_err = Pa_ReadStream(aud->stream, aud->buffer, aud->buffer_size)) != paNoError) { + if ((pa_err = Pa_ReadStream(aud->stream_in, aud->buffer, aud->buffer_size)) != paNoError) { fprintf(stderr, "Cannot read from a PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); return -1; } @@ -102,7 +175,7 @@ int audio_write(audio_t *aud, const unsigned char *input, int input_len) { return -1; } - if ((pa_err = Pa_WriteStream(aud->stream, aud->buffer, aud->buffer_size)) != paNoError) { + if ((pa_err = Pa_WriteStream(aud->stream_out, aud->buffer, aud->buffer_size)) != paNoError) { fprintf(stderr, "Cannot write to a PortAudio stream: %s\n", Pa_GetErrorText(pa_err)); return -1; } diff --git a/src/audio.h b/src/audio.h index ee1c1eb..f3a34c3 100644 --- a/src/audio.h +++ b/src/audio.h @@ -7,8 +7,11 @@ #define AUDIO_SAMPLE_FORMAT paFloat32 typedef float audio_sample_t; +int audio_init_soundsystem(void); +int audio_terminate_soundsystem(void); + typedef struct audio_t { - PaStream *stream; + PaStream *stream_in, *stream_out; OpusEncoder *opus_enc; OpusDecoder *opus_dec; @@ -16,9 +19,12 @@ typedef struct audio_t { int buffer_size; } audio_t; -int audio_init(audio_t *aud, int channels, int sample_rate, int frame_size); +int audio_init_default(audio_t *aud, int channels, int sample_rate, int frame_size); int audio_destroy(audio_t *aud); +int audio_stream_input_toggle(audio_t *aud); +int audio_stream_output_toggle(audio_t *aud); + int audio_read(audio_t *aud, unsigned char *output, int output_len); int audio_write(audio_t *aud, const unsigned char *input, int input_len); diff --git a/src/main.c b/src/main.c index 6d7a802..26924db 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,4 @@ +#include #include #include @@ -7,7 +8,7 @@ #define CHANNELS 1 #define SAMPLE_RATE 48000 -#define FRAMES_PER_BUFFFER 480 +#define FRAMES_PER_BUFFFER 960 #define BUF_SIZE (FRAMES_PER_BUFFFER * CHANNELS) @@ -109,31 +110,43 @@ int main(int argc, char **argv) { goto cleanup; } + if (audio_init_soundsystem() == -1) { + rt = -1; + goto cleanup; + } audio_t aud; unsigned char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); - audio_init(&aud, CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFFER); + audio_init_default(&aud, CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFFER); + + if (audio_stream_input_toggle(&aud) == -1) { + rt = -1; + goto cleanup; + } + + if (audio_stream_output_toggle(&aud) == -1) { + rt = -1; + goto cleanup; + } unsigned char *c = NULL, *m = NULL; unsigned long long cl = 0, ml = 0; printf("Listening... "); - for (int i = 0; i < (20 * SAMPLE_RATE)/FRAMES_PER_BUFFFER; ++i) { + for (int i = 0; i < (10 * SAMPLE_RATE)/FRAMES_PER_BUFFFER; ++i) { audio_read(&aud, buf, BUF_SIZE); c = crypt_session_encrypt(&os, buf, BUF_SIZE, &cl); - int sc = net_send(&nc, (const char *)c, cl); - int rc = net_recv(&ns, c, cl); - fprintf(stderr, "%d %d\n", sc, rc); + net_send(&nc, (const char *)c, cl); + net_recv(&ns, c, cl); m = crypt_session_decrypt(&rs, c, cl, &ml); audio_write(&aud, m, ml); free(c); free(m); } printf("Done!\n"); - audio_destroy(&aud); cleanup: free(oh); @@ -154,5 +167,8 @@ cleanup: net_destroy(&ns); net_destroy(&nc); + audio_destroy(&aud); + audio_terminate_soundsystem(); + return rt; }