2
audio_alsa: sound output with Advanced Linux Sound Architecture 1.x API
4
copyright 2006 by the mpg123 project - free software under the terms of the LGPL 2.1
5
see COPYING and AUTHORS files in distribution or http://mpg123.de
7
written by Clemens Ladisch <clemens@ladisch.de>
15
/* make ALSA 0.9.x compatible to the 1.0.x API */
16
#define ALSA_PCM_NEW_HW_PARAMS_API
17
#define ALSA_PCM_NEW_SW_PARAMS_API
19
#include <alsa/asoundlib.h>
21
/* My laptop has probs playing low-sampled files with only 0.5s buffer... this should be a user setting -- ThOr */
22
#define BUFFER_LENGTH 0.5 /* in seconds */
25
snd_pcm_format_t alsa;
28
{ SND_PCM_FORMAT_S16, AUDIO_FORMAT_SIGNED_16 },
29
{ SND_PCM_FORMAT_U16, AUDIO_FORMAT_UNSIGNED_16 },
30
{ SND_PCM_FORMAT_U8, AUDIO_FORMAT_UNSIGNED_8 },
31
{ SND_PCM_FORMAT_S8, AUDIO_FORMAT_SIGNED_8 },
32
{ SND_PCM_FORMAT_A_LAW, AUDIO_FORMAT_ALAW_8 },
33
{ SND_PCM_FORMAT_MU_LAW, AUDIO_FORMAT_ULAW_8 },
35
#define NUM_FORMATS (sizeof format_map / sizeof format_map[0])
37
static int initialize_device(struct audio_info_struct *ai);
39
int audio_open(struct audio_info_struct *ai)
44
pcm_name = ai->device ? ai->device : "default";
45
if (snd_pcm_open(&pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
46
fprintf(stderr, "audio_open(): cannot open device %s\n", pcm_name);
50
if (ai->format != -1) {
51
/* we're going to play: initalize sample format */
52
return initialize_device(ai);
54
/* query mode; sample format will be set for each query */
59
static int rates_match(long int desired, unsigned int actual)
61
return actual * 100 > desired * (100 - AUDIO_RATE_TOLERANCE) &&
62
actual * 100 < desired * (100 + AUDIO_RATE_TOLERANCE);
65
static int initialize_device(struct audio_info_struct *ai)
67
snd_pcm_hw_params_t *hw;
69
snd_pcm_format_t format;
71
snd_pcm_uframes_t buffer_size;
72
snd_pcm_uframes_t period_size;
73
snd_pcm_sw_params_t *sw;
74
snd_pcm_uframes_t boundary;
76
snd_pcm_hw_params_alloca(&hw);
77
if (snd_pcm_hw_params_any(ai->handle, hw) < 0) {
78
fprintf(stderr, "initialize_device(): no configuration available\n");
81
if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
82
fprintf(stderr, "initialize_device(): device does not support interleaved access\n");
85
format = SND_PCM_FORMAT_UNKNOWN;
86
for (i = 0; i < NUM_FORMATS; ++i) {
87
if (ai->format == format_map[i].mpg123) {
88
format = format_map[i].alsa;
92
if (format == SND_PCM_FORMAT_UNKNOWN) {
93
fprintf(stderr, "initialize_device(): invalid sample format %d\n", ai->format);
97
if (snd_pcm_hw_params_set_format(ai->handle, hw, format) < 0) {
98
fprintf(stderr, "initialize_device(): cannot set format %s\n", snd_pcm_format_name(format));
101
if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0) {
102
fprintf(stderr, "initialize_device(): cannot set %d channels\n", ai->channels);
106
if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0) {
107
fprintf(stderr, "initialize_device(): cannot set rate %u\n", rate);
110
if (!rates_match(ai->rate, rate)) {
111
fprintf(stderr, "initialize_device(): rate %ld not available, using %u\n", ai->rate, rate);
114
buffer_size = rate * BUFFER_LENGTH;
115
if (snd_pcm_hw_params_set_buffer_size_near(ai->handle, hw, &buffer_size) < 0) {
116
fprintf(stderr, "initialize_device(): cannot set buffer size\n");
119
period_size = buffer_size / 4;
120
if (snd_pcm_hw_params_set_period_size_near(ai->handle, hw, &period_size, NULL) < 0) {
121
fprintf(stderr, "initialize_device(): cannot set period size\n");
124
if (snd_pcm_hw_params(ai->handle, hw) < 0) {
125
fprintf(stderr, "initialize_device(): cannot set hw params\n");
129
snd_pcm_sw_params_alloca(&sw);
130
if (snd_pcm_sw_params_current(ai->handle, sw) < 0) {
131
fprintf(stderr, "initialize_device(): cannot get sw params\n");
134
/* start playing after the first write */
135
if (snd_pcm_sw_params_set_start_threshold(ai->handle, sw, 1) < 0) {
136
fprintf(stderr, "initialize_device(): cannot set start threshold\n");
139
if (snd_pcm_sw_params_get_boundary(sw, &boundary) < 0) {
140
fprintf(stderr, "initialize_device(): cannot get boundary\n");
143
/* never stop on underruns */
144
if (snd_pcm_sw_params_set_stop_threshold(ai->handle, sw, boundary) < 0) {
145
fprintf(stderr, "initialize_device(): cannot set stop threshold\n");
148
/* wake up on every interrupt */
149
if (snd_pcm_sw_params_set_avail_min(ai->handle, sw, 1) < 0) {
150
fprintf(stderr, "initialize_device(): cannot set min avail\n");
153
/* always write as many frames as possible */
154
if (snd_pcm_sw_params_set_xfer_align(ai->handle, sw, 1) < 0) {
155
fprintf(stderr, "initialize_device(): cannot set transfer alignment\n");
158
/* play silence when there is an underrun */
159
if (snd_pcm_sw_params_set_silence_size(ai->handle, sw, boundary) < 0) {
160
fprintf(stderr, "initialize_device(): cannot set silence size\n");
163
if (snd_pcm_sw_params(ai->handle, sw) < 0) {
164
fprintf(stderr, "initialize_device(): cannot set sw params\n");
170
int audio_get_formats(struct audio_info_struct *ai)
172
snd_pcm_hw_params_t *hw;
174
int supported_formats, i;
176
snd_pcm_hw_params_alloca(&hw);
177
if (snd_pcm_hw_params_any(ai->handle, hw) < 0) {
178
fprintf(stderr, "audio_get_formats(): no configuration available\n");
181
if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
183
if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0)
186
if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0)
188
if (!rates_match(ai->rate, rate))
190
supported_formats = 0;
191
for (i = 0; i < NUM_FORMATS; ++i) {
192
if (snd_pcm_hw_params_test_format(ai->handle, hw, format_map[i].alsa) == 0)
193
supported_formats |= format_map[i].mpg123;
195
return supported_formats;
198
int audio_play_samples(struct audio_info_struct *ai, unsigned char *buf, int bytes)
200
snd_pcm_uframes_t frames;
201
snd_pcm_sframes_t written;
203
#if SND_LIB_VERSION >= 0x000901
204
snd_pcm_sframes_t delay;
205
if (snd_pcm_delay(ai->handle, &delay) >= 0 && delay < 0)
206
/* underrun - move the application pointer forward to catch up */
207
snd_pcm_forward(ai->handle, -delay);
209
frames = snd_pcm_bytes_to_frames(ai->handle, bytes);
210
written = snd_pcm_writei(ai->handle, buf, frames);
212
return snd_pcm_frames_to_bytes(ai->handle, written);
217
void audio_queueflush(struct audio_info_struct *ai)
219
/* is this the optimal solution? - we should figure out what we really whant from this function */
220
snd_pcm_drop(ai->handle);
221
snd_pcm_prepare(ai->handle);
224
int audio_close(struct audio_info_struct *ai)
226
if(ai->handle != NULL) /* be really generous for being called without any device opening */
228
if (snd_pcm_state(ai->handle) == SND_PCM_STATE_RUNNING)
229
snd_pcm_drain(ai->handle);
230
return snd_pcm_close(ai->handle);