2 * QEMU Audio subsystem header
4 * Copyright (c) 2005 Vassili Karpov (malc)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
27 #define HW glue (HWVoice, Out)
28 #define SW glue (SWVoice, Out)
31 #define HW glue (HWVoice, In)
32 #define SW glue (SWVoice, In)
35 static void glue (audio_pcm_sw_fini_
, TYPE
) (SW
*sw
)
37 glue (audio_pcm_sw_free_resources_
, TYPE
) (sw
);
44 static void glue (audio_pcm_hw_add_sw_
, TYPE
) (HW
*hw
, SW
*sw
)
46 LIST_INSERT_HEAD (&hw
->sw_head
, sw
, entries
);
49 static void glue (audio_pcm_hw_del_sw_
, TYPE
) (SW
*sw
)
51 LIST_REMOVE (sw
, entries
);
54 static void glue (audio_pcm_hw_fini_
, TYPE
) (HW
*hw
)
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
));
63 static void glue (audio_pcm_hw_gc_
, TYPE
) (HW
*hw
)
65 if (!hw
->sw_head
.lh_first
) {
66 glue (audio_pcm_hw_fini_
, TYPE
) (hw
);
70 static HW
*glue (audio_pcm_hw_find_any_
, TYPE
) (HW
*hw
)
72 return hw
? hw
->entries
.le_next
: glue (hw_head_
, TYPE
).lh_first
;
75 static HW
*glue (audio_pcm_hw_find_any_active_
, TYPE
) (HW
*hw
)
77 while ((hw
= glue (audio_pcm_hw_find_any_
, TYPE
) (hw
))) {
85 static HW
*glue (audio_pcm_hw_find_any_active_enabled_
, TYPE
) (HW
*hw
)
87 while ((hw
= glue (audio_pcm_hw_find_any_
, TYPE
) (hw
))) {
88 if (hw
->active
&& hw
->enabled
) {
95 static HW
*glue (audio_pcm_hw_find_any_passive_
, TYPE
) (HW
*hw
)
97 while ((hw
= glue (audio_pcm_hw_find_any_
, TYPE
) (hw
))) {
105 static HW
*glue (audio_pcm_hw_find_specific_
, TYPE
) (
112 while ((hw
= glue (audio_pcm_hw_find_any_active_
, TYPE
) (hw
))) {
113 if (audio_pcm_info_eq (&hw
->info
, freq
, nchannels
, fmt
)) {
120 static HW
*glue (audio_pcm_hw_add_new_
, TYPE
) (
128 hw
= glue (audio_pcm_hw_find_any_passive_
, TYPE
) (NULL
);
130 hw
->pcm_ops
= audio_state
.drv
->pcm_ops
;
135 if (glue (audio_pcm_hw_init_
, TYPE
) (hw
, freq
, nchannels
, fmt
)) {
136 glue (audio_pcm_hw_gc_
, TYPE
) (hw
);
147 static HW
*glue (audio_pcm_hw_add_
, TYPE
) (
155 if (glue (audio_state
.greedy_
, TYPE
)) {
156 hw
= glue (audio_pcm_hw_add_new_
, TYPE
) (freq
, nchannels
, fmt
);
162 hw
= glue (audio_pcm_hw_find_specific_
, TYPE
) (NULL
, freq
, nchannels
, fmt
);
167 hw
= glue (audio_pcm_hw_add_new_
, TYPE
) (freq
, nchannels
, fmt
);
172 return glue (audio_pcm_hw_find_any_active_
, TYPE
) (NULL
);
175 static SW
*glue (audio_pcm_create_voice_pair_
, TYPE
) (
185 int hw_nchannels
= nchannels
;
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
);
194 sw
= qemu_mallocz (sizeof (*sw
));
199 hw
= glue (audio_pcm_hw_add_
, TYPE
) (hw_freq
, hw_nchannels
, hw_fmt
);
204 glue (audio_pcm_hw_add_sw_
, TYPE
) (hw
, sw
);
206 if (glue (audio_pcm_sw_init_
, TYPE
) (sw
, hw
, name
, freq
, nchannels
, fmt
)) {
213 glue (audio_pcm_hw_del_sw_
, TYPE
) (sw
);
214 glue (audio_pcm_hw_gc_
, TYPE
) (hw
);
221 void glue (AUD_close_
, TYPE
) (SW
*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
);
231 SW
*glue (AUD_open_
, TYPE
) (
234 void *callback_opaque
,
235 audio_callback_fn_t callback_fn
,
247 dolog ("No callback specifed for voice `%s'\n", name
);
251 if (nchannels
!= 1 && nchannels
!= 2) {
252 dolog ("Bogus channel count %d for voice `%s'\n", nchannels
, name
);
256 if (!audio_state
.drv
) {
257 dolog ("No audio driver defined\n");
261 if (sw
&& audio_pcm_info_eq (&sw
->info
, freq
, nchannels
, fmt
)) {
266 if (audio_state
.plive
&& sw
&& (!sw
->active
&& !sw
->empty
)) {
267 live
= sw
->total_hw_samples_mixed
;
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,
280 old_sw
->callback
.fn
= NULL
;
286 if (!glue (audio_state
.fixed_settings_
, TYPE
) && sw
) {
287 glue (AUD_close_
, TYPE
) (sw
);
295 dolog ("Internal logic error voice %s has no hardware store\n",
300 if (glue (audio_pcm_sw_init_
, TYPE
) (
312 sw
= glue (audio_pcm_create_voice_pair_
, TYPE
) (
318 dolog ("Failed to create voice %s\n", name
);
324 sw
->vol
= nominal_volume
;
325 sw
->callback
.fn
= callback_fn
;
326 sw
->callback
.opaque
= callback_opaque
;
331 (live
<< old_sw
->info
.shift
)
332 * old_sw
->info
.bytes_per_second
333 / sw
->info
.bytes_per_second
;
336 dolog ("Silence will be mixed %d\n", mixed
);
338 sw
->total_hw_samples_mixed
+= mixed
;
343 dolog ("%s\n", name
);
344 audio_pcm_print_info ("hw", &sw
->hw
->info
);
345 audio_pcm_print_info ("sw", &sw
->info
);
352 glue (AUD_close_
, TYPE
) (sw
);
356 int glue (AUD_is_active_
, TYPE
) (SW
*sw
)
358 return sw
? sw
->active
: 0;
361 void glue (AUD_init_time_stamp_
, TYPE
) (SW
*sw
, QEMUAudioTimeStamp
*ts
)
367 ts
->old_ts
= sw
->hw
->ts_helper
;
370 uint64_t glue (AUD_time_stamp_get_elapsed_usec_
, TYPE
) (
372 QEMUAudioTimeStamp
*ts
375 uint64_t delta
, cur_ts
, old_ts
;
381 cur_ts
= sw
->hw
->ts_helper
;
383 /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
385 if (cur_ts
>= old_ts
) {
386 delta
= cur_ts
- old_ts
;
389 delta
= UINT64_MAX
- old_ts
+ cur_ts
;
396 return (delta
* sw
->hw
->info
.freq
) / 1000000;