-
Notifications
You must be signed in to change notification settings - Fork 11
/
alsa.h
148 lines (129 loc) · 3.93 KB
/
alsa.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* public domain Simple, Minimalistic, Audio library for ALSA
* ©2017 Yuichiro Nakada
*
* Basic usage:
* AUDIO a;
* AUDIO_init(&a, "plughw:PCH,0", 48000, 2, 32); // device, 48000 samplerate, 2 channels, 32 frame
* ...
* int f = AUDIO_frame(&a); // audio data in a.buffer
* ...
* AUDIO_close(&a);
*
* */
// Use the newer ALSA API
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
typedef struct {
snd_pcm_t *handle;
snd_pcm_uframes_t frames;
char *buffer;
int size;
} AUDIO;
int AUDIO_init(AUDIO *thiz, char *dev, unsigned int val, int ch, int frames, int flag)
{
// Open PCM device.
int rc = snd_pcm_open(&thiz->handle, dev, flag ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device '%s' (%s)\n", dev, snd_strerror(rc));
return 1;
}
// Allocate a hardware parameters object.
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(¶ms);
// Fill it in with default values.
snd_pcm_hw_params_any(thiz->handle, params);
// Set the desired hardware parameters.
// Interleaved mode
rc = snd_pcm_hw_params_set_access(thiz->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (rc < 0) {
fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(rc));
snd_pcm_drain(thiz->handle);
snd_pcm_close(thiz->handle);
return 1;
}
// Signed 16-bit little-endian format
rc = snd_pcm_hw_params_set_format(thiz->handle, params, SND_PCM_FORMAT_S16_LE);
if (rc < 0) {
fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(rc));
snd_pcm_drain(thiz->handle);
snd_pcm_close(thiz->handle);
return 1;
}
// Channels
rc = snd_pcm_hw_params_set_channels(thiz->handle, params, ch);
if (rc < 0) {
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(rc));
snd_pcm_drain(thiz->handle);
snd_pcm_close(thiz->handle);
return 1;
}
// 44100 bits/second sampling rate (CD quality)
int dir;
rc = snd_pcm_hw_params_set_rate_near(thiz->handle, params, &val, &dir);
if (rc < 0) {
fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(rc));
snd_pcm_drain(thiz->handle);
snd_pcm_close(thiz->handle);
return 1;
}
// Set period size to 32 frames.
thiz->frames = frames;
snd_pcm_hw_params_set_period_size_near(thiz->handle, params, &thiz->frames, &dir);
// Write the parameters to the driver
rc = snd_pcm_hw_params(thiz->handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set parameters (%s)\n", snd_strerror(rc));
snd_pcm_drain(thiz->handle);
snd_pcm_close(thiz->handle);
return 1;
}
// Use a buffer large enough to hold one period
snd_pcm_hw_params_get_period_size(params, &thiz->frames, &dir);
thiz->size = thiz->frames * 2 * ch; /* 2 bytes/sample, 2 channels */
thiz->buffer = (char*)malloc(thiz->size);
snd_pcm_hw_params_get_period_time(params, &val, &dir);
return 0;
}
int AUDIO_frame(AUDIO *thiz)
{
int rc = snd_pcm_readi(thiz->handle, thiz->buffer, thiz->frames);
if (rc == -EPIPE) {
// EPIPE means overrun
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(thiz->handle);
} else if (rc < 0) {
fprintf(stderr, "read failed (%s)\n", snd_strerror(rc));
} else if (rc != (int)thiz->frames) {
fprintf(stderr, "short read, read %d frames\n", rc);
}
return rc;
}
int AUDIO_play(AUDIO *thiz, char *data, int frames)
{
int rc = snd_pcm_writei(thiz->handle, data, frames);
if (rc == -EPIPE) {
// EPIPE means overrun
fprintf(stderr, "overrun occurred\n");
snd_pcm_recover(thiz->handle, rc, 0);
//snd_pcm_prepare(thiz->handle);
} else if (rc < 0) {
fprintf(stderr, "write failed (%s)\n", snd_strerror(rc));
} else if (rc != frames) {
fprintf(stderr, "short write, write %d/%d frames\n", rc, (int)thiz->frames);
}
return rc;
}
int AUDIO_play0(AUDIO *thiz)
{
return AUDIO_play(thiz, thiz->buffer, thiz->frames);
}
void AUDIO_wait(AUDIO *thiz, int msec)
{
snd_pcm_wait(thiz->handle, msec);
}
void AUDIO_close(AUDIO *thiz)
{
snd_pcm_drain(thiz->handle);
snd_pcm_close(thiz->handle);
free(thiz->buffer);
}