Mercurial > audlegacy-plugins
comparison src/alsa-ng/alsa-core.c @ 3166:8cbf077ba5d0
alsa-ng: Software pause, so we don't have to use snd_pcm_pause(), which is not part of the safe ALSA subset.
Also, make heavy use of thread signalling to remove crap like:
while (condition != true && pcm_going)
g_usleep(10000);
That's... so XMMS.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Fri, 15 May 2009 00:02:47 -0500 |
parents | 087abc78516e |
children | 9739ba93fd79 |
comparison
equal
deleted
inserted
replaced
3165:087abc78516e | 3166:8cbf077ba5d0 |
---|---|
27 static gint bps; | 27 static gint bps; |
28 | 28 |
29 static gsize wr_total = 0; | 29 static gsize wr_total = 0; |
30 static gsize wr_hwframes = 0; | 30 static gsize wr_hwframes = 0; |
31 | 31 |
32 static gint flush_request, pause_request, paused; | 32 static gint flush_request, paused; |
33 static gboolean can_pause; | 33 |
34 static GMutex *pcm_pause_mutex, *pcm_state_mutex; | |
35 static GCond *pcm_pause_cond, *pcm_state_cond; | |
34 | 36 |
35 /******************************************************************************** | 37 /******************************************************************************** |
36 * ALSA Mixer setting functions. * | 38 * ALSA Mixer setting functions. * |
37 ********************************************************************************/ | 39 ********************************************************************************/ |
38 | 40 |
78 { | 80 { |
79 snd_pcm_drop(pcm_handle); | 81 snd_pcm_drop(pcm_handle); |
80 snd_pcm_prepare(pcm_handle); | 82 snd_pcm_prepare(pcm_handle); |
81 wr_total = flush_request * (bps / 1000); | 83 wr_total = flush_request * (bps / 1000); |
82 flush_request = -1; | 84 flush_request = -1; |
83 } | 85 |
84 | 86 g_cond_broadcast(pcm_state_cond); |
85 if (pause_request != paused) | |
86 { | |
87 snd_pcm_pause(pcm_handle, pause_request); | |
88 paused = pause_request; | |
89 continue; | |
90 } | 87 } |
91 | 88 |
92 if (alsaplug_ringbuffer_read(&pcm_ringbuf, buf, 2048) == -1) | 89 if (alsaplug_ringbuffer_read(&pcm_ringbuf, buf, 2048) == -1) |
93 { | 90 { |
94 /* less than 2048 bytes to go...? */ | 91 /* less than 2048 bytes to go...? */ |
95 gint remain = alsaplug_ringbuffer_used(&pcm_ringbuf); | 92 gint remain = alsaplug_ringbuffer_used(&pcm_ringbuf); |
96 if (remain <= 2048) | 93 if (remain <= 2048 && remain > 0) |
97 { | 94 { |
98 alsaplug_ringbuffer_read(&pcm_ringbuf, buf, remain); | 95 alsaplug_ringbuffer_read(&pcm_ringbuf, buf, remain); |
99 alsaplug_write_buffer(buf, remain); | 96 alsaplug_write_buffer(buf, remain); |
100 } | 97 } |
98 else | |
99 { | |
100 g_mutex_lock(pcm_state_mutex); | |
101 g_cond_wait(pcm_state_cond, pcm_state_mutex); | |
102 g_mutex_unlock(pcm_state_mutex); | |
103 } | |
101 | 104 |
102 continue; | 105 continue; |
103 } | 106 } |
104 | 107 |
105 alsaplug_write_buffer(buf, 2048); | 108 alsaplug_write_buffer(buf, 2048); |
106 } | 109 } |
107 | 110 |
108 snd_pcm_drain(pcm_handle); | 111 snd_pcm_drain(pcm_handle); |
109 snd_pcm_close(pcm_handle); | 112 snd_pcm_close(pcm_handle); |
110 pcm_handle = NULL; | 113 pcm_handle = NULL; |
114 alsaplug_ringbuffer_destroy(&pcm_ringbuf); | |
111 | 115 |
112 return NULL; | 116 return NULL; |
113 } | 117 } |
114 | 118 |
115 /******************************************************************************** | 119 /******************************************************************************** |
118 | 122 |
119 static OutputPluginInitStatus | 123 static OutputPluginInitStatus |
120 alsaplug_init(void) | 124 alsaplug_init(void) |
121 { | 125 { |
122 gint card = -1; | 126 gint card = -1; |
127 | |
128 pcm_pause_mutex = g_mutex_new(); | |
129 pcm_pause_cond = g_cond_new(); | |
130 | |
131 pcm_state_mutex = g_mutex_new(); | |
132 pcm_state_cond = g_cond_new(); | |
123 | 133 |
124 if (snd_card_next(&card) != 0) | 134 if (snd_card_next(&card) != 0) |
125 return OUTPUT_PLUGIN_INIT_NO_DEVICES; | 135 return OUTPUT_PLUGIN_INIT_NO_DEVICES; |
126 | 136 |
127 return OUTPUT_PLUGIN_INIT_FOUND_DEVICES; | 137 return OUTPUT_PLUGIN_INIT_FOUND_DEVICES; |
155 { | 165 { |
156 _ERROR("snd_pcm_hw_params failed: %s", snd_strerror(err)); | 166 _ERROR("snd_pcm_hw_params failed: %s", snd_strerror(err)); |
157 return -1; | 167 return -1; |
158 } | 168 } |
159 | 169 |
160 can_pause = snd_pcm_hw_params_can_pause(hwparams); | |
161 bitwidth = snd_pcm_format_physical_width(afmt); | 170 bitwidth = snd_pcm_format_physical_width(afmt); |
162 bps = (rate * bitwidth * nch) >> 3; | 171 bps = (rate * bitwidth * nch) >> 3; |
163 ringbuf_size = aud_cfg->output_buffer_size * bps / 1000; | 172 ringbuf_size = aud_cfg->output_buffer_size * bps / 1000; |
164 alsaplug_ringbuffer_init(&pcm_ringbuf, ringbuf_size); | 173 alsaplug_ringbuffer_init(&pcm_ringbuf, ringbuf_size); |
165 pcm_going = TRUE; | 174 pcm_going = TRUE; |
170 } | 179 } |
171 | 180 |
172 static void | 181 static void |
173 alsaplug_close_audio(void) | 182 alsaplug_close_audio(void) |
174 { | 183 { |
184 g_mutex_lock(pcm_state_mutex); | |
175 pcm_going = FALSE; | 185 pcm_going = FALSE; |
186 g_mutex_unlock(pcm_state_mutex); | |
187 g_cond_broadcast(pcm_state_cond); | |
176 | 188 |
177 g_thread_join(audio_thread); | 189 g_thread_join(audio_thread); |
178 audio_thread = NULL; | 190 audio_thread = NULL; |
179 | 191 |
180 wr_total = 0; | 192 wr_total = 0; |
181 wr_hwframes = 0; | 193 wr_hwframes = 0; |
182 bps = 0; | 194 bps = 0; |
183 alsaplug_ringbuffer_destroy(&pcm_ringbuf); | |
184 } | 195 } |
185 | 196 |
186 static void | 197 static void |
187 alsaplug_write_audio(gpointer data, gint length) | 198 alsaplug_write_audio(gpointer data, gint length) |
188 { | 199 { |
200 if (paused) | |
201 { | |
202 g_mutex_lock(pcm_pause_mutex); | |
203 g_cond_wait(pcm_pause_cond, pcm_pause_mutex); | |
204 g_mutex_unlock(pcm_pause_mutex); | |
205 } | |
206 | |
189 wr_total += length; | 207 wr_total += length; |
190 alsaplug_ringbuffer_write(&pcm_ringbuf, data, length); | 208 alsaplug_ringbuffer_write(&pcm_ringbuf, data, length); |
209 g_cond_broadcast(pcm_state_cond); | |
191 } | 210 } |
192 | 211 |
193 static gint | 212 static gint |
194 alsaplug_output_time(void) | 213 alsaplug_output_time(void) |
195 { | 214 { |
229 } | 248 } |
230 | 249 |
231 static void | 250 static void |
232 alsaplug_flush(gint time) | 251 alsaplug_flush(gint time) |
233 { | 252 { |
253 /* make the request... */ | |
254 g_mutex_lock(pcm_state_mutex); | |
234 flush_request = time; | 255 flush_request = time; |
235 while (flush_request != -1 && pcm_going) | 256 g_mutex_unlock(pcm_state_mutex); |
236 g_usleep(10000); | 257 g_cond_broadcast(pcm_state_cond); |
258 | |
259 /* ...then wait for the transaction to complete. */ | |
260 g_mutex_lock(pcm_state_mutex); | |
261 g_cond_wait(pcm_state_cond, pcm_state_mutex); | |
262 g_mutex_unlock(pcm_state_mutex); | |
237 } | 263 } |
238 | 264 |
239 static gint | 265 static gint |
240 alsaplug_buffer_playing(void) | 266 alsaplug_buffer_playing(void) |
241 { | 267 { |
243 } | 269 } |
244 | 270 |
245 static void | 271 static void |
246 alsaplug_pause(short p) | 272 alsaplug_pause(short p) |
247 { | 273 { |
248 pause_request = p; | 274 g_mutex_lock(pcm_pause_mutex); |
275 paused = p; | |
276 g_mutex_unlock(pcm_pause_mutex); | |
277 g_cond_broadcast(pcm_pause_cond); | |
249 } | 278 } |
250 | 279 |
251 /******************************************************************************** | 280 /******************************************************************************** |
252 * Plugin glue. * | 281 * Plugin glue. * |
253 ********************************************************************************/ | 282 ********************************************************************************/ |