]> git.proxmox.com Git - mirror_qemu.git/blame - audio/audio_template.h
merged 15a_aqemu.patch audio patch (malc)
[mirror_qemu.git] / audio / audio_template.h
CommitLineData
1d14ffa9
FB
1/*
2 * QEMU Audio subsystem header
3 *
4 * Copyright (c) 2005 Vassili Karpov (malc)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#ifdef DAC
26#define TYPE out
27#define HW glue (HWVoice, Out)
28#define SW glue (SWVoice, Out)
29#else
30#define TYPE in
31#define HW glue (HWVoice, In)
32#define SW glue (SWVoice, In)
33#endif
34
35static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
36{
37 glue (audio_pcm_sw_free_resources_, TYPE) (sw);
38 if (sw->name) {
39 qemu_free (sw->name);
40 sw->name = NULL;
41 }
42}
43
44static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
45{
46 LIST_INSERT_HEAD (&hw->sw_head, sw, entries);
47}
48
49static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
50{
51 LIST_REMOVE (sw, entries);
52}
53
54static void glue (audio_pcm_hw_fini_, TYPE) (HW *hw)
55{
56 if (hw->active) {
57 glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
58 glue (hw->pcm_ops->fini_, TYPE) (hw);
59 memset (hw, 0, glue (audio_state.drv->voice_size_, TYPE));
60 }
61}
62
63static void glue (audio_pcm_hw_gc_, TYPE) (HW *hw)
64{
65 if (!hw->sw_head.lh_first) {
66 glue (audio_pcm_hw_fini_, TYPE) (hw);
67 }
68}
69
70static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
71{
72 return hw ? hw->entries.le_next : glue (hw_head_, TYPE).lh_first;
73}
74
75static HW *glue (audio_pcm_hw_find_any_active_, TYPE) (HW *hw)
76{
77 while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
78 if (hw->active) {
79 return hw;
80 }
81 }
82 return NULL;
83}
84
85static HW *glue (audio_pcm_hw_find_any_active_enabled_, TYPE) (HW *hw)
86{
87 while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
88 if (hw->active && hw->enabled) {
89 return hw;
90 }
91 }
92 return NULL;
93}
94
95static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (HW *hw)
96{
97 while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
98 if (!hw->active) {
99 return hw;
100 }
101 }
102 return NULL;
103}
104
105static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
106 HW *hw,
107 int freq,
108 int nchannels,
109 audfmt_e fmt
110 )
111{
112 while ((hw = glue (audio_pcm_hw_find_any_active_, TYPE) (hw))) {
113 if (audio_pcm_info_eq (&hw->info, freq, nchannels, fmt)) {
114 return hw;
115 }
116 }
117 return NULL;
118}
119
120static HW *glue (audio_pcm_hw_add_new_, TYPE) (
121 int freq,
122 int nchannels,
123 audfmt_e fmt
124 )
125{
126 HW *hw;
127
128 hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (NULL);
129 if (hw) {
130 hw->pcm_ops = audio_state.drv->pcm_ops;
131 if (!hw->pcm_ops) {
132 return NULL;
133 }
134
135 if (glue (audio_pcm_hw_init_, TYPE) (hw, freq, nchannels, fmt)) {
136 glue (audio_pcm_hw_gc_, TYPE) (hw);
137 return NULL;
138 }
139 else {
140 return hw;
141 }
142 }
143
144 return NULL;
145}
146
147static HW *glue (audio_pcm_hw_add_, TYPE) (
148 int freq,
149 int nchannels,
150 audfmt_e fmt
151 )
152{
153 HW *hw;
154
155 if (glue (audio_state.greedy_, TYPE)) {
156 hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt);
157 if (hw) {
158 return hw;
159 }
160 }
161
162 hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, freq, nchannels, fmt);
163 if (hw) {
164 return hw;
165 }
166
167 hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt);
168 if (hw) {
169 return hw;
170 }
171
172 return glue (audio_pcm_hw_find_any_active_, TYPE) (NULL);
173}
174
175static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
176 const char *name,
177 int freq,
178 int nchannels,
179 audfmt_e fmt
180 )
181{
182 SW *sw;
183 HW *hw;
184 int hw_freq = freq;
185 int hw_nchannels = nchannels;
186 int hw_fmt = fmt;
187
188 if (glue (audio_state.fixed_settings_, TYPE)) {
189 hw_freq = glue (audio_state.fixed_freq_, TYPE);
190 hw_nchannels = glue (audio_state.fixed_channels_, TYPE);
191 hw_fmt = glue (audio_state.fixed_fmt_, TYPE);
192 }
193
194 sw = qemu_mallocz (sizeof (*sw));
195 if (!sw) {
196 goto err1;
197 }
198
199 hw = glue (audio_pcm_hw_add_, TYPE) (hw_freq, hw_nchannels, hw_fmt);
200 if (!hw) {
201 goto err2;
202 }
203
204 glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
205
206 if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, freq, nchannels, fmt)) {
207 goto err3;
208 }
209
210 return sw;
211
212err3:
213 glue (audio_pcm_hw_del_sw_, TYPE) (sw);
214 glue (audio_pcm_hw_gc_, TYPE) (hw);
215err2:
216 qemu_free (sw);
217err1:
218 return NULL;
219}
220
221void glue (AUD_close_, TYPE) (SW *sw)
222{
223 if (sw) {
224 glue (audio_pcm_sw_fini_, TYPE) (sw);
225 glue (audio_pcm_hw_del_sw_, TYPE) (sw);
226 glue (audio_pcm_hw_gc_, TYPE) (sw->hw);
227 qemu_free (sw);
228 }
229}
230
231SW *glue (AUD_open_, TYPE) (
232 SW *sw,
233 const char *name,
234 void *callback_opaque ,
235 audio_callback_fn_t callback_fn,
236 int freq,
237 int nchannels,
238 audfmt_e fmt
239 )
240{
241#ifdef DAC
242 int live = 0;
243 SW *old_sw = NULL;
244#endif
245
246 if (!callback_fn) {
247 dolog ("No callback specifed for voice `%s'\n", name);
248 goto fail;
249 }
250
251 if (nchannels != 1 && nchannels != 2) {
252 dolog ("Bogus channel count %d for voice `%s'\n", nchannels, name);
253 goto fail;
254 }
255
256 if (!audio_state.drv) {
257 dolog ("No audio driver defined\n");
258 goto fail;
259 }
260
261 if (sw && audio_pcm_info_eq (&sw->info, freq, nchannels, fmt)) {
262 return sw;
263 }
264
265#ifdef DAC
266 if (audio_state.plive && sw && (!sw->active && !sw->empty)) {
267 live = sw->total_hw_samples_mixed;
268
269#ifdef DEBUG_PLIVE
270 dolog ("Replacing voice %s with %d live samples\n", sw->name, live);
271 dolog ("Old %s freq %d, bits %d, channels %d\n",
272 sw->name, sw->info.freq, sw->info.bits, sw->info.nchannels);
273 dolog ("New %s freq %d, bits %d, channels %d\n",
274 name, freq, (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8,
275 nchannels);
276#endif
277
278 if (live) {
279 old_sw = sw;
280 old_sw->callback.fn = NULL;
281 sw = NULL;
282 }
283 }
284#endif
285
286 if (!glue (audio_state.fixed_settings_, TYPE) && sw) {
287 glue (AUD_close_, TYPE) (sw);
288 sw = NULL;
289 }
290
291 if (sw) {
292 HW *hw = sw->hw;
293
294 if (!hw) {
295 dolog ("Internal logic error voice %s has no hardware store\n",
296 name);
297 goto fail;
298 }
299
300 if (glue (audio_pcm_sw_init_, TYPE) (
301 sw,
302 hw,
303 name,
304 freq,
305 nchannels,
306 fmt
307 )) {
308 goto fail;
309 }
310 }
311 else {
312 sw = glue (audio_pcm_create_voice_pair_, TYPE) (
313 name,
314 freq,
315 nchannels,
316 fmt);
317 if (!sw) {
318 dolog ("Failed to create voice %s\n", name);
319 goto fail;
320 }
321 }
322
323 if (sw) {
324 sw->vol = nominal_volume;
325 sw->callback.fn = callback_fn;
326 sw->callback.opaque = callback_opaque;
327
328#ifdef DAC
329 if (live) {
330 int mixed =
331 (live << old_sw->info.shift)
332 * old_sw->info.bytes_per_second
333 / sw->info.bytes_per_second;
334
335#ifdef DEBUG_PLIVE
336 dolog ("Silence will be mixed %d\n", mixed);
337#endif
338 sw->total_hw_samples_mixed += mixed;
339 }
340#endif
341
342#ifdef DEBUG_AUDIO
343 dolog ("%s\n", name);
344 audio_pcm_print_info ("hw", &sw->hw->info);
345 audio_pcm_print_info ("sw", &sw->info);
346#endif
347 }
348
349 return sw;
350
351 fail:
352 glue (AUD_close_, TYPE) (sw);
353 return NULL;
354}
355
356int glue (AUD_is_active_, TYPE) (SW *sw)
357{
358 return sw ? sw->active : 0;
359}
360
361void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
362{
363 if (!sw) {
364 return;
365 }
366
367 ts->old_ts = sw->hw->ts_helper;
368}
369
370uint64_t glue (AUD_time_stamp_get_elapsed_usec_, TYPE) (
371 SW *sw,
372 QEMUAudioTimeStamp *ts
373 )
374{
375 uint64_t delta, cur_ts, old_ts;
376
377 if (!sw) {
378 return 0;
379 }
380
381 cur_ts = sw->hw->ts_helper;
382 old_ts = ts->old_ts;
383 /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
384
385 if (cur_ts >= old_ts) {
386 delta = cur_ts - old_ts;
387 }
388 else {
389 delta = UINT64_MAX - old_ts + cur_ts;
390 }
391
392 if (!delta) {
393 return 0;
394 }
395
396 return (delta * sw->hw->info.freq) / 1000000;
397}
398
399#undef TYPE
400#undef HW
401#undef SW