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 ********************************************************************************/