blob: 7ccfec01168c46a6969f25a1f559824ea054e9f0 [file] [log] [blame]
bellard1d14ffa2005-10-30 18:58:22 +00001/*
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
bellard571ec3d2005-11-20 16:24:34 +000026#define NAME "playback"
27#define HWBUF hw->mix_buf
bellard1d14ffa2005-10-30 18:58:22 +000028#define TYPE out
bellard571ec3d2005-11-20 16:24:34 +000029#define HW HWVoiceOut
30#define SW SWVoiceOut
bellard1d14ffa2005-10-30 18:58:22 +000031#else
bellard571ec3d2005-11-20 16:24:34 +000032#define NAME "capture"
bellard1d14ffa2005-10-30 18:58:22 +000033#define TYPE in
bellard571ec3d2005-11-20 16:24:34 +000034#define HW HWVoiceIn
35#define SW SWVoiceIn
36#define HWBUF hw->conv_buf
bellard1d14ffa2005-10-30 18:58:22 +000037#endif
38
Kővágó, Zoltán526fb052019-08-19 01:06:46 +020039static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
Paolo Bonzini5c63d142023-09-22 18:36:28 +020040 struct audio_driver *drv, int min_voices)
bellardc0fe3822005-11-05 18:55:28 +000041{
bellard571ec3d2005-11-20 16:24:34 +000042 int max_voices = glue (drv->max_voices_, TYPE);
Volker Rümelin3724ab32023-01-21 10:47:31 +010043 size_t voice_size = glue(drv->voice_size_, TYPE);
bellardc0fe3822005-11-05 18:55:28 +000044
Paolo Bonzini5c63d142023-09-22 18:36:28 +020045 glue (s->nb_hw_voices_, TYPE) = glue(audio_get_pdo_, TYPE)(s->dev)->voices;
bellard571ec3d2005-11-20 16:24:34 +000046 if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
47 if (!max_voices) {
bellardc0fe3822005-11-05 18:55:28 +000048#ifdef DAC
bellard571ec3d2005-11-20 16:24:34 +000049 dolog ("Driver `%s' does not support " NAME "\n", drv->name);
bellardc0fe3822005-11-05 18:55:28 +000050#endif
Zhang Han6c6886b2021-01-15 09:24:25 +080051 } else {
bellard571ec3d2005-11-20 16:24:34 +000052 dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
53 drv->name,
54 glue (s->nb_hw_voices_, TYPE),
55 max_voices);
56 }
57 glue (s->nb_hw_voices_, TYPE) = max_voices;
58 }
bellardc0fe3822005-11-05 18:55:28 +000059
Paolo Bonzini5c63d142023-09-22 18:36:28 +020060 if (glue (s->nb_hw_voices_, TYPE) < min_voices) {
61 dolog ("Bogus number of " NAME " voices %d, setting to %d\n",
62 glue (s->nb_hw_voices_, TYPE),
63 min_voices);
64 }
65
Alistair Francis470bcab2018-02-03 09:43:02 +010066 if (audio_bug(__func__, !voice_size && max_voices)) {
bellard571ec3d2005-11-20 16:24:34 +000067 dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
68 drv->name, max_voices);
Volker Rümelin12f4abf2022-09-17 15:16:25 +020069 glue (s->nb_hw_voices_, TYPE) = 0;
bellard571ec3d2005-11-20 16:24:34 +000070 }
71
Alistair Francis470bcab2018-02-03 09:43:02 +010072 if (audio_bug(__func__, voice_size && !max_voices)) {
Volker Rümelin3724ab32023-01-21 10:47:31 +010073 dolog("drv=`%s' voice_size=%zu max_voices=0\n",
74 drv->name, voice_size);
bellard571ec3d2005-11-20 16:24:34 +000075 }
76}
77
78static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
79{
Kővágó, Zoltánff095e52019-09-19 23:24:09 +020080 g_free(hw->buf_emul);
Volker Rümelin8dbd3d12023-02-24 20:05:41 +010081 g_free(HWBUF.buffer);
82 HWBUF.buffer = NULL;
83 HWBUF.size = 0;
bellard571ec3d2005-11-20 16:24:34 +000084}
85
Kővágó, Zoltándc88e382019-09-19 23:24:20 +020086static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
bellard571ec3d2005-11-20 16:24:34 +000087{
Kővágó, Zoltán19306162019-10-13 21:57:59 +020088 if (glue(audio_get_pdo_, TYPE)(hw->s->dev)->mixing_engine) {
89 size_t samples = hw->samples;
90 if (audio_bug(__func__, samples == 0)) {
91 dolog("Attempted to allocate empty buffer\n");
92 }
bellardc0fe3822005-11-05 18:55:28 +000093
Volker Rümelin8dbd3d12023-02-24 20:05:41 +010094 HWBUF.buffer = g_new0(st_sample, samples);
95 HWBUF.size = samples;
96 HWBUF.pos = 0;
Kővágó, Zoltán19306162019-10-13 21:57:59 +020097 } else {
Volker Rümelin8dbd3d12023-02-24 20:05:41 +010098 HWBUF.buffer = NULL;
99 HWBUF.size = 0;
Kővágó, Zoltán19306162019-10-13 21:57:59 +0200100 }
bellardc0fe3822005-11-05 18:55:28 +0000101}
102
bellard571ec3d2005-11-20 16:24:34 +0000103static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
104{
Volker Rümelin2c3f9a02023-02-24 20:05:42 +0100105 g_free(sw->resample_buf.buffer);
106 sw->resample_buf.buffer = NULL;
107 sw->resample_buf.size = 0;
bellard571ec3d2005-11-20 16:24:34 +0000108
109 if (sw->rate) {
110 st_rate_stop (sw->rate);
111 }
bellard571ec3d2005-11-20 16:24:34 +0000112 sw->rate = NULL;
113}
114
115static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
116{
Volker Rümelin148392a2023-02-24 20:05:54 +0100117 HW *hw = sw->hw;
Volker Rümelin2f886a32023-02-24 20:05:55 +0100118 uint64_t samples;
bellard571ec3d2005-11-20 16:24:34 +0000119
Kővágó, Zoltán19306162019-10-13 21:57:59 +0200120 if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
121 return 0;
122 }
123
Volker Rümelin2f886a32023-02-24 20:05:55 +0100124 samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
Volker Rümelinb9ae74e2023-01-21 10:47:25 +0100125 if (samples == 0) {
Volker Rümelin2f886a32023-02-24 20:05:55 +0100126 uint64_t f_fe_min;
127 uint64_t f_be = (uint32_t)hw->info.freq;
Volker Rümelinb9ae74e2023-01-21 10:47:25 +0100128
129 /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
Volker Rümelin2f886a32023-02-24 20:05:55 +0100130 f_fe_min = (f_be + HWBUF.size - 1) / HWBUF.size;
Volker Rümelinb9ae74e2023-01-21 10:47:25 +0100131 qemu_log_mask(LOG_UNIMP,
132 AUDIO_CAP ": The guest selected a " NAME " sample rate"
Volker Rümelin2f886a32023-02-24 20:05:55 +0100133 " of %d Hz for %s. Only sample rates >= %" PRIu64 " Hz"
134 " are supported.\n",
Volker Rümelinb9ae74e2023-01-21 10:47:25 +0100135 sw->info.freq, sw->name, f_fe_min);
136 return -1;
137 }
bellard571ec3d2005-11-20 16:24:34 +0000138
Volker Rümeline1e6a6f2023-02-24 20:05:53 +0100139 /*
140 * Allocate one additional audio frame that is needed for upsampling
141 * if the resample buffer size is small. For large buffer sizes take
Volker Rümelin2f886a32023-02-24 20:05:55 +0100142 * care of overflows and truncation.
Volker Rümeline1e6a6f2023-02-24 20:05:53 +0100143 */
Volker Rümelin2f886a32023-02-24 20:05:55 +0100144 samples = samples < SIZE_MAX ? samples + 1 : SIZE_MAX;
Volker Rümelin2c3f9a02023-02-24 20:05:42 +0100145 sw->resample_buf.buffer = g_new0(st_sample, samples);
146 sw->resample_buf.size = samples;
147 sw->resample_buf.pos = 0;
bellard571ec3d2005-11-20 16:24:34 +0000148
149#ifdef DAC
Volker Rümelin148392a2023-02-24 20:05:54 +0100150 sw->rate = st_rate_start(sw->info.freq, hw->info.freq);
bellard571ec3d2005-11-20 16:24:34 +0000151#else
Volker Rümelin148392a2023-02-24 20:05:54 +0100152 sw->rate = st_rate_start(hw->info.freq, sw->info.freq);
bellard571ec3d2005-11-20 16:24:34 +0000153#endif
Volker Rümelin25bf0c22023-01-21 10:47:29 +0100154
bellard571ec3d2005-11-20 16:24:34 +0000155 return 0;
156}
157
158static int glue (audio_pcm_sw_init_, TYPE) (
159 SW *sw,
160 HW *hw,
161 const char *name,
malc1ea879e2008-12-03 22:48:44 +0000162 struct audsettings *as
bellard571ec3d2005-11-20 16:24:34 +0000163 )
164{
165 int err;
166
bellardd929eba2006-07-04 21:47:22 +0000167 audio_pcm_init_info (&sw->info, as);
bellard571ec3d2005-11-20 16:24:34 +0000168 sw->hw = hw;
169 sw->active = 0;
170#ifdef DAC
bellard571ec3d2005-11-20 16:24:34 +0000171 sw->total_hw_samples_mixed = 0;
172 sw->empty = 1;
bellard571ec3d2005-11-20 16:24:34 +0000173#endif
174
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100175 if (sw->info.is_float) {
bellard571ec3d2005-11-20 16:24:34 +0000176#ifdef DAC
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100177 sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
bellard571ec3d2005-11-20 16:24:34 +0000178#else
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100179 sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
bellard571ec3d2005-11-20 16:24:34 +0000180#endif
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100181 } else {
182#ifdef DAC
183 sw->conv = mixeng_conv
184#else
185 sw->clip = mixeng_clip
186#endif
187 [sw->info.nchannels == 2]
188 [sw->info.is_signed]
189 [sw->info.swap_endianness]
190 [audio_bits_to_index(sw->info.bits)];
191 }
bellard571ec3d2005-11-20 16:24:34 +0000192
Anthony Liguori7267c092011-08-20 22:09:37 -0500193 sw->name = g_strdup (name);
bellard571ec3d2005-11-20 16:24:34 +0000194 err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
195 if (err) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500196 g_free (sw->name);
bellard571ec3d2005-11-20 16:24:34 +0000197 sw->name = NULL;
198 }
199 return err;
200}
201
bellard1d14ffa2005-10-30 18:58:22 +0000202static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
203{
204 glue (audio_pcm_sw_free_resources_, TYPE) (sw);
Markus Armbrusterfb7da622014-06-06 18:35:13 +0200205 g_free (sw->name);
206 sw->name = NULL;
bellard1d14ffa2005-10-30 18:58:22 +0000207}
208
209static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
210{
Blue Swirl72cf2d42009-09-12 07:36:22 +0000211 QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
bellard1d14ffa2005-10-30 18:58:22 +0000212}
213
214static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
215{
Blue Swirl72cf2d42009-09-12 07:36:22 +0000216 QLIST_REMOVE (sw, entries);
bellard1d14ffa2005-10-30 18:58:22 +0000217}
218
malc1a7dafc2009-05-14 03:11:35 +0400219static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
bellard1d14ffa2005-10-30 18:58:22 +0000220{
bellardc0fe3822005-11-05 18:55:28 +0000221 HW *hw = *hwp;
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200222 AudioState *s = hw->s;
bellardc0fe3822005-11-05 18:55:28 +0000223
224 if (!hw->sw_head.lh_first) {
bellard8ead62c2006-07-04 16:51:32 +0000225#ifdef DAC
Zhang Han8abf3fe2021-01-15 09:24:31 +0800226 audio_detach_capture(hw);
bellard8ead62c2006-07-04 16:51:32 +0000227#endif
Zhang Han8abf3fe2021-01-15 09:24:31 +0800228 QLIST_REMOVE(hw, entries);
229 glue(hw->pcm_ops->fini_, TYPE) (hw);
230 glue(s->nb_hw_voices_, TYPE) += 1;
231 glue(audio_pcm_hw_free_resources_ , TYPE) (hw);
232 g_free(hw);
bellardc0fe3822005-11-05 18:55:28 +0000233 *hwp = NULL;
bellard1d14ffa2005-10-30 18:58:22 +0000234 }
235}
236
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200237static HW *glue(audio_pcm_hw_find_any_, TYPE)(AudioState *s, HW *hw)
bellard1d14ffa2005-10-30 18:58:22 +0000238{
malc1a7dafc2009-05-14 03:11:35 +0400239 return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
bellard1d14ffa2005-10-30 18:58:22 +0000240}
241
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200242static HW *glue(audio_pcm_hw_find_any_enabled_, TYPE)(AudioState *s, HW *hw)
bellard1d14ffa2005-10-30 18:58:22 +0000243{
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200244 while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
bellardc0fe3822005-11-05 18:55:28 +0000245 if (hw->enabled) {
bellard1d14ffa2005-10-30 18:58:22 +0000246 return hw;
247 }
248 }
249 return NULL;
250}
251
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200252static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
253 struct audsettings *as)
bellard1d14ffa2005-10-30 18:58:22 +0000254{
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200255 while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
bellardc0fe3822005-11-05 18:55:28 +0000256 if (audio_pcm_info_eq (&hw->info, as)) {
bellard1d14ffa2005-10-30 18:58:22 +0000257 return hw;
258 }
259 }
260 return NULL;
261}
262
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200263static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
264 struct audsettings *as)
bellard1d14ffa2005-10-30 18:58:22 +0000265{
266 HW *hw;
bellard571ec3d2005-11-20 16:24:34 +0000267 struct audio_driver *drv = s->drv;
bellard1d14ffa2005-10-30 18:58:22 +0000268
bellard571ec3d2005-11-20 16:24:34 +0000269 if (!glue (s->nb_hw_voices_, TYPE)) {
270 return NULL;
bellard1d14ffa2005-10-30 18:58:22 +0000271 }
272
Alistair Francis470bcab2018-02-03 09:43:02 +0100273 if (audio_bug(__func__, !drv)) {
bellard571ec3d2005-11-20 16:24:34 +0000274 dolog ("No host audio driver\n");
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200275 return NULL;
bellard571ec3d2005-11-20 16:24:34 +0000276 }
277
Alistair Francis470bcab2018-02-03 09:43:02 +0100278 if (audio_bug(__func__, !drv->pcm_ops)) {
bellard571ec3d2005-11-20 16:24:34 +0000279 dolog ("Host audio driver without pcm_ops\n");
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200280 return NULL;
bellard571ec3d2005-11-20 16:24:34 +0000281 }
282
Volker Rümelin3724ab32023-01-21 10:47:31 +0100283 /*
284 * Since glue(s->nb_hw_voices_, TYPE) is != 0, glue(drv->voice_size_, TYPE)
285 * is guaranteed to be != 0. See the audio_init_nb_voices_* functions.
286 */
287 hw = g_malloc0(glue(drv->voice_size_, TYPE));
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200288 hw->s = s;
bellard571ec3d2005-11-20 16:24:34 +0000289 hw->pcm_ops = drv->pcm_ops;
Marc-André Lureauc01b2452012-04-17 14:32:36 +0200290
Blue Swirl72cf2d42009-09-12 07:36:22 +0000291 QLIST_INIT (&hw->sw_head);
bellard8ead62c2006-07-04 16:51:32 +0000292#ifdef DAC
Blue Swirl72cf2d42009-09-12 07:36:22 +0000293 QLIST_INIT (&hw->cap_head);
bellard8ead62c2006-07-04 16:51:32 +0000294#endif
Kővágó, Zoltán5706db12015-06-03 23:03:47 +0200295 if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) {
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200296 goto err0;
bellard571ec3d2005-11-20 16:24:34 +0000297 }
298
Alistair Francis470bcab2018-02-03 09:43:02 +0100299 if (audio_bug(__func__, hw->samples <= 0)) {
Kővágó, Zoltán75204622019-08-19 01:06:58 +0200300 dolog("hw->samples=%zd\n", hw->samples);
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200301 goto err1;
bellard571ec3d2005-11-20 16:24:34 +0000302 }
303
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100304 if (hw->info.is_float) {
Volker Rümelin180b0442020-02-02 15:06:41 +0100305#ifdef DAC
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100306 hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
Volker Rümelin180b0442020-02-02 15:06:41 +0100307#else
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100308 hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
Volker Rümelin180b0442020-02-02 15:06:41 +0100309#endif
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100310 } else {
bellard571ec3d2005-11-20 16:24:34 +0000311#ifdef DAC
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100312 hw->clip = mixeng_clip
bellard571ec3d2005-11-20 16:24:34 +0000313#else
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100314 hw->conv = mixeng_conv
bellard571ec3d2005-11-20 16:24:34 +0000315#endif
Kővágó, Zoltáned2a4a72020-02-02 20:38:07 +0100316 [hw->info.nchannels == 2]
317 [hw->info.is_signed]
318 [hw->info.swap_endianness]
319 [audio_bits_to_index(hw->info.bits)];
320 }
bellard571ec3d2005-11-20 16:24:34 +0000321
Kővágó, Zoltándc88e382019-09-19 23:24:20 +0200322 glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
bellard571ec3d2005-11-20 16:24:34 +0000323
Blue Swirl72cf2d42009-09-12 07:36:22 +0000324 QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
bellard571ec3d2005-11-20 16:24:34 +0000325 glue (s->nb_hw_voices_, TYPE) -= 1;
bellard8ead62c2006-07-04 16:51:32 +0000326#ifdef DAC
malc1a7dafc2009-05-14 03:11:35 +0400327 audio_attach_capture (hw);
bellard8ead62c2006-07-04 16:51:32 +0000328#endif
bellard571ec3d2005-11-20 16:24:34 +0000329 return hw;
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200330
331 err1:
332 glue (hw->pcm_ops->fini_, TYPE) (hw);
333 err0:
334 g_free (hw);
335 return NULL;
bellard1d14ffa2005-10-30 18:58:22 +0000336}
337
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100338AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
339{
340 switch (dev->driver) {
341 case AUDIODEV_DRIVER_NONE:
342 return dev->u.none.TYPE;
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100343#ifdef CONFIG_AUDIO_ALSA
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100344 case AUDIODEV_DRIVER_ALSA:
345 return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE);
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100346#endif
347#ifdef CONFIG_AUDIO_COREAUDIO
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100348 case AUDIODEV_DRIVER_COREAUDIO:
349 return qapi_AudiodevCoreaudioPerDirectionOptions_base(
350 dev->u.coreaudio.TYPE);
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100351#endif
352#ifdef CONFIG_DBUS_DISPLAY
Marc-André Lureau739362d2021-03-09 17:15:28 +0400353 case AUDIODEV_DRIVER_DBUS:
354 return dev->u.dbus.TYPE;
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100355#endif
356#ifdef CONFIG_AUDIO_DSOUND
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100357 case AUDIODEV_DRIVER_DSOUND:
358 return dev->u.dsound.TYPE;
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100359#endif
360#ifdef CONFIG_AUDIO_JACK
Geoffrey McRae2e445702020-04-29 15:53:58 +1000361 case AUDIODEV_DRIVER_JACK:
362 return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE);
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100363#endif
364#ifdef CONFIG_AUDIO_OSS
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100365 case AUDIODEV_DRIVER_OSS:
366 return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100367#endif
368#ifdef CONFIG_AUDIO_PA
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100369 case AUDIODEV_DRIVER_PA:
370 return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100371#endif
Dorinda Basseyc2d3d1c2023-04-17 12:56:54 +0200372#ifdef CONFIG_AUDIO_PIPEWIRE
373 case AUDIODEV_DRIVER_PIPEWIRE:
374 return qapi_AudiodevPipewirePerDirectionOptions_base(dev->u.pipewire.TYPE);
375#endif
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100376#ifdef CONFIG_AUDIO_SDL
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100377 case AUDIODEV_DRIVER_SDL:
Volker Rümelin5a0926c2021-01-10 11:02:19 +0100378 return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100379#endif
380#ifdef CONFIG_AUDIO_SNDIO
Alexandre Ratchov663df1c2022-09-07 15:23:42 +0200381 case AUDIODEV_DRIVER_SNDIO:
382 return dev->u.sndio.TYPE;
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100383#endif
384#ifdef CONFIG_SPICE
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100385 case AUDIODEV_DRIVER_SPICE:
386 return dev->u.spice.TYPE;
Daniel P. Berrangé7a92a852023-01-23 09:39:57 +0100387#endif
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100388 case AUDIODEV_DRIVER_WAV:
389 return dev->u.wav.TYPE;
390
391 case AUDIODEV_DRIVER__MAX:
392 break;
393 }
394 abort();
395}
396
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200397static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as)
bellard1d14ffa2005-10-30 18:58:22 +0000398{
399 HW *hw;
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100400 AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
bellard1d14ffa2005-10-30 18:58:22 +0000401
Kővágó, Zoltán19306162019-10-13 21:57:59 +0200402 if (!pdo->mixing_engine || pdo->fixed_settings) {
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200403 hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
Kővágó, Zoltán19306162019-10-13 21:57:59 +0200404 if (!pdo->mixing_engine || hw) {
bellard1d14ffa2005-10-30 18:58:22 +0000405 return hw;
406 }
407 }
408
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200409 hw = glue(audio_pcm_hw_find_specific_, TYPE)(s, NULL, as);
bellard1d14ffa2005-10-30 18:58:22 +0000410 if (hw) {
411 return hw;
412 }
413
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200414 hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
bellard1d14ffa2005-10-30 18:58:22 +0000415 if (hw) {
416 return hw;
417 }
418
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200419 return glue(audio_pcm_hw_find_any_, TYPE)(s, NULL);
bellard1d14ffa2005-10-30 18:58:22 +0000420}
421
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200422static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
423 AudioState *s,
bellardc0fe3822005-11-05 18:55:28 +0000424 const char *sw_name,
malc1ea879e2008-12-03 22:48:44 +0000425 struct audsettings *as
bellard1d14ffa2005-10-30 18:58:22 +0000426 )
427{
428 SW *sw;
429 HW *hw;
malc1ea879e2008-12-03 22:48:44 +0000430 struct audsettings hw_as;
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100431 AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
bellard1d14ffa2005-10-30 18:58:22 +0000432
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100433 if (pdo->fixed_settings) {
434 hw_as = audiodev_to_audsettings(pdo);
Zhang Han6c6886b2021-01-15 09:24:25 +0800435 } else {
bellardc0fe3822005-11-05 18:55:28 +0000436 hw_as = *as;
bellard1d14ffa2005-10-30 18:58:22 +0000437 }
438
Volker Rümelinc6b69a82023-01-21 10:47:32 +0100439 sw = g_new0(SW, 1);
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200440 sw->s = s;
bellard1d14ffa2005-10-30 18:58:22 +0000441
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200442 hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
bellard1d14ffa2005-10-30 18:58:22 +0000443 if (!hw) {
Volker Rümelin90394fe2023-01-21 10:47:26 +0100444 dolog("Could not create a backend for voice `%s'\n", sw_name);
Volker Rümelinc6b69a82023-01-21 10:47:32 +0100445 goto err1;
bellard1d14ffa2005-10-30 18:58:22 +0000446 }
447
448 glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
449
bellardd929eba2006-07-04 21:47:22 +0000450 if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
Volker Rümelinc6b69a82023-01-21 10:47:32 +0100451 goto err2;
bellard1d14ffa2005-10-30 18:58:22 +0000452 }
453
454 return sw;
455
Volker Rümelinc6b69a82023-01-21 10:47:32 +0100456err2:
bellard1d14ffa2005-10-30 18:58:22 +0000457 glue (audio_pcm_hw_del_sw_, TYPE) (sw);
malc1a7dafc2009-05-14 03:11:35 +0400458 glue (audio_pcm_hw_gc_, TYPE) (&hw);
bellard1d14ffa2005-10-30 18:58:22 +0000459err1:
Volker Rümelinc6b69a82023-01-21 10:47:32 +0100460 g_free(sw);
bellard1d14ffa2005-10-30 18:58:22 +0000461 return NULL;
462}
463
malc1a7dafc2009-05-14 03:11:35 +0400464static void glue (audio_close_, TYPE) (SW *sw)
bellardc0fe3822005-11-05 18:55:28 +0000465{
466 glue (audio_pcm_sw_fini_, TYPE) (sw);
467 glue (audio_pcm_hw_del_sw_, TYPE) (sw);
malc1a7dafc2009-05-14 03:11:35 +0400468 glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
Anthony Liguori7267c092011-08-20 22:09:37 -0500469 g_free (sw);
bellardc0fe3822005-11-05 18:55:28 +0000470}
bellard571ec3d2005-11-20 16:24:34 +0000471
bellardc0fe3822005-11-05 18:55:28 +0000472void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
bellard1d14ffa2005-10-30 18:58:22 +0000473{
474 if (sw) {
Alistair Francis470bcab2018-02-03 09:43:02 +0100475 if (audio_bug(__func__, !card)) {
malc1a7dafc2009-05-14 03:11:35 +0400476 dolog ("card=%p\n", card);
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200477 return;
bellardc0fe3822005-11-05 18:55:28 +0000478 }
479
malc1a7dafc2009-05-14 03:11:35 +0400480 glue (audio_close_, TYPE) (sw);
bellard1d14ffa2005-10-30 18:58:22 +0000481 }
482}
483
484SW *glue (AUD_open_, TYPE) (
bellardc0fe3822005-11-05 18:55:28 +0000485 QEMUSoundCard *card,
bellard1d14ffa2005-10-30 18:58:22 +0000486 SW *sw,
487 const char *name,
488 void *callback_opaque ,
malccb4f03e2009-10-15 02:40:17 +0400489 audio_callback_fn callback_fn,
malc1ea879e2008-12-03 22:48:44 +0000490 struct audsettings *as
bellard1d14ffa2005-10-30 18:58:22 +0000491 )
492{
Kővágó, Zoltánd1670b22019-09-11 01:26:18 +0200493 AudioState *s;
494 AudiodevPerDirectionOptions *pdo;
bellard1d14ffa2005-10-30 18:58:22 +0000495
Alistair Francis470bcab2018-02-03 09:43:02 +0100496 if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
malc1a7dafc2009-05-14 03:11:35 +0400497 dolog ("card=%p name=%p callback_fn=%p as=%p\n",
498 card, name, callback_fn, as);
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200499 goto fail;
bellard1d14ffa2005-10-30 18:58:22 +0000500 }
501
Kővágó, Zoltánd1670b22019-09-11 01:26:18 +0200502 s = card->state;
503 pdo = glue(audio_get_pdo_, TYPE)(s->dev);
504
Stefan Weil93b65992012-09-03 09:25:16 +0000505 ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
506 name, as->freq, as->nchannels, as->fmt);
507
Alistair Francis470bcab2018-02-03 09:43:02 +0100508 if (audio_bug(__func__, audio_validate_settings(as))) {
bellardc0fe3822005-11-05 18:55:28 +0000509 audio_print_settings (as);
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200510 goto fail;
bellard1d14ffa2005-10-30 18:58:22 +0000511 }
512
Alistair Francis470bcab2018-02-03 09:43:02 +0100513 if (audio_bug(__func__, !s->drv)) {
bellardc0fe3822005-11-05 18:55:28 +0000514 dolog ("Can not open `%s' (no host audio driver)\n", name);
Volker Rümelin12f4abf2022-09-17 15:16:25 +0200515 goto fail;
bellard1d14ffa2005-10-30 18:58:22 +0000516 }
517
bellardc0fe3822005-11-05 18:55:28 +0000518 if (sw && audio_pcm_info_eq (&sw->info, as)) {
bellard1d14ffa2005-10-30 18:58:22 +0000519 return sw;
520 }
521
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100522 if (!pdo->fixed_settings && sw) {
bellardc0fe3822005-11-05 18:55:28 +0000523 glue (AUD_close_, TYPE) (card, sw);
bellard1d14ffa2005-10-30 18:58:22 +0000524 sw = NULL;
525 }
526
527 if (sw) {
528 HW *hw = sw->hw;
529
530 if (!hw) {
Volker Rümelinb637a612023-01-21 10:47:27 +0100531 dolog("Internal logic error: voice `%s' has no backend\n",
532 SW_NAME(sw));
bellard1d14ffa2005-10-30 18:58:22 +0000533 goto fail;
534 }
535
bellard571ec3d2005-11-20 16:24:34 +0000536 glue (audio_pcm_sw_fini_, TYPE) (sw);
bellardd929eba2006-07-04 21:47:22 +0000537 if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
bellard1d14ffa2005-10-30 18:58:22 +0000538 goto fail;
539 }
Zhang Han6c6886b2021-01-15 09:24:25 +0800540 } else {
Kővágó, Zoltán526fb052019-08-19 01:06:46 +0200541 sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
bellard1d14ffa2005-10-30 18:58:22 +0000542 if (!sw) {
bellard571ec3d2005-11-20 16:24:34 +0000543 return NULL;
bellard1d14ffa2005-10-30 18:58:22 +0000544 }
545 }
546
malc7cbb28e2009-11-18 19:15:19 +0300547 sw->card = card;
548 sw->vol = nominal_volume;
549 sw->callback.fn = callback_fn;
550 sw->callback.opaque = callback_opaque;
bellard1d14ffa2005-10-30 18:58:22 +0000551
bellard1d14ffa2005-10-30 18:58:22 +0000552#ifdef DEBUG_AUDIO
malc7cbb28e2009-11-18 19:15:19 +0300553 dolog ("%s\n", name);
554 audio_pcm_print_info ("hw", &sw->hw->info);
555 audio_pcm_print_info ("sw", &sw->info);
bellard1d14ffa2005-10-30 18:58:22 +0000556#endif
bellard1d14ffa2005-10-30 18:58:22 +0000557
558 return sw;
559
560 fail:
bellardc0fe3822005-11-05 18:55:28 +0000561 glue (AUD_close_, TYPE) (card, sw);
bellard1d14ffa2005-10-30 18:58:22 +0000562 return NULL;
563}
564
565int glue (AUD_is_active_, TYPE) (SW *sw)
566{
567 return sw ? sw->active : 0;
568}
569
570void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
571{
572 if (!sw) {
573 return;
574 }
575
576 ts->old_ts = sw->hw->ts_helper;
577}
578
bellardc0fe3822005-11-05 18:55:28 +0000579uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
bellard1d14ffa2005-10-30 18:58:22 +0000580{
581 uint64_t delta, cur_ts, old_ts;
582
583 if (!sw) {
584 return 0;
585 }
586
587 cur_ts = sw->hw->ts_helper;
588 old_ts = ts->old_ts;
Blue Swirl0bfcd592010-05-22 08:02:12 +0000589 /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
bellard1d14ffa2005-10-30 18:58:22 +0000590
591 if (cur_ts >= old_ts) {
592 delta = cur_ts - old_ts;
Zhang Han6c6886b2021-01-15 09:24:25 +0800593 } else {
bellard1d14ffa2005-10-30 18:58:22 +0000594 delta = UINT64_MAX - old_ts + cur_ts;
595 }
596
597 if (!delta) {
598 return 0;
599 }
600
malc4f4cc0e2009-09-18 08:16:03 +0400601 return muldiv64 (delta, sw->hw->info.freq, 1000000);
bellard1d14ffa2005-10-30 18:58:22 +0000602}
603
604#undef TYPE
605#undef HW
606#undef SW
bellard571ec3d2005-11-20 16:24:34 +0000607#undef HWBUF
608#undef NAME