core: fix audio-only + framestep weird behavior
[mplayer/glamo.git] / stream / ai_alsa.c
blobc5e2f3f623917984397c66d7c688a142ccea5053
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <sys/time.h>
22 #include <alloca.h>
24 #include "config.h"
26 #include <alsa/asoundlib.h>
27 #include "audio_in.h"
28 #include "mp_msg.h"
30 int ai_alsa_setup(audio_in_t *ai)
32 snd_pcm_hw_params_t *params;
33 snd_pcm_sw_params_t *swparams;
34 int buffer_size;
35 int err;
36 unsigned int rate;
38 snd_pcm_hw_params_alloca(&params);
39 snd_pcm_sw_params_alloca(&swparams);
41 err = snd_pcm_hw_params_any(ai->alsa.handle, params);
42 if (err < 0) {
43 mp_tmsg(MSGT_TV, MSGL_ERR, "Broken configuration for this PCM: no configurations available.\n");
44 return -1;
46 err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
47 SND_PCM_ACCESS_RW_INTERLEAVED);
48 if (err < 0) {
49 mp_tmsg(MSGT_TV, MSGL_ERR, "Access type not available.\n");
50 return -1;
52 err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
53 if (err < 0) {
54 mp_tmsg(MSGT_TV, MSGL_ERR, "Sample format not available.\n");
55 return -1;
57 err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
58 if (err < 0) {
59 ai->channels = snd_pcm_hw_params_get_channels(params);
60 mp_tmsg(MSGT_TV, MSGL_ERR, "Channel count not available - reverting to default: %d\n",
61 ai->channels);
62 } else {
63 ai->channels = ai->req_channels;
66 err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0);
67 assert(err >= 0);
68 rate = err;
69 ai->samplerate = rate;
71 ai->alsa.buffer_time = 1000000;
72 ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
73 ai->alsa.buffer_time, 0);
74 assert(ai->alsa.buffer_time >= 0);
75 ai->alsa.period_time = ai->alsa.buffer_time / 4;
76 ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
77 ai->alsa.period_time, 0);
78 assert(ai->alsa.period_time >= 0);
79 err = snd_pcm_hw_params(ai->alsa.handle, params);
80 if (err < 0) {
81 mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install hardware parameters: %s");
82 snd_pcm_hw_params_dump(params, ai->alsa.log);
83 return -1;
85 ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0);
86 buffer_size = snd_pcm_hw_params_get_buffer_size(params);
87 if (ai->alsa.chunk_size == buffer_size) {
88 mp_tmsg(MSGT_TV, MSGL_ERR, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size);
89 return -1;
91 snd_pcm_sw_params_current(ai->alsa.handle, swparams);
92 err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0);
93 assert(err >= 0);
94 err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);
95 assert(err >= 0);
97 err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
98 assert(err >= 0);
99 err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);
100 assert(err >= 0);
102 assert(err >= 0);
103 if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
104 mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install software parameters:\n");
105 snd_pcm_sw_params_dump(swparams, ai->alsa.log);
106 return -1;
109 if (mp_msg_test(MSGT_TV, MSGL_V)) {
110 snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
113 ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
114 ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
115 ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
116 ai->samplesize = ai->alsa.bits_per_sample;
117 ai->bytes_per_sample = ai->alsa.bits_per_sample/8;
119 return 0;
122 int ai_alsa_init(audio_in_t *ai)
124 int err;
126 err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0);
127 if (err < 0) {
128 mp_tmsg(MSGT_TV, MSGL_ERR, "Error opening audio: %s\n", snd_strerror(err));
129 return -1;
132 err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0);
134 if (err < 0) {
135 return -1;
138 err = ai_alsa_setup(ai);
140 return err;
143 #ifndef timersub
144 #define timersub(a, b, result) \
145 do { \
146 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
147 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
148 if ((result)->tv_usec < 0) { \
149 --(result)->tv_sec; \
150 (result)->tv_usec += 1000000; \
152 } while (0)
153 #endif
155 int ai_alsa_xrun(audio_in_t *ai)
157 snd_pcm_status_t *status;
158 int res;
160 snd_pcm_status_alloca(&status);
161 if ((res = snd_pcm_status(ai->alsa.handle, status))<0) {
162 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA status error: %s", snd_strerror(res));
163 return -1;
165 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
166 struct timeval now, diff, tstamp;
167 gettimeofday(&now, 0);
168 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
169 timersub(&now, &tstamp, &diff);
170 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA xrun!!! (at least %.3f ms long)\n",
171 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
172 if (mp_msg_test(MSGT_TV, MSGL_V)) {
173 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA Status:\n");
174 snd_pcm_status_dump(status, ai->alsa.log);
176 if ((res = snd_pcm_prepare(ai->alsa.handle))<0) {
177 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA xrun: prepare error: %s", snd_strerror(res));
178 return -1;
180 return 0; /* ok, data should be accepted again */
182 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA read/write error");
183 return -1;