Merge remote branch 'mplayer/master'
[mplayer/glamo.git] / stream / ai_alsa1x.c
blobfa307a1cd8fbd5dfc02855cbe291729d54799406
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/time.h>
4 #include <alloca.h>
6 #include "config.h"
8 #include <alsa/asoundlib.h>
9 #include "audio_in.h"
10 #include "mp_msg.h"
11 #include "help_mp.h"
13 int ai_alsa_setup(audio_in_t *ai)
15 snd_pcm_hw_params_t *params;
16 snd_pcm_sw_params_t *swparams;
17 snd_pcm_uframes_t buffer_size, period_size;
18 int err;
19 int dir;
20 unsigned int rate;
22 snd_pcm_hw_params_alloca(&params);
23 snd_pcm_sw_params_alloca(&swparams);
25 err = snd_pcm_hw_params_any(ai->alsa.handle, params);
26 if (err < 0) {
27 mp_tmsg(MSGT_TV, MSGL_ERR, "Broken configuration for this PCM: no configurations available.\n");
28 return -1;
31 err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
32 SND_PCM_ACCESS_RW_INTERLEAVED);
33 if (err < 0) {
34 mp_tmsg(MSGT_TV, MSGL_ERR, "Access type not available.\n");
35 return -1;
38 err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
39 if (err < 0) {
40 mp_tmsg(MSGT_TV, MSGL_ERR, "Sample format not available.\n");
41 return -1;
44 err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
45 if (err < 0) {
46 snd_pcm_hw_params_get_channels(params, &ai->channels);
47 mp_tmsg(MSGT_TV, MSGL_ERR, "Channel count not available - reverting to default: %d\n",
48 ai->channels);
49 } else {
50 ai->channels = ai->req_channels;
53 dir = 0;
54 rate = ai->req_samplerate;
55 err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir);
56 if (err < 0) {
57 mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set samplerate.\n");
59 ai->samplerate = rate;
61 dir = 0;
62 ai->alsa.buffer_time = 1000000;
63 err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
64 &ai->alsa.buffer_time, &dir);
65 if (err < 0) {
66 mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set buffer time.\n");
69 dir = 0;
70 ai->alsa.period_time = ai->alsa.buffer_time / 4;
71 err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
72 &ai->alsa.period_time, &dir);
73 if (err < 0) {
74 mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set period time.\n");
77 err = snd_pcm_hw_params(ai->alsa.handle, params);
78 if (err < 0) {
79 mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install hardware paramameters: %s", snd_strerror(err));
80 snd_pcm_hw_params_dump(params, ai->alsa.log);
81 return -1;
84 dir = -1;
85 snd_pcm_hw_params_get_period_size(params, &period_size, &dir);
86 snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
87 ai->alsa.chunk_size = period_size;
88 if (period_size == buffer_size) {
89 mp_tmsg(MSGT_TV, MSGL_ERR, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size);
90 return -1;
93 snd_pcm_sw_params_current(ai->alsa.handle, swparams);
94 err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0);
95 err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);
97 err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
98 err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);
100 if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
101 mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install software parameters:\n");
102 snd_pcm_sw_params_dump(swparams, ai->alsa.log);
103 return -1;
106 if (mp_msg_test(MSGT_TV, MSGL_V)) {
107 snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
110 ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
111 ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
112 ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
113 ai->samplesize = ai->alsa.bits_per_sample;
114 ai->bytes_per_sample = ai->alsa.bits_per_sample/8;
116 return 0;
119 int ai_alsa_init(audio_in_t *ai)
121 int err;
123 err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0);
124 if (err < 0) {
125 mp_tmsg(MSGT_TV, MSGL_ERR, "Error opening audio: %s\n", snd_strerror(err));
126 return -1;
129 err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0);
131 if (err < 0) {
132 return -1;
135 err = ai_alsa_setup(ai);
137 return err;
140 #ifndef timersub
141 #define timersub(a, b, result) \
142 do { \
143 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
144 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
145 if ((result)->tv_usec < 0) { \
146 --(result)->tv_sec; \
147 (result)->tv_usec += 1000000; \
149 } while (0)
150 #endif
152 int ai_alsa_xrun(audio_in_t *ai)
154 snd_pcm_status_t *status;
155 int res;
157 snd_pcm_status_alloca(&status);
158 if ((res = snd_pcm_status(ai->alsa.handle, status))<0) {
159 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA status error: %s", snd_strerror(res));
160 return -1;
162 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
163 struct timeval now, diff, tstamp;
164 gettimeofday(&now, 0);
165 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
166 timersub(&now, &tstamp, &diff);
167 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA xrun!!! (at least %.3f ms long)\n",
168 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
169 if (mp_msg_test(MSGT_TV, MSGL_V)) {
170 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA Status:\n");
171 snd_pcm_status_dump(status, ai->alsa.log);
173 if ((res = snd_pcm_prepare(ai->alsa.handle))<0) {
174 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA xrun: prepare error: %s", snd_strerror(res));
175 return -1;
177 return 0; /* ok, data should be accepted again */
179 mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA read/write error");
180 return -1;