revert commits 26437-26439 the right way[tm]
[mplayer/glamo.git] / stream / ai_alsa1x.c
blob455c64191f68a9bb0ff191bcbdeb42efe8006d05
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/time.h>
5 #include "config.h"
7 #include <alsa/asoundlib.h>
8 #include "audio_in.h"
9 #include "mp_msg.h"
10 #include "help_mp.h"
12 int ai_alsa_setup(audio_in_t *ai)
14 snd_pcm_hw_params_t *params;
15 snd_pcm_sw_params_t *swparams;
16 snd_pcm_uframes_t buffer_size, period_size;
17 int err;
18 int dir;
19 unsigned int rate;
21 snd_pcm_hw_params_alloca(&params);
22 snd_pcm_sw_params_alloca(&swparams);
24 err = snd_pcm_hw_params_any(ai->alsa.handle, params);
25 if (err < 0) {
26 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig);
27 return -1;
30 err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
31 SND_PCM_ACCESS_RW_INTERLEAVED);
32 if (err < 0) {
33 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType);
34 return -1;
37 err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
38 if (err < 0) {
39 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt);
40 return -1;
43 err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
44 if (err < 0) {
45 snd_pcm_hw_params_get_channels(params, &ai->channels);
46 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount,
47 ai->channels);
48 } else {
49 ai->channels = ai->req_channels;
52 dir = 0;
53 rate = ai->req_samplerate;
54 err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir);
55 if (err < 0) {
56 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetSamplerate);
58 ai->samplerate = rate;
60 dir = 0;
61 ai->alsa.buffer_time = 1000000;
62 err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
63 &ai->alsa.buffer_time, &dir);
64 if (err < 0) {
65 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetBufferTime);
68 dir = 0;
69 ai->alsa.period_time = ai->alsa.buffer_time / 4;
70 err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
71 &ai->alsa.period_time, &dir);
72 if (err < 0) {
73 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetPeriodTime);
76 err = snd_pcm_hw_params(ai->alsa.handle, params);
77 if (err < 0) {
78 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams, snd_strerror(err));
79 snd_pcm_hw_params_dump(params, ai->alsa.log);
80 return -1;
83 dir = -1;
84 snd_pcm_hw_params_get_period_size(params, &period_size, &dir);
85 snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
86 ai->alsa.chunk_size = period_size;
87 if (period_size == buffer_size) {
88 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size);
89 return -1;
92 snd_pcm_sw_params_current(ai->alsa.handle, swparams);
93 err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0);
94 err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);
96 err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
97 err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);
99 if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
100 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams);
101 snd_pcm_sw_params_dump(swparams, ai->alsa.log);
102 return -1;
105 if (mp_msg_test(MSGT_TV, MSGL_V)) {
106 snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
109 ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
110 ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
111 ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
112 ai->samplesize = ai->alsa.bits_per_sample;
113 ai->bytes_per_sample = ai->alsa.bits_per_sample/8;
115 return 0;
118 int ai_alsa_init(audio_in_t *ai)
120 int err;
122 err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0);
123 if (err < 0) {
124 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err));
125 return -1;
128 err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0);
130 if (err < 0) {
131 return -1;
134 err = ai_alsa_setup(ai);
136 return err;
139 #ifndef timersub
140 #define timersub(a, b, result) \
141 do { \
142 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
143 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
144 if ((result)->tv_usec < 0) { \
145 --(result)->tv_sec; \
146 (result)->tv_usec += 1000000; \
148 } while (0)
149 #endif
151 int ai_alsa_xrun(audio_in_t *ai)
153 snd_pcm_status_t *status;
154 int res;
156 snd_pcm_status_alloca(&status);
157 if ((res = snd_pcm_status(ai->alsa.handle, status))<0) {
158 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res));
159 return -1;
161 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
162 struct timeval now, diff, tstamp;
163 gettimeofday(&now, 0);
164 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
165 timersub(&now, &tstamp, &diff);
166 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN,
167 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
168 if (mp_msg_test(MSGT_TV, MSGL_V)) {
169 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus);
170 snd_pcm_status_dump(status, ai->alsa.log);
172 if ((res = snd_pcm_prepare(ai->alsa.handle))<0) {
173 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res));
174 return -1;
176 return 0; /* ok, data should be accepted again */
178 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError);
179 return -1;