libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
audio.c
1#include <clod/audio.h>
2#include "config.h"
3#include "debug.h"
4
5#if CLOD_USE_ALSA
6#include <alsa/asoundlib.h>
7
8int clod_audio_read(clod_stream *self, struct clod_string *dst) {
9 if (dst->cap <= 0) return CLOD_STREAM_INVALID;
10 if (dst->len >= dst->cap) return CLOD_STREAM_INVALID;
11
12again:
13 int64_t n = snd_pcm_readi((void*)self->impl, dst->ptr + dst->len, (size_t)(dst->cap - dst->len) / sizeof(float));
14 if (n < 0 && n != -EAGAIN) {
15 debug(CLOD_DEBUG, "Audio read error: %s", snd_strerror((int)n));
16 n = snd_pcm_recover((void*)self->impl, (int)n, 0);
17 if (n < 0) {
18 return -(int)n;
19 }
20
21 goto again;
22 }
23
24 dst->len += n * (ptrdiff_t)sizeof(float);
25 return CLOD_STREAM_OK;
26}
27int clod_audio_write(clod_stream *self, struct clod_string *src) {
28 if (src->len < 0) return CLOD_STREAM_INVALID;
29
30again:
31 int64_t n = snd_pcm_writei((void*)self->impl, src->ptr, (size_t)(src->len) / sizeof(float));
32 if (n < 0 && n != -EAGAIN) {
33 debug(CLOD_DEBUG, "Audio write error: %s", snd_strerror((int)n));
34 n = snd_pcm_recover((void*)self->impl, (int)n, 0);
35 if (n < 0) {
36 return -(int)n;
37 }
38
39 goto again;
40 }
41
42 src->ptr += n * (ptrdiff_t)sizeof(float);
43 src->len -= n * (ptrdiff_t)sizeof(float);
44 return CLOD_STREAM_OK;
45}
46int clod_audio_close(clod_stream *self) {
47 int res = CLOD_STREAM_OK;
48
49 if ((snd_pcm_t*)(void*)self->impl) {
50 snd_pcm_drain((void*)self->impl);
51 res = snd_pcm_close((void*)self->impl);
52 if (res != 0) debug(CLOD_DEBUG, "Audio stream close error: %s", snd_strerror(res));
53 }
54
55 return CLOD_STREAM_OK;
56}
57int clod_audio(clod_stream *stream_out, int flags) {
58 if (flags & CLOD_AUDIO_IN && flags & CLOD_AUDIO_OUT) {
59 debug(CLOD_DEBUG, "A single audio stream cannot be both input and output.");
60 return CLOD_STREAM_INVALID;
61 }
62
63 int res;
64 #define check_error(expr) if((res = (expr)) < 0) {\
65 debug(CLOD_DEBUG, "Failed to initialise audio. "#expr" returned %i: %s.", res, snd_strerror(res));\
66 goto error;\
67 };
68
69 snd_pcm_t *pcm;
70 check_error(snd_pcm_open(
71 &pcm,
72 "default",
73 flags & CLOD_AUDIO_IN ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
74 0
75 ));
76
77 snd_pcm_hw_params_t *hw_params;
78 snd_pcm_hw_params_alloca(&hw_params);
79 check_error(snd_pcm_hw_params_any(pcm, hw_params));
80 check_error(snd_pcm_hw_params_set_access(pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
81 check_error(snd_pcm_hw_params_set_format(pcm, hw_params, SND_PCM_FORMAT_FLOAT));
82 check_error(snd_pcm_hw_params_set_channels(pcm, hw_params, 1));
83 check_error(snd_pcm_hw_params_set_rate(pcm, hw_params, 48000, 0));
84
85 check_error(snd_pcm_hw_params(pcm, hw_params));
86 check_error(snd_pcm_prepare(pcm));
87
88 if (flags & CLOD_AUDIO_IN) {
89 stream_out->impl = (uintptr_t)(void*)pcm;
90 stream_out->read = clod_audio_read;
91 stream_out->write = nullptr;
92 stream_out->close = clod_audio_close;
93 } else {
94 stream_out->impl = (uintptr_t)(void*)pcm;
95 stream_out->read = nullptr;
96 stream_out->write = clod_audio_write;
97 stream_out->close = clod_audio_close;
98 }
99 return 0;
100
101 #undef check_error
102error:
103 if (pcm) snd_pcm_close(pcm);
104 return -res;
105}
106#else
107int clod_audio(clod_stream *, int) {
108 return CLOD_STREAM_INVALID;
109}
110#endif
int(* write)(clod_stream *self, struct clod_string *src)
Definition stream.h:88
uintptr_t impl
Definition stream.h:59
int(* read)(clod_stream *self, struct clod_string *dst)
Definition stream.h:72
int(* close)(clod_stream *self)
Definition stream.h:102
char * ptr
Definition string.h:28
ptrdiff_t len
Definition string.h:32
ptrdiff_t cap
Definition string.h:36