aboutsummaryrefslogtreecommitdiff
path: root/src/audio.c
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2022-10-22 23:53:29 +0300
committerkartofen <mladenovnasko0@gmail.com>2022-10-22 23:53:29 +0300
commitf45b143dcf90970122436d10bd6226f577a9310d (patch)
tree986563759bf1f5935e15a66613e673e445b26e97 /src/audio.c
parentf4c66a4c77e5818ca9703f59a80ea92e27ed45c6 (diff)
works with alsa and runs at 30 fpsHEADmaster
Diffstat (limited to 'src/audio.c')
-rw-r--r--src/audio.c143
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(&params); // 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);
}