xref: /qemu/audio/audio_template.h (revision a244eb7429ecc34797abb23c0852257e31675716)
11d14ffa9Sbellard /*
21d14ffa9Sbellard  * QEMU Audio subsystem header
31d14ffa9Sbellard  *
41d14ffa9Sbellard  * Copyright (c) 2005 Vassili Karpov (malc)
51d14ffa9Sbellard  *
61d14ffa9Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
71d14ffa9Sbellard  * of this software and associated documentation files (the "Software"), to deal
81d14ffa9Sbellard  * in the Software without restriction, including without limitation the rights
91d14ffa9Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
101d14ffa9Sbellard  * copies of the Software, and to permit persons to whom the Software is
111d14ffa9Sbellard  * furnished to do so, subject to the following conditions:
121d14ffa9Sbellard  *
131d14ffa9Sbellard  * The above copyright notice and this permission notice shall be included in
141d14ffa9Sbellard  * all copies or substantial portions of the Software.
151d14ffa9Sbellard  *
161d14ffa9Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171d14ffa9Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181d14ffa9Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
191d14ffa9Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201d14ffa9Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211d14ffa9Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
221d14ffa9Sbellard  * THE SOFTWARE.
231d14ffa9Sbellard  */
241d14ffa9Sbellard 
251d14ffa9Sbellard #ifdef DAC
26571ec3d6Sbellard #define NAME "playback"
27571ec3d6Sbellard #define HWBUF hw->mix_buf
281d14ffa9Sbellard #define TYPE out
29571ec3d6Sbellard #define HW HWVoiceOut
30571ec3d6Sbellard #define SW SWVoiceOut
311d14ffa9Sbellard #else
32571ec3d6Sbellard #define NAME "capture"
331d14ffa9Sbellard #define TYPE in
34571ec3d6Sbellard #define HW HWVoiceIn
35571ec3d6Sbellard #define SW SWVoiceIn
36571ec3d6Sbellard #define HWBUF hw->conv_buf
371d14ffa9Sbellard #endif
381d14ffa9Sbellard 
391a7dafceSmalc static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
40c0fe3827Sbellard {
411a7dafceSmalc     AudioState *s = &glob_audio_state;
42571ec3d6Sbellard     int max_voices = glue (drv->max_voices_, TYPE);
43571ec3d6Sbellard     int voice_size = glue (drv->voice_size_, TYPE);
44c0fe3827Sbellard 
45571ec3d6Sbellard     if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
46571ec3d6Sbellard         if (!max_voices) {
47c0fe3827Sbellard #ifdef DAC
48571ec3d6Sbellard             dolog ("Driver `%s' does not support " NAME "\n", drv->name);
49c0fe3827Sbellard #endif
50571ec3d6Sbellard         }
51571ec3d6Sbellard         else {
52571ec3d6Sbellard             dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
53571ec3d6Sbellard                    drv->name,
54571ec3d6Sbellard                    glue (s->nb_hw_voices_, TYPE),
55571ec3d6Sbellard                    max_voices);
56571ec3d6Sbellard         }
57571ec3d6Sbellard         glue (s->nb_hw_voices_, TYPE) = max_voices;
58571ec3d6Sbellard     }
59c0fe3827Sbellard 
60571ec3d6Sbellard     if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
61571ec3d6Sbellard         dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
62571ec3d6Sbellard                drv->name, max_voices);
63571ec3d6Sbellard         glue (s->nb_hw_voices_, TYPE) = 0;
64571ec3d6Sbellard     }
65571ec3d6Sbellard 
66571ec3d6Sbellard     if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
67571ec3d6Sbellard         dolog ("drv=`%s' voice_size=%d max_voices=0\n",
68571ec3d6Sbellard                drv->name, voice_size);
69571ec3d6Sbellard     }
70571ec3d6Sbellard }
71571ec3d6Sbellard 
72571ec3d6Sbellard static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
73571ec3d6Sbellard {
74571ec3d6Sbellard     if (HWBUF) {
75571ec3d6Sbellard         qemu_free (HWBUF);
76571ec3d6Sbellard     }
77571ec3d6Sbellard 
78571ec3d6Sbellard     HWBUF = NULL;
79571ec3d6Sbellard }
80571ec3d6Sbellard 
81571ec3d6Sbellard static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
82571ec3d6Sbellard {
831ea879e5Smalc     HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
84571ec3d6Sbellard     if (!HWBUF) {
85571ec3d6Sbellard         dolog ("Could not allocate " NAME " buffer (%d samples)\n",
86571ec3d6Sbellard                hw->samples);
87c0fe3827Sbellard         return -1;
88c0fe3827Sbellard     }
89c0fe3827Sbellard 
90c0fe3827Sbellard     return 0;
91c0fe3827Sbellard }
92c0fe3827Sbellard 
93571ec3d6Sbellard static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
94571ec3d6Sbellard {
95571ec3d6Sbellard     if (sw->buf) {
96571ec3d6Sbellard         qemu_free (sw->buf);
97571ec3d6Sbellard     }
98571ec3d6Sbellard 
99571ec3d6Sbellard     if (sw->rate) {
100571ec3d6Sbellard         st_rate_stop (sw->rate);
101571ec3d6Sbellard     }
102571ec3d6Sbellard 
103571ec3d6Sbellard     sw->buf = NULL;
104571ec3d6Sbellard     sw->rate = NULL;
105571ec3d6Sbellard }
106571ec3d6Sbellard 
107571ec3d6Sbellard static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
108571ec3d6Sbellard {
109571ec3d6Sbellard     int samples;
110571ec3d6Sbellard 
111571ec3d6Sbellard #ifdef DAC
112571ec3d6Sbellard     samples = sw->hw->samples;
113571ec3d6Sbellard #else
114571ec3d6Sbellard     samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
115571ec3d6Sbellard #endif
116571ec3d6Sbellard 
1171ea879e5Smalc     sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
118571ec3d6Sbellard     if (!sw->buf) {
119571ec3d6Sbellard         dolog ("Could not allocate buffer for `%s' (%d samples)\n",
120571ec3d6Sbellard                SW_NAME (sw), samples);
121571ec3d6Sbellard         return -1;
122571ec3d6Sbellard     }
123571ec3d6Sbellard 
124571ec3d6Sbellard #ifdef DAC
125571ec3d6Sbellard     sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
126571ec3d6Sbellard #else
127571ec3d6Sbellard     sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
128571ec3d6Sbellard #endif
129571ec3d6Sbellard     if (!sw->rate) {
130571ec3d6Sbellard         qemu_free (sw->buf);
131571ec3d6Sbellard         sw->buf = NULL;
132571ec3d6Sbellard         return -1;
133571ec3d6Sbellard     }
134571ec3d6Sbellard     return 0;
135571ec3d6Sbellard }
136571ec3d6Sbellard 
137571ec3d6Sbellard static int glue (audio_pcm_sw_init_, TYPE) (
138571ec3d6Sbellard     SW *sw,
139571ec3d6Sbellard     HW *hw,
140571ec3d6Sbellard     const char *name,
1411ea879e5Smalc     struct audsettings *as
142571ec3d6Sbellard     )
143571ec3d6Sbellard {
144571ec3d6Sbellard     int err;
145571ec3d6Sbellard 
146d929eba5Sbellard     audio_pcm_init_info (&sw->info, as);
147571ec3d6Sbellard     sw->hw = hw;
148571ec3d6Sbellard     sw->active = 0;
149571ec3d6Sbellard #ifdef DAC
150571ec3d6Sbellard     sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
151571ec3d6Sbellard     sw->total_hw_samples_mixed = 0;
152571ec3d6Sbellard     sw->empty = 1;
153571ec3d6Sbellard #else
154571ec3d6Sbellard     sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
155571ec3d6Sbellard #endif
156571ec3d6Sbellard 
157571ec3d6Sbellard #ifdef DAC
158571ec3d6Sbellard     sw->conv = mixeng_conv
159571ec3d6Sbellard #else
160571ec3d6Sbellard     sw->clip = mixeng_clip
161571ec3d6Sbellard #endif
162571ec3d6Sbellard         [sw->info.nchannels == 2]
163571ec3d6Sbellard         [sw->info.sign]
164d929eba5Sbellard         [sw->info.swap_endianness]
165f941aa25Sths         [audio_bits_to_index (sw->info.bits)];
166571ec3d6Sbellard 
167571ec3d6Sbellard     sw->name = qemu_strdup (name);
168571ec3d6Sbellard     err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
169571ec3d6Sbellard     if (err) {
170571ec3d6Sbellard         qemu_free (sw->name);
171571ec3d6Sbellard         sw->name = NULL;
172571ec3d6Sbellard     }
173571ec3d6Sbellard     return err;
174571ec3d6Sbellard }
175571ec3d6Sbellard 
1761d14ffa9Sbellard static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
1771d14ffa9Sbellard {
1781d14ffa9Sbellard     glue (audio_pcm_sw_free_resources_, TYPE) (sw);
1791d14ffa9Sbellard     if (sw->name) {
1801d14ffa9Sbellard         qemu_free (sw->name);
1811d14ffa9Sbellard         sw->name = NULL;
1821d14ffa9Sbellard     }
1831d14ffa9Sbellard }
1841d14ffa9Sbellard 
1851d14ffa9Sbellard static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
1861d14ffa9Sbellard {
18772cf2d4fSBlue Swirl     QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
1881d14ffa9Sbellard }
1891d14ffa9Sbellard 
1901d14ffa9Sbellard static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
1911d14ffa9Sbellard {
19272cf2d4fSBlue Swirl     QLIST_REMOVE (sw, entries);
1931d14ffa9Sbellard }
1941d14ffa9Sbellard 
1951a7dafceSmalc static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
1961d14ffa9Sbellard {
1971a7dafceSmalc     AudioState *s = &glob_audio_state;
198c0fe3827Sbellard     HW *hw = *hwp;
199c0fe3827Sbellard 
200c0fe3827Sbellard     if (!hw->sw_head.lh_first) {
2018ead62cfSbellard #ifdef DAC
2028ead62cfSbellard         audio_detach_capture (hw);
2038ead62cfSbellard #endif
20472cf2d4fSBlue Swirl         QLIST_REMOVE (hw, entries);
205c0fe3827Sbellard         glue (s->nb_hw_voices_, TYPE) += 1;
2061d14ffa9Sbellard         glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
2071d14ffa9Sbellard         glue (hw->pcm_ops->fini_, TYPE) (hw);
208c0fe3827Sbellard         qemu_free (hw);
209c0fe3827Sbellard         *hwp = NULL;
2101d14ffa9Sbellard     }
2111d14ffa9Sbellard }
2121d14ffa9Sbellard 
2131a7dafceSmalc static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
2141d14ffa9Sbellard {
2151a7dafceSmalc     AudioState *s = &glob_audio_state;
2161a7dafceSmalc     return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
2171d14ffa9Sbellard }
2181d14ffa9Sbellard 
2191a7dafceSmalc static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
2201d14ffa9Sbellard {
2211a7dafceSmalc     while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
222c0fe3827Sbellard         if (hw->enabled) {
2231d14ffa9Sbellard             return hw;
2241d14ffa9Sbellard         }
2251d14ffa9Sbellard     }
2261d14ffa9Sbellard     return NULL;
2271d14ffa9Sbellard }
2281d14ffa9Sbellard 
2291d14ffa9Sbellard static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
2301d14ffa9Sbellard     HW *hw,
2311ea879e5Smalc     struct audsettings *as
2321d14ffa9Sbellard     )
2331d14ffa9Sbellard {
2341a7dafceSmalc     while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
235c0fe3827Sbellard         if (audio_pcm_info_eq (&hw->info, as)) {
2361d14ffa9Sbellard             return hw;
2371d14ffa9Sbellard         }
2381d14ffa9Sbellard     }
2391d14ffa9Sbellard     return NULL;
2401d14ffa9Sbellard }
2411d14ffa9Sbellard 
2421a7dafceSmalc static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
2431d14ffa9Sbellard {
2441d14ffa9Sbellard     HW *hw;
2451a7dafceSmalc     AudioState *s = &glob_audio_state;
246571ec3d6Sbellard     struct audio_driver *drv = s->drv;
2471d14ffa9Sbellard 
248571ec3d6Sbellard     if (!glue (s->nb_hw_voices_, TYPE)) {
2491d14ffa9Sbellard         return NULL;
2501d14ffa9Sbellard     }
2511d14ffa9Sbellard 
252571ec3d6Sbellard     if (audio_bug (AUDIO_FUNC, !drv)) {
253571ec3d6Sbellard         dolog ("No host audio driver\n");
2541d14ffa9Sbellard         return NULL;
2551d14ffa9Sbellard     }
256571ec3d6Sbellard 
257571ec3d6Sbellard     if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
258571ec3d6Sbellard         dolog ("Host audio driver without pcm_ops\n");
259571ec3d6Sbellard         return NULL;
260571ec3d6Sbellard     }
261571ec3d6Sbellard 
262571ec3d6Sbellard     hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
263571ec3d6Sbellard     if (!hw) {
264571ec3d6Sbellard         dolog ("Can not allocate voice `%s' size %d\n",
265571ec3d6Sbellard                drv->name, glue (drv->voice_size_, TYPE));
266571ec3d6Sbellard         return NULL;
267571ec3d6Sbellard     }
268571ec3d6Sbellard 
269571ec3d6Sbellard     hw->pcm_ops = drv->pcm_ops;
27072cf2d4fSBlue Swirl     QLIST_INIT (&hw->sw_head);
2718ead62cfSbellard #ifdef DAC
27272cf2d4fSBlue Swirl     QLIST_INIT (&hw->cap_head);
2738ead62cfSbellard #endif
274571ec3d6Sbellard     if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
275571ec3d6Sbellard         goto err0;
276571ec3d6Sbellard     }
277571ec3d6Sbellard 
278571ec3d6Sbellard     if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
279571ec3d6Sbellard         dolog ("hw->samples=%d\n", hw->samples);
280571ec3d6Sbellard         goto err1;
281571ec3d6Sbellard     }
282571ec3d6Sbellard 
283571ec3d6Sbellard #ifdef DAC
284571ec3d6Sbellard     hw->clip = mixeng_clip
285571ec3d6Sbellard #else
286571ec3d6Sbellard     hw->conv = mixeng_conv
287571ec3d6Sbellard #endif
288571ec3d6Sbellard         [hw->info.nchannels == 2]
289571ec3d6Sbellard         [hw->info.sign]
290d929eba5Sbellard         [hw->info.swap_endianness]
291f941aa25Sths         [audio_bits_to_index (hw->info.bits)];
292571ec3d6Sbellard 
293571ec3d6Sbellard     if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
294571ec3d6Sbellard         goto err1;
295571ec3d6Sbellard     }
296571ec3d6Sbellard 
29772cf2d4fSBlue Swirl     QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
298571ec3d6Sbellard     glue (s->nb_hw_voices_, TYPE) -= 1;
2998ead62cfSbellard #ifdef DAC
3001a7dafceSmalc     audio_attach_capture (hw);
3018ead62cfSbellard #endif
3021d14ffa9Sbellard     return hw;
3031d14ffa9Sbellard 
304571ec3d6Sbellard  err1:
305571ec3d6Sbellard     glue (hw->pcm_ops->fini_, TYPE) (hw);
306571ec3d6Sbellard  err0:
307571ec3d6Sbellard     qemu_free (hw);
3081d14ffa9Sbellard     return NULL;
3091d14ffa9Sbellard }
3101d14ffa9Sbellard 
3111a7dafceSmalc static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
3121d14ffa9Sbellard {
3131d14ffa9Sbellard     HW *hw;
3141d14ffa9Sbellard 
315c0fe3827Sbellard     if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
3161a7dafceSmalc         hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
3171d14ffa9Sbellard         if (hw) {
3181d14ffa9Sbellard             return hw;
3191d14ffa9Sbellard         }
3201d14ffa9Sbellard     }
3211d14ffa9Sbellard 
3221a7dafceSmalc     hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
3231d14ffa9Sbellard     if (hw) {
3241d14ffa9Sbellard         return hw;
3251d14ffa9Sbellard     }
3261d14ffa9Sbellard 
3271a7dafceSmalc     hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
3281d14ffa9Sbellard     if (hw) {
3291d14ffa9Sbellard         return hw;
3301d14ffa9Sbellard     }
3311d14ffa9Sbellard 
3321a7dafceSmalc     return glue (audio_pcm_hw_find_any_, TYPE) (NULL);
3331d14ffa9Sbellard }
3341d14ffa9Sbellard 
3351d14ffa9Sbellard static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
336c0fe3827Sbellard     const char *sw_name,
3371ea879e5Smalc     struct audsettings *as
3381d14ffa9Sbellard     )
3391d14ffa9Sbellard {
3401d14ffa9Sbellard     SW *sw;
3411d14ffa9Sbellard     HW *hw;
3421ea879e5Smalc     struct audsettings hw_as;
3431d14ffa9Sbellard 
344c0fe3827Sbellard     if (glue (conf.fixed_, TYPE).enabled) {
345c0fe3827Sbellard         hw_as = glue (conf.fixed_, TYPE).settings;
346c0fe3827Sbellard     }
347c0fe3827Sbellard     else {
348c0fe3827Sbellard         hw_as = *as;
3491d14ffa9Sbellard     }
3501d14ffa9Sbellard 
351c0fe3827Sbellard     sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
3521d14ffa9Sbellard     if (!sw) {
353e7cad338Sbellard         dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
354c0fe3827Sbellard                sw_name ? sw_name : "unknown", sizeof (*sw));
3551d14ffa9Sbellard         goto err1;
3561d14ffa9Sbellard     }
3571d14ffa9Sbellard 
3581a7dafceSmalc     hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as);
3591d14ffa9Sbellard     if (!hw) {
3601d14ffa9Sbellard         goto err2;
3611d14ffa9Sbellard     }
3621d14ffa9Sbellard 
3631d14ffa9Sbellard     glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
3641d14ffa9Sbellard 
365d929eba5Sbellard     if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
3661d14ffa9Sbellard         goto err3;
3671d14ffa9Sbellard     }
3681d14ffa9Sbellard 
3691d14ffa9Sbellard     return sw;
3701d14ffa9Sbellard 
3711d14ffa9Sbellard err3:
3721d14ffa9Sbellard     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
3731a7dafceSmalc     glue (audio_pcm_hw_gc_, TYPE) (&hw);
3741d14ffa9Sbellard err2:
3751d14ffa9Sbellard     qemu_free (sw);
3761d14ffa9Sbellard err1:
3771d14ffa9Sbellard     return NULL;
3781d14ffa9Sbellard }
3791d14ffa9Sbellard 
3801a7dafceSmalc static void glue (audio_close_, TYPE) (SW *sw)
3811d14ffa9Sbellard {
3821d14ffa9Sbellard     glue (audio_pcm_sw_fini_, TYPE) (sw);
3831d14ffa9Sbellard     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
3841a7dafceSmalc     glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
3851d14ffa9Sbellard     qemu_free (sw);
3861d14ffa9Sbellard }
387571ec3d6Sbellard 
388c0fe3827Sbellard void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
389c0fe3827Sbellard {
390c0fe3827Sbellard     if (sw) {
3911a7dafceSmalc         if (audio_bug (AUDIO_FUNC, !card)) {
3921a7dafceSmalc             dolog ("card=%p\n", card);
393c0fe3827Sbellard             return;
394c0fe3827Sbellard         }
395c0fe3827Sbellard 
3961a7dafceSmalc         glue (audio_close_, TYPE) (sw);
397c0fe3827Sbellard     }
3981d14ffa9Sbellard }
3991d14ffa9Sbellard 
4001d14ffa9Sbellard SW *glue (AUD_open_, TYPE) (
401c0fe3827Sbellard     QEMUSoundCard *card,
4021d14ffa9Sbellard     SW *sw,
4031d14ffa9Sbellard     const char *name,
4041d14ffa9Sbellard     void *callback_opaque ,
405cb4f03e8Smalc     audio_callback_fn callback_fn,
4061ea879e5Smalc     struct audsettings *as
4071d14ffa9Sbellard     )
4081d14ffa9Sbellard {
4091a7dafceSmalc     AudioState *s = &glob_audio_state;
4101d14ffa9Sbellard #ifdef DAC
4111d14ffa9Sbellard     int live = 0;
4121d14ffa9Sbellard     SW *old_sw = NULL;
4131d14ffa9Sbellard #endif
4141d14ffa9Sbellard 
415c0fe3827Sbellard     ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
416c0fe3827Sbellard             name, as->freq, as->nchannels, as->fmt);
417c0fe3827Sbellard 
4181a7dafceSmalc     if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
4191a7dafceSmalc         dolog ("card=%p name=%p callback_fn=%p as=%p\n",
4201a7dafceSmalc                card, name, callback_fn, as);
4211d14ffa9Sbellard         goto fail;
4221d14ffa9Sbellard     }
4231d14ffa9Sbellard 
424ec36b695Sbellard     if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
425c0fe3827Sbellard         audio_print_settings (as);
4261d14ffa9Sbellard         goto fail;
4271d14ffa9Sbellard     }
4281d14ffa9Sbellard 
429c0fe3827Sbellard     if (audio_bug (AUDIO_FUNC, !s->drv)) {
430c0fe3827Sbellard         dolog ("Can not open `%s' (no host audio driver)\n", name);
4311d14ffa9Sbellard         goto fail;
4321d14ffa9Sbellard     }
4331d14ffa9Sbellard 
434c0fe3827Sbellard     if (sw && audio_pcm_info_eq (&sw->info, as)) {
4351d14ffa9Sbellard         return sw;
4361d14ffa9Sbellard     }
4371d14ffa9Sbellard 
4381d14ffa9Sbellard #ifdef DAC
439c0fe3827Sbellard     if (conf.plive && sw && (!sw->active && !sw->empty)) {
4401d14ffa9Sbellard         live = sw->total_hw_samples_mixed;
4411d14ffa9Sbellard 
4421d14ffa9Sbellard #ifdef DEBUG_PLIVE
443c0fe3827Sbellard         dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
4441d14ffa9Sbellard         dolog ("Old %s freq %d, bits %d, channels %d\n",
445c0fe3827Sbellard                SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
4461d14ffa9Sbellard         dolog ("New %s freq %d, bits %d, channels %d\n",
447c0fe3827Sbellard                name,
448*a244eb74SJuan Quintela                as->freq,
449*a244eb74SJuan Quintela                (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8,
450*a244eb74SJuan Quintela                as->nchannels);
4511d14ffa9Sbellard #endif
4521d14ffa9Sbellard 
4531d14ffa9Sbellard         if (live) {
4541d14ffa9Sbellard             old_sw = sw;
4551d14ffa9Sbellard             old_sw->callback.fn = NULL;
4561d14ffa9Sbellard             sw = NULL;
4571d14ffa9Sbellard         }
4581d14ffa9Sbellard     }
4591d14ffa9Sbellard #endif
4601d14ffa9Sbellard 
461c0fe3827Sbellard     if (!glue (conf.fixed_, TYPE).enabled && sw) {
462c0fe3827Sbellard         glue (AUD_close_, TYPE) (card, sw);
4631d14ffa9Sbellard         sw = NULL;
4641d14ffa9Sbellard     }
4651d14ffa9Sbellard 
4661d14ffa9Sbellard     if (sw) {
4671d14ffa9Sbellard         HW *hw = sw->hw;
4681d14ffa9Sbellard 
4691d14ffa9Sbellard         if (!hw) {
470c0fe3827Sbellard             dolog ("Internal logic error voice `%s' has no hardware store\n",
471c0fe3827Sbellard                    SW_NAME (sw));
4721d14ffa9Sbellard             goto fail;
4731d14ffa9Sbellard         }
4741d14ffa9Sbellard 
475571ec3d6Sbellard         glue (audio_pcm_sw_fini_, TYPE) (sw);
476d929eba5Sbellard         if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
4771d14ffa9Sbellard             goto fail;
4781d14ffa9Sbellard         }
4791d14ffa9Sbellard     }
4801d14ffa9Sbellard     else {
4811a7dafceSmalc         sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
4821d14ffa9Sbellard         if (!sw) {
483c0fe3827Sbellard             dolog ("Failed to create voice `%s'\n", name);
484571ec3d6Sbellard             return NULL;
4851d14ffa9Sbellard         }
4861d14ffa9Sbellard     }
4871d14ffa9Sbellard 
4881a7dafceSmalc     sw->card = card;
4891d14ffa9Sbellard     sw->vol = nominal_volume;
4901d14ffa9Sbellard     sw->callback.fn = callback_fn;
4911d14ffa9Sbellard     sw->callback.opaque = callback_opaque;
4921d14ffa9Sbellard 
4931d14ffa9Sbellard #ifdef DAC
4941d14ffa9Sbellard     if (live) {
4951d14ffa9Sbellard         int mixed =
4961d14ffa9Sbellard             (live << old_sw->info.shift)
4971d14ffa9Sbellard             * old_sw->info.bytes_per_second
4981d14ffa9Sbellard             / sw->info.bytes_per_second;
4991d14ffa9Sbellard 
5001d14ffa9Sbellard #ifdef DEBUG_PLIVE
5011d14ffa9Sbellard         dolog ("Silence will be mixed %d\n", mixed);
5021d14ffa9Sbellard #endif
5031d14ffa9Sbellard         sw->total_hw_samples_mixed += mixed;
5041d14ffa9Sbellard     }
5051d14ffa9Sbellard #endif
5061d14ffa9Sbellard 
5071d14ffa9Sbellard #ifdef DEBUG_AUDIO
5081d14ffa9Sbellard     dolog ("%s\n", name);
5091d14ffa9Sbellard     audio_pcm_print_info ("hw", &sw->hw->info);
5101d14ffa9Sbellard     audio_pcm_print_info ("sw", &sw->info);
5111d14ffa9Sbellard #endif
5121d14ffa9Sbellard 
5131d14ffa9Sbellard     return sw;
5141d14ffa9Sbellard 
5151d14ffa9Sbellard  fail:
516c0fe3827Sbellard     glue (AUD_close_, TYPE) (card, sw);
5171d14ffa9Sbellard     return NULL;
5181d14ffa9Sbellard }
5191d14ffa9Sbellard 
5201d14ffa9Sbellard int glue (AUD_is_active_, TYPE) (SW *sw)
5211d14ffa9Sbellard {
5221d14ffa9Sbellard     return sw ? sw->active : 0;
5231d14ffa9Sbellard }
5241d14ffa9Sbellard 
5251d14ffa9Sbellard void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
5261d14ffa9Sbellard {
5271d14ffa9Sbellard     if (!sw) {
5281d14ffa9Sbellard         return;
5291d14ffa9Sbellard     }
5301d14ffa9Sbellard 
5311d14ffa9Sbellard     ts->old_ts = sw->hw->ts_helper;
5321d14ffa9Sbellard }
5331d14ffa9Sbellard 
534c0fe3827Sbellard uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
5351d14ffa9Sbellard {
5361d14ffa9Sbellard     uint64_t delta, cur_ts, old_ts;
5371d14ffa9Sbellard 
5381d14ffa9Sbellard     if (!sw) {
5391d14ffa9Sbellard         return 0;
5401d14ffa9Sbellard     }
5411d14ffa9Sbellard 
5421d14ffa9Sbellard     cur_ts = sw->hw->ts_helper;
5431d14ffa9Sbellard     old_ts = ts->old_ts;
5448ead62cfSbellard     /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
5451d14ffa9Sbellard 
5461d14ffa9Sbellard     if (cur_ts >= old_ts) {
5471d14ffa9Sbellard         delta = cur_ts - old_ts;
5481d14ffa9Sbellard     }
5491d14ffa9Sbellard     else {
5501d14ffa9Sbellard         delta = UINT64_MAX - old_ts + cur_ts;
5511d14ffa9Sbellard     }
5521d14ffa9Sbellard 
5531d14ffa9Sbellard     if (!delta) {
5541d14ffa9Sbellard         return 0;
5551d14ffa9Sbellard     }
5561d14ffa9Sbellard 
5574f4cc0efSmalc     return muldiv64 (delta, sw->hw->info.freq, 1000000);
5581d14ffa9Sbellard }
5591d14ffa9Sbellard 
5601d14ffa9Sbellard #undef TYPE
5611d14ffa9Sbellard #undef HW
5621d14ffa9Sbellard #undef SW
563571ec3d6Sbellard #undef HWBUF
564571ec3d6Sbellard #undef NAME
565