diff options
author | kartofen <mladenovnasko0@gmail.com> | 2022-10-22 23:53:29 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2022-10-22 23:53:29 +0300 |
commit | f45b143dcf90970122436d10bd6226f577a9310d (patch) | |
tree | 986563759bf1f5935e15a66613e673e445b26e97 /src/audio.c | |
parent | f4c66a4c77e5818ca9703f59a80ea92e27ed45c6 (diff) |
Diffstat (limited to 'src/audio.c')
-rw-r--r-- | src/audio.c | 143 |
1 files changed, 79 insertions, 64 deletions
diff --git a/src/audio.c b/src/audio.c index 710c10c..d9bf3da 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1,90 +1,105 @@ -// TODO: Rewrite with alsa, fuck pulseaudio - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> - -#include <pulse/simple.h> -#include <pulse/error.h> +#define ALSA_PCM_NEW_HW_PARAMS_API +#include <alsa/asoundlib.h> #include "audio.h" #include "typedef.h" -static const pa_sample_spec ss = { - .format = PA_SAMPLE_S16BE, - .rate = 44100, - .channels = 2 -}; +#define TEMP_BUF_SZ (handle->frames * CHANNELS * 2) +#define HANDLE (*(snd_pcm_t**)(handle->h)) -static pa_simple *play = NULL; -static pa_simple *rec = NULL; +#define MIN(a,b) (((a)<(b))?(a):(b)) -int audio_play(char *buf) +int audio_create(audio_handle *handle, audio_handle_types t) { - int ret = 1; - int error; - - if(play == NULL) { - if (!(play = pa_simple_new(NULL, __FILE__, PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); - goto finish; - } + handle->h = malloc(sizeof(snd_pcm_t *)); + snd_pcm_stream_t type = (t == RECORD) ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK; + int rc = snd_pcm_open(handle->h, "default", type, 0); + if (rc < 0) { + err("unable to open pcm device: %s\n", snd_strerror(rc)); + return 1; } - if(pa_simple_flush(play, &error) < 0) - { - fprintf(stderr, __FILE__": pa_simple_flush() failed: %s\n", pa_strerror(error)); - goto finish; - } + int dir; + snd_pcm_hw_params_t *params; - if(pa_simple_write(play, buf, REC_CAP, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); - goto finish; - } + snd_pcm_hw_params_alloca(¶ms); // allocate params + snd_pcm_hw_params_any(HANDLE, params); // set params + snd_pcm_hw_params_set_access(HANDLE, params, SND_PCM_ACCESS_RW_INTERLEAVED); // interleaved mode + snd_pcm_hw_params_set_format(HANDLE, params, SND_PCM_FORMAT_S16_LE); - if(pa_simple_drain(play, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); - goto finish; - } + snd_pcm_hw_params_set_channels(HANDLE, params, CHANNELS); - ret = 0; + unsigned int samp_rate = SAMPLING_RATE; + snd_pcm_hw_params_set_rate_near(HANDLE, params, &samp_rate, &dir); -finish: + snd_pcm_uframes_t frames = FRAMES; + snd_pcm_hw_params_set_period_size_near(HANDLE, params, &frames, &dir); - // if (play) - // pa_simple_free(play); + rc = snd_pcm_hw_params(HANDLE, params); // write params to handle + if (rc < 0) { + err("unable to set hw parameters: %s\n", snd_strerror(rc)); + return 1; + } - return ret; + snd_pcm_hw_params_get_period_size(params, &frames, &dir); + handle->frames = frames; + + return 0; } -int audio_record(char *buf) +int audio_play(audio_handle *handle, char *buf) { - int ret = 1; - int error; - - if(!rec) { - if (!(rec = pa_simple_new(NULL, __FILE__, PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); - goto finish; + char t[TEMP_BUF_SZ]; + for(int i = 0; ;) + { + if(i >= REC_CAP) break;; + + memset(t, 0, TEMP_BUF_SZ); + memcpy(t, &(buf[i]), MIN(TEMP_BUF_SZ, REC_CAP - i)); + + int rc = snd_pcm_writei(HANDLE, t, FRAMES); + if (rc == -EPIPE) { + err("underrun occurred\n"); + snd_pcm_prepare(HANDLE); + } else if (rc < 0) { + err("error from writei: %s\n", snd_strerror(rc)); + } else if (rc != FRAMES) { + err("short write, write %d frames\n", rc); } - } - if(pa_simple_flush(rec, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_flush() failed: %s\n", pa_strerror(error)); - goto finish; + i += TEMP_BUF_SZ; } + return 0; +} - if (pa_simple_read(rec, buf, REC_CAP, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); - goto finish; - } +int audio_record(audio_handle *handle, char *buf) +{ + char t[TEMP_BUF_SZ]; + for(int i = 0; ;) + { + if(i >= REC_CAP) break; + memset(t, 0, TEMP_BUF_SZ); + + int rc = snd_pcm_readi(HANDLE, t, FRAMES); + if (rc == -EPIPE) { + err("overrun occurred\n"); + snd_pcm_prepare(HANDLE); + } else if (rc < 0) { + err("error from read: %s\n", snd_strerror(rc)); + } else if (rc != FRAMES) { + err("short read, read %d frames\n", rc); + } - ret = 0; + memcpy(&(buf[i]), t, MIN(TEMP_BUF_SZ, REC_CAP - i)); + i += TEMP_BUF_SZ; + } -finish: - // if(rec) - // pa_simple_free(rec); + return 0; +} - return ret; +void audio_destroy(audio_handle *handle) +{ + snd_pcm_drain(HANDLE); + snd_pcm_close(HANDLE); + free(handle->h); } |