Use DECLARE_ALIGNED macro instead of gcc __attribute__.
[mplayer/glamo.git] / stream / ai_alsa.c
blob4371dd23babeb8f221c30e1a9bcfc4011e385742
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 int buffer_size;
18 int err;
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;
29 err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
30 SND_PCM_ACCESS_RW_INTERLEAVED);
31 if (err < 0) {
32 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType);
33 return -1;
35 err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
36 if (err < 0) {
37 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt);
38 return -1;
40 err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
41 if (err < 0) {
42 ai->channels = snd_pcm_hw_params_get_channels(params);
43 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount,
44 ai->channels);
45 } else {
46 ai->channels = ai->req_channels;
49 err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0);
50 assert(err >= 0);
51 rate = err;
52 ai->samplerate = rate;
54 ai->alsa.buffer_time = 1000000;
55 ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
56 ai->alsa.buffer_time, 0);
57 assert(ai->alsa.buffer_time >= 0);
58 ai->alsa.period_time = ai->alsa.buffer_time / 4;
59 ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
60 ai->alsa.period_time, 0);
61 assert(ai->alsa.period_time >= 0);
62 err = snd_pcm_hw_params(ai->alsa.handle, params);
63 if (err < 0) {
64 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams);
65 snd_pcm_hw_params_dump(params, ai->alsa.log);
66 return -1;
68 ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0);
69 buffer_size = snd_pcm_hw_params_get_buffer_size(params);
70 if (ai->alsa.chunk_size == buffer_size) {
71 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size);
72 return -1;
74 snd_pcm_sw_params_current(ai->alsa.handle, swparams);
75 err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0);
76 assert(err >= 0);
77 err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);
78 assert(err >= 0);
80 err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
81 assert(err >= 0);
82 err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);
83 assert(err >= 0);
85 assert(err >= 0);
86 if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
87 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams);
88 snd_pcm_sw_params_dump(swparams, ai->alsa.log);
89 return -1;
92 if (mp_msg_test(MSGT_TV, MSGL_V)) {
93 snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
96 ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
97 ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
98 ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
99 ai->samplesize = ai->alsa.bits_per_sample;
100 ai->bytes_per_sample = ai->alsa.bits_per_sample/8;
102 return 0;
105 int ai_alsa_init(audio_in_t *ai)
107 int err;
109 err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0);
110 if (err < 0) {
111 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err));
112 return -1;
115 err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0);
117 if (err < 0) {
118 return -1;
121 err = ai_alsa_setup(ai);
123 return err;
126 #ifndef timersub
127 #define timersub(a, b, result) \
128 do { \
129 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
130 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
131 if ((result)->tv_usec < 0) { \
132 --(result)->tv_sec; \
133 (result)->tv_usec += 1000000; \
135 } while (0)
136 #endif
138 int ai_alsa_xrun(audio_in_t *ai)
140 snd_pcm_status_t *status;
141 int res;
143 snd_pcm_status_alloca(&status);
144 if ((res = snd_pcm_status(ai->alsa.handle, status))<0) {
145 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res));
146 return -1;
148 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
149 struct timeval now, diff, tstamp;
150 gettimeofday(&now, 0);
151 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
152 timersub(&now, &tstamp, &diff);
153 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN,
154 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
155 if (mp_msg_test(MSGT_TV, MSGL_V)) {
156 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus);
157 snd_pcm_status_dump(status, ai->alsa.log);
159 if ((res = snd_pcm_prepare(ai->alsa.handle))<0) {
160 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res));
161 return -1;
163 return 0; /* ok, data should be accepted again */
165 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError);
166 return -1;