Add explanatory comments to the #endif part of multiple inclusion guards.
[mplayer/greg.git] / stream / ai_alsa.c
bloba1468bed09987f155b2d8f33810c3c4e42536b78
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 int buffer_size;
17 int err;
18 unsigned int rate;
20 snd_pcm_hw_params_alloca(&params);
21 snd_pcm_sw_params_alloca(&swparams);
23 err = snd_pcm_hw_params_any(ai->alsa.handle, params);
24 if (err < 0) {
25 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig);
26 return -1;
28 err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
29 SND_PCM_ACCESS_RW_INTERLEAVED);
30 if (err < 0) {
31 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType);
32 return -1;
34 err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
35 if (err < 0) {
36 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt);
37 return -1;
39 err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
40 if (err < 0) {
41 ai->channels = snd_pcm_hw_params_get_channels(params);
42 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount,
43 ai->channels);
44 } else {
45 ai->channels = ai->req_channels;
48 err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0);
49 assert(err >= 0);
50 rate = err;
51 ai->samplerate = rate;
53 ai->alsa.buffer_time = 1000000;
54 ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
55 ai->alsa.buffer_time, 0);
56 assert(ai->alsa.buffer_time >= 0);
57 ai->alsa.period_time = ai->alsa.buffer_time / 4;
58 ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
59 ai->alsa.period_time, 0);
60 assert(ai->alsa.period_time >= 0);
61 err = snd_pcm_hw_params(ai->alsa.handle, params);
62 if (err < 0) {
63 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams);
64 snd_pcm_hw_params_dump(params, ai->alsa.log);
65 return -1;
67 ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0);
68 buffer_size = snd_pcm_hw_params_get_buffer_size(params);
69 if (ai->alsa.chunk_size == buffer_size) {
70 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size);
71 return -1;
73 snd_pcm_sw_params_current(ai->alsa.handle, swparams);
74 err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0);
75 assert(err >= 0);
76 err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);
77 assert(err >= 0);
79 err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
80 assert(err >= 0);
81 err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);
82 assert(err >= 0);
84 assert(err >= 0);
85 if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
86 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams);
87 snd_pcm_sw_params_dump(swparams, ai->alsa.log);
88 return -1;
91 if (mp_msg_test(MSGT_TV, MSGL_V)) {
92 snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
95 ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
96 ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
97 ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
98 ai->samplesize = ai->alsa.bits_per_sample;
99 ai->bytes_per_sample = ai->alsa.bits_per_sample/8;
101 return 0;
104 int ai_alsa_init(audio_in_t *ai)
106 int err;
108 err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0);
109 if (err < 0) {
110 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err));
111 return -1;
114 err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0);
116 if (err < 0) {
117 return -1;
120 err = ai_alsa_setup(ai);
122 return err;
125 #ifndef timersub
126 #define timersub(a, b, result) \
127 do { \
128 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
129 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
130 if ((result)->tv_usec < 0) { \
131 --(result)->tv_sec; \
132 (result)->tv_usec += 1000000; \
134 } while (0)
135 #endif
137 int ai_alsa_xrun(audio_in_t *ai)
139 snd_pcm_status_t *status;
140 int res;
142 snd_pcm_status_alloca(&status);
143 if ((res = snd_pcm_status(ai->alsa.handle, status))<0) {
144 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res));
145 return -1;
147 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
148 struct timeval now, diff, tstamp;
149 gettimeofday(&now, 0);
150 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
151 timersub(&now, &tstamp, &diff);
152 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN,
153 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
154 if (mp_msg_test(MSGT_TV, MSGL_V)) {
155 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus);
156 snd_pcm_status_dump(status, ai->alsa.log);
158 if ((res = snd_pcm_prepare(ai->alsa.handle))<0) {
159 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res));
160 return -1;
162 return 0; /* ok, data should be accepted again */
164 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError);
165 return -1;