xref: /qemu/audio/audio_template.h (revision d1670b20dc007c17760b076c0475eedb3d20f270)
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 
39526fb058SKővágó, Zoltán static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
40526fb058SKővágó, Zoltán                                               struct audio_driver *drv)
41c0fe3827Sbellard {
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 
60470bcabdSAlistair Francis     if (audio_bug(__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 
66470bcabdSAlistair Francis     if (audio_bug(__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 {
74ff095e52SKővágó, Zoltán     g_free(hw->buf_emul);
757267c094SAnthony Liguori     g_free (HWBUF);
76571ec3d6Sbellard     HWBUF = NULL;
77571ec3d6Sbellard }
78571ec3d6Sbellard 
79dc88e38fSKővágó, Zoltán static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
80571ec3d6Sbellard {
81dc88e38fSKővágó, Zoltán     size_t samples = hw->samples;
82dc88e38fSKővágó, Zoltán     if (audio_bug(__func__, samples == 0)) {
83dc88e38fSKővágó, Zoltán         dolog("Attempted to allocate empty buffer\n");
84c0fe3827Sbellard     }
85c0fe3827Sbellard 
86dc88e38fSKővágó, Zoltán     HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
87dc88e38fSKővágó, Zoltán     HWBUF->size = samples;
88c0fe3827Sbellard }
89c0fe3827Sbellard 
90571ec3d6Sbellard static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
91571ec3d6Sbellard {
927267c094SAnthony Liguori     g_free (sw->buf);
93571ec3d6Sbellard 
94571ec3d6Sbellard     if (sw->rate) {
95571ec3d6Sbellard         st_rate_stop (sw->rate);
96571ec3d6Sbellard     }
97571ec3d6Sbellard 
98571ec3d6Sbellard     sw->buf = NULL;
99571ec3d6Sbellard     sw->rate = NULL;
100571ec3d6Sbellard }
101571ec3d6Sbellard 
102571ec3d6Sbellard static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
103571ec3d6Sbellard {
104571ec3d6Sbellard     int samples;
105571ec3d6Sbellard 
106dc88e38fSKővágó, Zoltán     samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
107571ec3d6Sbellard 
108470bcabdSAlistair Francis     sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
109571ec3d6Sbellard     if (!sw->buf) {
110571ec3d6Sbellard         dolog ("Could not allocate buffer for `%s' (%d samples)\n",
111571ec3d6Sbellard                SW_NAME (sw), samples);
112571ec3d6Sbellard         return -1;
113571ec3d6Sbellard     }
114571ec3d6Sbellard 
115571ec3d6Sbellard #ifdef DAC
116571ec3d6Sbellard     sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
117571ec3d6Sbellard #else
118571ec3d6Sbellard     sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
119571ec3d6Sbellard #endif
120571ec3d6Sbellard     if (!sw->rate) {
1217267c094SAnthony Liguori         g_free (sw->buf);
122571ec3d6Sbellard         sw->buf = NULL;
123571ec3d6Sbellard         return -1;
124571ec3d6Sbellard     }
125571ec3d6Sbellard     return 0;
126571ec3d6Sbellard }
127571ec3d6Sbellard 
128571ec3d6Sbellard static int glue (audio_pcm_sw_init_, TYPE) (
129571ec3d6Sbellard     SW *sw,
130571ec3d6Sbellard     HW *hw,
131571ec3d6Sbellard     const char *name,
1321ea879e5Smalc     struct audsettings *as
133571ec3d6Sbellard     )
134571ec3d6Sbellard {
135571ec3d6Sbellard     int err;
136571ec3d6Sbellard 
137d929eba5Sbellard     audio_pcm_init_info (&sw->info, as);
138571ec3d6Sbellard     sw->hw = hw;
139571ec3d6Sbellard     sw->active = 0;
140571ec3d6Sbellard #ifdef DAC
141571ec3d6Sbellard     sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
142571ec3d6Sbellard     sw->total_hw_samples_mixed = 0;
143571ec3d6Sbellard     sw->empty = 1;
144571ec3d6Sbellard #else
145571ec3d6Sbellard     sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
146571ec3d6Sbellard #endif
147571ec3d6Sbellard 
148571ec3d6Sbellard #ifdef DAC
149571ec3d6Sbellard     sw->conv = mixeng_conv
150571ec3d6Sbellard #else
151571ec3d6Sbellard     sw->clip = mixeng_clip
152571ec3d6Sbellard #endif
153571ec3d6Sbellard         [sw->info.nchannels == 2]
154571ec3d6Sbellard         [sw->info.sign]
155d929eba5Sbellard         [sw->info.swap_endianness]
156f941aa25Sths         [audio_bits_to_index (sw->info.bits)];
157571ec3d6Sbellard 
1587267c094SAnthony Liguori     sw->name = g_strdup (name);
159571ec3d6Sbellard     err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
160571ec3d6Sbellard     if (err) {
1617267c094SAnthony Liguori         g_free (sw->name);
162571ec3d6Sbellard         sw->name = NULL;
163571ec3d6Sbellard     }
164571ec3d6Sbellard     return err;
165571ec3d6Sbellard }
166571ec3d6Sbellard 
1671d14ffa9Sbellard static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
1681d14ffa9Sbellard {
1691d14ffa9Sbellard     glue (audio_pcm_sw_free_resources_, TYPE) (sw);
1707267c094SAnthony Liguori     g_free (sw->name);
1711d14ffa9Sbellard     sw->name = NULL;
1721d14ffa9Sbellard }
1731d14ffa9Sbellard 
1741d14ffa9Sbellard static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
1751d14ffa9Sbellard {
17672cf2d4fSBlue Swirl     QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
1771d14ffa9Sbellard }
1781d14ffa9Sbellard 
1791d14ffa9Sbellard static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
1801d14ffa9Sbellard {
18172cf2d4fSBlue Swirl     QLIST_REMOVE (sw, entries);
1821d14ffa9Sbellard }
1831d14ffa9Sbellard 
1841a7dafceSmalc static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
1851d14ffa9Sbellard {
186c0fe3827Sbellard     HW *hw = *hwp;
187526fb058SKővágó, Zoltán     AudioState *s = hw->s;
188c0fe3827Sbellard 
189c0fe3827Sbellard     if (!hw->sw_head.lh_first) {
1908ead62cfSbellard #ifdef DAC
1918ead62cfSbellard         audio_detach_capture (hw);
1928ead62cfSbellard #endif
19372cf2d4fSBlue Swirl         QLIST_REMOVE (hw, entries);
194b28fb27bSPeter Maydell         glue (hw->pcm_ops->fini_, TYPE) (hw);
195c0fe3827Sbellard         glue (s->nb_hw_voices_, TYPE) += 1;
1961d14ffa9Sbellard         glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
1977267c094SAnthony Liguori         g_free (hw);
198c0fe3827Sbellard         *hwp = NULL;
1991d14ffa9Sbellard     }
2001d14ffa9Sbellard }
2011d14ffa9Sbellard 
202526fb058SKővágó, Zoltán static HW *glue(audio_pcm_hw_find_any_, TYPE)(AudioState *s, HW *hw)
2031d14ffa9Sbellard {
2041a7dafceSmalc     return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
2051d14ffa9Sbellard }
2061d14ffa9Sbellard 
207526fb058SKővágó, Zoltán static HW *glue(audio_pcm_hw_find_any_enabled_, TYPE)(AudioState *s, HW *hw)
2081d14ffa9Sbellard {
209526fb058SKővágó, Zoltán     while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
210c0fe3827Sbellard         if (hw->enabled) {
2111d14ffa9Sbellard             return hw;
2121d14ffa9Sbellard         }
2131d14ffa9Sbellard     }
2141d14ffa9Sbellard     return NULL;
2151d14ffa9Sbellard }
2161d14ffa9Sbellard 
217526fb058SKővágó, Zoltán static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
218526fb058SKővágó, Zoltán                                                    struct audsettings *as)
2191d14ffa9Sbellard {
220526fb058SKővágó, Zoltán     while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
221c0fe3827Sbellard         if (audio_pcm_info_eq (&hw->info, as)) {
2221d14ffa9Sbellard             return hw;
2231d14ffa9Sbellard         }
2241d14ffa9Sbellard     }
2251d14ffa9Sbellard     return NULL;
2261d14ffa9Sbellard }
2271d14ffa9Sbellard 
228526fb058SKővágó, Zoltán static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
229526fb058SKővágó, Zoltán                                              struct audsettings *as)
2301d14ffa9Sbellard {
2311d14ffa9Sbellard     HW *hw;
232571ec3d6Sbellard     struct audio_driver *drv = s->drv;
2331d14ffa9Sbellard 
234571ec3d6Sbellard     if (!glue (s->nb_hw_voices_, TYPE)) {
2351d14ffa9Sbellard         return NULL;
2361d14ffa9Sbellard     }
2371d14ffa9Sbellard 
238470bcabdSAlistair Francis     if (audio_bug(__func__, !drv)) {
239571ec3d6Sbellard         dolog ("No host audio driver\n");
2401d14ffa9Sbellard         return NULL;
2411d14ffa9Sbellard     }
242571ec3d6Sbellard 
243470bcabdSAlistair Francis     if (audio_bug(__func__, !drv->pcm_ops)) {
244571ec3d6Sbellard         dolog ("Host audio driver without pcm_ops\n");
245571ec3d6Sbellard         return NULL;
246571ec3d6Sbellard     }
247571ec3d6Sbellard 
248470bcabdSAlistair Francis     hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
249571ec3d6Sbellard     if (!hw) {
250571ec3d6Sbellard         dolog ("Can not allocate voice `%s' size %d\n",
251571ec3d6Sbellard                drv->name, glue (drv->voice_size_, TYPE));
252571ec3d6Sbellard         return NULL;
253571ec3d6Sbellard     }
254571ec3d6Sbellard 
255526fb058SKővágó, Zoltán     hw->s = s;
256571ec3d6Sbellard     hw->pcm_ops = drv->pcm_ops;
257c01b2456SMarc-André Lureau 
25872cf2d4fSBlue Swirl     QLIST_INIT (&hw->sw_head);
2598ead62cfSbellard #ifdef DAC
26072cf2d4fSBlue Swirl     QLIST_INIT (&hw->cap_head);
2618ead62cfSbellard #endif
2625706db1dSKővágó, Zoltán     if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) {
263571ec3d6Sbellard         goto err0;
264571ec3d6Sbellard     }
265571ec3d6Sbellard 
266470bcabdSAlistair Francis     if (audio_bug(__func__, hw->samples <= 0)) {
2677520462bSKővágó, Zoltán         dolog("hw->samples=%zd\n", hw->samples);
268571ec3d6Sbellard         goto err1;
269571ec3d6Sbellard     }
270571ec3d6Sbellard 
271571ec3d6Sbellard #ifdef DAC
272571ec3d6Sbellard     hw->clip = mixeng_clip
273571ec3d6Sbellard #else
274571ec3d6Sbellard     hw->conv = mixeng_conv
275571ec3d6Sbellard #endif
276571ec3d6Sbellard         [hw->info.nchannels == 2]
277571ec3d6Sbellard         [hw->info.sign]
278d929eba5Sbellard         [hw->info.swap_endianness]
279f941aa25Sths         [audio_bits_to_index (hw->info.bits)];
280571ec3d6Sbellard 
281dc88e38fSKővágó, Zoltán     glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
282571ec3d6Sbellard 
28372cf2d4fSBlue Swirl     QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
284571ec3d6Sbellard     glue (s->nb_hw_voices_, TYPE) -= 1;
2858ead62cfSbellard #ifdef DAC
2861a7dafceSmalc     audio_attach_capture (hw);
2878ead62cfSbellard #endif
2881d14ffa9Sbellard     return hw;
2891d14ffa9Sbellard 
290571ec3d6Sbellard  err1:
291571ec3d6Sbellard     glue (hw->pcm_ops->fini_, TYPE) (hw);
292571ec3d6Sbellard  err0:
2937267c094SAnthony Liguori     g_free (hw);
2941d14ffa9Sbellard     return NULL;
2951d14ffa9Sbellard }
2961d14ffa9Sbellard 
29771830221SKővágó, Zoltán AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
29871830221SKővágó, Zoltán {
29971830221SKővágó, Zoltán     switch (dev->driver) {
30071830221SKővágó, Zoltán     case AUDIODEV_DRIVER_NONE:
30171830221SKővágó, Zoltán         return dev->u.none.TYPE;
30271830221SKővágó, Zoltán     case AUDIODEV_DRIVER_ALSA:
30371830221SKővágó, Zoltán         return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE);
30471830221SKővágó, Zoltán     case AUDIODEV_DRIVER_COREAUDIO:
30571830221SKővágó, Zoltán         return qapi_AudiodevCoreaudioPerDirectionOptions_base(
30671830221SKővágó, Zoltán             dev->u.coreaudio.TYPE);
30771830221SKővágó, Zoltán     case AUDIODEV_DRIVER_DSOUND:
30871830221SKővágó, Zoltán         return dev->u.dsound.TYPE;
30971830221SKővágó, Zoltán     case AUDIODEV_DRIVER_OSS:
31071830221SKővágó, Zoltán         return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
31171830221SKővágó, Zoltán     case AUDIODEV_DRIVER_PA:
31271830221SKővágó, Zoltán         return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
31371830221SKővágó, Zoltán     case AUDIODEV_DRIVER_SDL:
31471830221SKővágó, Zoltán         return dev->u.sdl.TYPE;
31571830221SKővágó, Zoltán     case AUDIODEV_DRIVER_SPICE:
31671830221SKővágó, Zoltán         return dev->u.spice.TYPE;
31771830221SKővágó, Zoltán     case AUDIODEV_DRIVER_WAV:
31871830221SKővágó, Zoltán         return dev->u.wav.TYPE;
31971830221SKővágó, Zoltán 
32071830221SKővágó, Zoltán     case AUDIODEV_DRIVER__MAX:
32171830221SKővágó, Zoltán         break;
32271830221SKővágó, Zoltán     }
32371830221SKővágó, Zoltán     abort();
32471830221SKővágó, Zoltán }
32571830221SKővágó, Zoltán 
326526fb058SKővágó, Zoltán static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as)
3271d14ffa9Sbellard {
3281d14ffa9Sbellard     HW *hw;
32971830221SKővágó, Zoltán     AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
3301d14ffa9Sbellard 
33171830221SKővágó, Zoltán     if (pdo->fixed_settings) {
332526fb058SKővágó, Zoltán         hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
3331d14ffa9Sbellard         if (hw) {
3341d14ffa9Sbellard             return hw;
3351d14ffa9Sbellard         }
3361d14ffa9Sbellard     }
3371d14ffa9Sbellard 
338526fb058SKővágó, Zoltán     hw = glue(audio_pcm_hw_find_specific_, TYPE)(s, NULL, as);
3391d14ffa9Sbellard     if (hw) {
3401d14ffa9Sbellard         return hw;
3411d14ffa9Sbellard     }
3421d14ffa9Sbellard 
343526fb058SKővágó, Zoltán     hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
3441d14ffa9Sbellard     if (hw) {
3451d14ffa9Sbellard         return hw;
3461d14ffa9Sbellard     }
3471d14ffa9Sbellard 
348526fb058SKővágó, Zoltán     return glue(audio_pcm_hw_find_any_, TYPE)(s, NULL);
3491d14ffa9Sbellard }
3501d14ffa9Sbellard 
3511d14ffa9Sbellard static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
352526fb058SKővágó, Zoltán     AudioState *s,
353c0fe3827Sbellard     const char *sw_name,
3541ea879e5Smalc     struct audsettings *as
3551d14ffa9Sbellard     )
3561d14ffa9Sbellard {
3571d14ffa9Sbellard     SW *sw;
3581d14ffa9Sbellard     HW *hw;
3591ea879e5Smalc     struct audsettings hw_as;
36071830221SKővágó, Zoltán     AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
3611d14ffa9Sbellard 
36271830221SKővágó, Zoltán     if (pdo->fixed_settings) {
36371830221SKővágó, Zoltán         hw_as = audiodev_to_audsettings(pdo);
364c0fe3827Sbellard     }
365c0fe3827Sbellard     else {
366c0fe3827Sbellard         hw_as = *as;
3671d14ffa9Sbellard     }
3681d14ffa9Sbellard 
369470bcabdSAlistair Francis     sw = audio_calloc(__func__, 1, sizeof(*sw));
3701d14ffa9Sbellard     if (!sw) {
371e7cad338Sbellard         dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
372c0fe3827Sbellard                sw_name ? sw_name : "unknown", sizeof (*sw));
3731d14ffa9Sbellard         goto err1;
3741d14ffa9Sbellard     }
375526fb058SKővágó, Zoltán     sw->s = s;
3761d14ffa9Sbellard 
377526fb058SKővágó, Zoltán     hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
3781d14ffa9Sbellard     if (!hw) {
3791d14ffa9Sbellard         goto err2;
3801d14ffa9Sbellard     }
3811d14ffa9Sbellard 
3821d14ffa9Sbellard     glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
3831d14ffa9Sbellard 
384d929eba5Sbellard     if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
3851d14ffa9Sbellard         goto err3;
3861d14ffa9Sbellard     }
3871d14ffa9Sbellard 
3881d14ffa9Sbellard     return sw;
3891d14ffa9Sbellard 
3901d14ffa9Sbellard err3:
3911d14ffa9Sbellard     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
3921a7dafceSmalc     glue (audio_pcm_hw_gc_, TYPE) (&hw);
3931d14ffa9Sbellard err2:
3947267c094SAnthony Liguori     g_free (sw);
3951d14ffa9Sbellard err1:
3961d14ffa9Sbellard     return NULL;
3971d14ffa9Sbellard }
3981d14ffa9Sbellard 
3991a7dafceSmalc static void glue (audio_close_, TYPE) (SW *sw)
4001d14ffa9Sbellard {
4011d14ffa9Sbellard     glue (audio_pcm_sw_fini_, TYPE) (sw);
4021d14ffa9Sbellard     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
4031a7dafceSmalc     glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
4047267c094SAnthony Liguori     g_free (sw);
4051d14ffa9Sbellard }
406571ec3d6Sbellard 
407c0fe3827Sbellard void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
408c0fe3827Sbellard {
409c0fe3827Sbellard     if (sw) {
410470bcabdSAlistair Francis         if (audio_bug(__func__, !card)) {
4111a7dafceSmalc             dolog ("card=%p\n", card);
412c0fe3827Sbellard             return;
413c0fe3827Sbellard         }
414c0fe3827Sbellard 
4151a7dafceSmalc         glue (audio_close_, TYPE) (sw);
416c0fe3827Sbellard     }
4171d14ffa9Sbellard }
4181d14ffa9Sbellard 
4191d14ffa9Sbellard SW *glue (AUD_open_, TYPE) (
420c0fe3827Sbellard     QEMUSoundCard *card,
4211d14ffa9Sbellard     SW *sw,
4221d14ffa9Sbellard     const char *name,
4231d14ffa9Sbellard     void *callback_opaque ,
424cb4f03e8Smalc     audio_callback_fn callback_fn,
4251ea879e5Smalc     struct audsettings *as
4261d14ffa9Sbellard     )
4271d14ffa9Sbellard {
428*d1670b20SKővágó, Zoltán     AudioState *s;
429*d1670b20SKővágó, Zoltán     AudiodevPerDirectionOptions *pdo;
4301d14ffa9Sbellard 
431470bcabdSAlistair Francis     if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
4321a7dafceSmalc         dolog ("card=%p name=%p callback_fn=%p as=%p\n",
4331a7dafceSmalc                card, name, callback_fn, as);
4341d14ffa9Sbellard         goto fail;
4351d14ffa9Sbellard     }
4361d14ffa9Sbellard 
437*d1670b20SKővágó, Zoltán     s = card->state;
438*d1670b20SKővágó, Zoltán     pdo = glue(audio_get_pdo_, TYPE)(s->dev);
439*d1670b20SKővágó, Zoltán 
44093b65997SStefan Weil     ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
44193b65997SStefan Weil             name, as->freq, as->nchannels, as->fmt);
44293b65997SStefan Weil 
443470bcabdSAlistair Francis     if (audio_bug(__func__, audio_validate_settings(as))) {
444c0fe3827Sbellard         audio_print_settings (as);
4451d14ffa9Sbellard         goto fail;
4461d14ffa9Sbellard     }
4471d14ffa9Sbellard 
448470bcabdSAlistair Francis     if (audio_bug(__func__, !s->drv)) {
449c0fe3827Sbellard         dolog ("Can not open `%s' (no host audio driver)\n", name);
4501d14ffa9Sbellard         goto fail;
4511d14ffa9Sbellard     }
4521d14ffa9Sbellard 
453c0fe3827Sbellard     if (sw && audio_pcm_info_eq (&sw->info, as)) {
4541d14ffa9Sbellard         return sw;
4551d14ffa9Sbellard     }
4561d14ffa9Sbellard 
45771830221SKővágó, Zoltán     if (!pdo->fixed_settings && sw) {
458c0fe3827Sbellard         glue (AUD_close_, TYPE) (card, sw);
4591d14ffa9Sbellard         sw = NULL;
4601d14ffa9Sbellard     }
4611d14ffa9Sbellard 
4621d14ffa9Sbellard     if (sw) {
4631d14ffa9Sbellard         HW *hw = sw->hw;
4641d14ffa9Sbellard 
4651d14ffa9Sbellard         if (!hw) {
466c0fe3827Sbellard             dolog ("Internal logic error voice `%s' has no hardware store\n",
467c0fe3827Sbellard                    SW_NAME (sw));
4681d14ffa9Sbellard             goto fail;
4691d14ffa9Sbellard         }
4701d14ffa9Sbellard 
471571ec3d6Sbellard         glue (audio_pcm_sw_fini_, TYPE) (sw);
472d929eba5Sbellard         if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
4731d14ffa9Sbellard             goto fail;
4741d14ffa9Sbellard         }
4751d14ffa9Sbellard     }
4761d14ffa9Sbellard     else {
477526fb058SKővágó, Zoltán         sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
4781d14ffa9Sbellard         if (!sw) {
479c0fe3827Sbellard             dolog ("Failed to create voice `%s'\n", name);
480571ec3d6Sbellard             return NULL;
4811d14ffa9Sbellard         }
4821d14ffa9Sbellard     }
4831d14ffa9Sbellard 
4841a7dafceSmalc     sw->card = card;
4851d14ffa9Sbellard     sw->vol = nominal_volume;
4861d14ffa9Sbellard     sw->callback.fn = callback_fn;
4871d14ffa9Sbellard     sw->callback.opaque = callback_opaque;
4881d14ffa9Sbellard 
4891d14ffa9Sbellard #ifdef DEBUG_AUDIO
4901d14ffa9Sbellard     dolog ("%s\n", name);
4911d14ffa9Sbellard     audio_pcm_print_info ("hw", &sw->hw->info);
4921d14ffa9Sbellard     audio_pcm_print_info ("sw", &sw->info);
4931d14ffa9Sbellard #endif
4941d14ffa9Sbellard 
4951d14ffa9Sbellard     return sw;
4961d14ffa9Sbellard 
4971d14ffa9Sbellard  fail:
498c0fe3827Sbellard     glue (AUD_close_, TYPE) (card, sw);
4991d14ffa9Sbellard     return NULL;
5001d14ffa9Sbellard }
5011d14ffa9Sbellard 
5021d14ffa9Sbellard int glue (AUD_is_active_, TYPE) (SW *sw)
5031d14ffa9Sbellard {
5041d14ffa9Sbellard     return sw ? sw->active : 0;
5051d14ffa9Sbellard }
5061d14ffa9Sbellard 
5071d14ffa9Sbellard void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
5081d14ffa9Sbellard {
5091d14ffa9Sbellard     if (!sw) {
5101d14ffa9Sbellard         return;
5111d14ffa9Sbellard     }
5121d14ffa9Sbellard 
5131d14ffa9Sbellard     ts->old_ts = sw->hw->ts_helper;
5141d14ffa9Sbellard }
5151d14ffa9Sbellard 
516c0fe3827Sbellard uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
5171d14ffa9Sbellard {
5181d14ffa9Sbellard     uint64_t delta, cur_ts, old_ts;
5191d14ffa9Sbellard 
5201d14ffa9Sbellard     if (!sw) {
5211d14ffa9Sbellard         return 0;
5221d14ffa9Sbellard     }
5231d14ffa9Sbellard 
5241d14ffa9Sbellard     cur_ts = sw->hw->ts_helper;
5251d14ffa9Sbellard     old_ts = ts->old_ts;
5260bfcd599SBlue Swirl     /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
5271d14ffa9Sbellard 
5281d14ffa9Sbellard     if (cur_ts >= old_ts) {
5291d14ffa9Sbellard         delta = cur_ts - old_ts;
5301d14ffa9Sbellard     }
5311d14ffa9Sbellard     else {
5321d14ffa9Sbellard         delta = UINT64_MAX - old_ts + cur_ts;
5331d14ffa9Sbellard     }
5341d14ffa9Sbellard 
5351d14ffa9Sbellard     if (!delta) {
5361d14ffa9Sbellard         return 0;
5371d14ffa9Sbellard     }
5381d14ffa9Sbellard 
5394f4cc0efSmalc     return muldiv64 (delta, sw->hw->info.freq, 1000000);
5401d14ffa9Sbellard }
5411d14ffa9Sbellard 
5421d14ffa9Sbellard #undef TYPE
5431d14ffa9Sbellard #undef HW
5441d14ffa9Sbellard #undef SW
545571ec3d6Sbellard #undef HWBUF
546571ec3d6Sbellard #undef NAME
547