]> git.proxmox.com Git - mirror_qemu.git/blame - audio/audio_template.h
audio/mixeng: use g_new0() instead of audio_calloc()
[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
571ec3d6
FB
26#define NAME "playback"
27#define HWBUF hw->mix_buf
1d14ffa9 28#define TYPE out
571ec3d6
FB
29#define HW HWVoiceOut
30#define SW SWVoiceOut
1d14ffa9 31#else
571ec3d6 32#define NAME "capture"
1d14ffa9 33#define TYPE in
571ec3d6
FB
34#define HW HWVoiceIn
35#define SW SWVoiceIn
36#define HWBUF hw->conv_buf
1d14ffa9
FB
37#endif
38
526fb058
KZ
39static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
40 struct audio_driver *drv)
c0fe3827 41{
571ec3d6
FB
42 int max_voices = glue (drv->max_voices_, TYPE);
43 int voice_size = glue (drv->voice_size_, TYPE);
c0fe3827 44
571ec3d6
FB
45 if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
46 if (!max_voices) {
47#ifdef DAC
48 dolog ("Driver `%s' does not support " NAME "\n", drv->name);
49#endif
6c6886bd 50 } else {
571ec3d6
FB
51 dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
52 drv->name,
53 glue (s->nb_hw_voices_, TYPE),
54 max_voices);
55 }
56 glue (s->nb_hw_voices_, TYPE) = max_voices;
c0fe3827
FB
57 }
58
470bcabd 59 if (audio_bug(__func__, !voice_size && max_voices)) {
571ec3d6
FB
60 dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
61 drv->name, max_voices);
12f4abf6 62 glue (s->nb_hw_voices_, TYPE) = 0;
571ec3d6
FB
63 }
64
470bcabd 65 if (audio_bug(__func__, voice_size && !max_voices)) {
571ec3d6
FB
66 dolog ("drv=`%s' voice_size=%d max_voices=0\n",
67 drv->name, voice_size);
68 }
69}
70
71static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
72{
ff095e52 73 g_free(hw->buf_emul);
fb7da626 74 g_free (HWBUF);
571ec3d6
FB
75 HWBUF = NULL;
76}
77
dc88e38f 78static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
571ec3d6 79{
1930616b
KZ
80 if (glue(audio_get_pdo_, TYPE)(hw->s->dev)->mixing_engine) {
81 size_t samples = hw->samples;
82 if (audio_bug(__func__, samples == 0)) {
83 dolog("Attempted to allocate empty buffer\n");
84 }
c0fe3827 85
1930616b
KZ
86 HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
87 HWBUF->size = samples;
88 } else {
89 HWBUF = NULL;
90 }
571ec3d6
FB
91}
92
93static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
94{
fb7da626 95 g_free (sw->buf);
571ec3d6
FB
96
97 if (sw->rate) {
98 st_rate_stop (sw->rate);
99 }
100
101 sw->buf = NULL;
102 sw->rate = NULL;
103}
104
105static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
106{
107 int samples;
108
1930616b
KZ
109 if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
110 return 0;
111 }
112
b73ef11f 113#ifdef DAC
dc88e38f 114 samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
b73ef11f
VR
115#else
116 samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
117#endif
b9ae74e2
VR
118 if (samples == 0) {
119 HW *hw = sw->hw;
120 size_t f_fe_min;
121
122 /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
123 f_fe_min = (hw->info.freq + HWBUF->size - 1) / HWBUF->size;
124 qemu_log_mask(LOG_UNIMP,
125 AUDIO_CAP ": The guest selected a " NAME " sample rate"
126 " of %d Hz for %s. Only sample rates >= %zu Hz are"
127 " supported.\n",
128 sw->info.freq, sw->name, f_fe_min);
129 return -1;
130 }
c0fe3827 131
470bcabd 132 sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
571ec3d6
FB
133 if (!sw->buf) {
134 dolog ("Could not allocate buffer for `%s' (%d samples)\n",
135 SW_NAME (sw), samples);
c0fe3827
FB
136 return -1;
137 }
138
571ec3d6
FB
139#ifdef DAC
140 sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
141#else
142 sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
143#endif
25bf0c2d 144
c0fe3827
FB
145 return 0;
146}
147
571ec3d6
FB
148static int glue (audio_pcm_sw_init_, TYPE) (
149 SW *sw,
150 HW *hw,
151 const char *name,
1ea879e5 152 struct audsettings *as
571ec3d6
FB
153 )
154{
155 int err;
156
d929eba5 157 audio_pcm_init_info (&sw->info, as);
571ec3d6
FB
158 sw->hw = hw;
159 sw->active = 0;
160#ifdef DAC
161 sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
162 sw->total_hw_samples_mixed = 0;
163 sw->empty = 1;
164#else
165 sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
166#endif
167
ed2a4a79 168 if (sw->info.is_float) {
571ec3d6 169#ifdef DAC
ed2a4a79 170 sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
571ec3d6 171#else
ed2a4a79 172 sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
571ec3d6 173#endif
ed2a4a79
KZ
174 } else {
175#ifdef DAC
176 sw->conv = mixeng_conv
177#else
178 sw->clip = mixeng_clip
179#endif
180 [sw->info.nchannels == 2]
181 [sw->info.is_signed]
182 [sw->info.swap_endianness]
183 [audio_bits_to_index(sw->info.bits)];
184 }
571ec3d6 185
7267c094 186 sw->name = g_strdup (name);
571ec3d6
FB
187 err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
188 if (err) {
7267c094 189 g_free (sw->name);
571ec3d6
FB
190 sw->name = NULL;
191 }
192 return err;
193}
194
1d14ffa9
FB
195static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
196{
197 glue (audio_pcm_sw_free_resources_, TYPE) (sw);
fb7da626
MA
198 g_free (sw->name);
199 sw->name = NULL;
1d14ffa9
FB
200}
201
202static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
203{
72cf2d4f 204 QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
1d14ffa9
FB
205}
206
207static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
208{
72cf2d4f 209 QLIST_REMOVE (sw, entries);
1d14ffa9
FB
210}
211
1a7dafce 212static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
1d14ffa9 213{
c0fe3827 214 HW *hw = *hwp;
526fb058 215 AudioState *s = hw->s;
1d14ffa9 216
1d14ffa9 217 if (!hw->sw_head.lh_first) {
8ead62cf 218#ifdef DAC
8abf3feb 219 audio_detach_capture(hw);
8ead62cf 220#endif
8abf3feb
ZH
221 QLIST_REMOVE(hw, entries);
222 glue(hw->pcm_ops->fini_, TYPE) (hw);
223 glue(s->nb_hw_voices_, TYPE) += 1;
224 glue(audio_pcm_hw_free_resources_ , TYPE) (hw);
225 g_free(hw);
c0fe3827 226 *hwp = NULL;
1d14ffa9
FB
227 }
228}
229
526fb058 230static HW *glue(audio_pcm_hw_find_any_, TYPE)(AudioState *s, HW *hw)
1d14ffa9 231{
1a7dafce 232 return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
1d14ffa9
FB
233}
234
526fb058 235static HW *glue(audio_pcm_hw_find_any_enabled_, TYPE)(AudioState *s, HW *hw)
1d14ffa9 236{
526fb058 237 while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
c0fe3827 238 if (hw->enabled) {
1d14ffa9
FB
239 return hw;
240 }
241 }
242 return NULL;
243}
244
526fb058
KZ
245static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
246 struct audsettings *as)
1d14ffa9 247{
526fb058 248 while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
c0fe3827 249 if (audio_pcm_info_eq (&hw->info, as)) {
1d14ffa9
FB
250 return hw;
251 }
252 }
253 return NULL;
254}
255
526fb058
KZ
256static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
257 struct audsettings *as)
1d14ffa9
FB
258{
259 HW *hw;
571ec3d6 260 struct audio_driver *drv = s->drv;
1d14ffa9 261
571ec3d6
FB
262 if (!glue (s->nb_hw_voices_, TYPE)) {
263 return NULL;
264 }
1d14ffa9 265
470bcabd 266 if (audio_bug(__func__, !drv)) {
571ec3d6 267 dolog ("No host audio driver\n");
12f4abf6 268 return NULL;
1d14ffa9
FB
269 }
270
470bcabd 271 if (audio_bug(__func__, !drv->pcm_ops)) {
571ec3d6 272 dolog ("Host audio driver without pcm_ops\n");
12f4abf6 273 return NULL;
571ec3d6
FB
274 }
275
470bcabd 276 hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
571ec3d6
FB
277 if (!hw) {
278 dolog ("Can not allocate voice `%s' size %d\n",
279 drv->name, glue (drv->voice_size_, TYPE));
280 return NULL;
281 }
282
526fb058 283 hw->s = s;
571ec3d6 284 hw->pcm_ops = drv->pcm_ops;
c01b2456 285
72cf2d4f 286 QLIST_INIT (&hw->sw_head);
8ead62cf 287#ifdef DAC
72cf2d4f 288 QLIST_INIT (&hw->cap_head);
8ead62cf 289#endif
5706db1d 290 if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) {
12f4abf6 291 goto err0;
571ec3d6
FB
292 }
293
470bcabd 294 if (audio_bug(__func__, hw->samples <= 0)) {
7520462b 295 dolog("hw->samples=%zd\n", hw->samples);
12f4abf6 296 goto err1;
571ec3d6
FB
297 }
298
ed2a4a79 299 if (hw->info.is_float) {
180b044f 300#ifdef DAC
ed2a4a79 301 hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
180b044f 302#else
ed2a4a79 303 hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
180b044f 304#endif
ed2a4a79 305 } else {
571ec3d6 306#ifdef DAC
ed2a4a79 307 hw->clip = mixeng_clip
571ec3d6 308#else
ed2a4a79 309 hw->conv = mixeng_conv
571ec3d6 310#endif
ed2a4a79
KZ
311 [hw->info.nchannels == 2]
312 [hw->info.is_signed]
313 [hw->info.swap_endianness]
314 [audio_bits_to_index(hw->info.bits)];
315 }
571ec3d6 316
dc88e38f 317 glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
571ec3d6 318
72cf2d4f 319 QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
571ec3d6 320 glue (s->nb_hw_voices_, TYPE) -= 1;
8ead62cf 321#ifdef DAC
1a7dafce 322 audio_attach_capture (hw);
8ead62cf 323#endif
571ec3d6 324 return hw;
12f4abf6
VR
325
326 err1:
327 glue (hw->pcm_ops->fini_, TYPE) (hw);
328 err0:
329 g_free (hw);
330 return NULL;
1d14ffa9
FB
331}
332
71830221
KZ
333AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
334{
335 switch (dev->driver) {
336 case AUDIODEV_DRIVER_NONE:
337 return dev->u.none.TYPE;
7a92a857 338#ifdef CONFIG_AUDIO_ALSA
71830221
KZ
339 case AUDIODEV_DRIVER_ALSA:
340 return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE);
7a92a857
DB
341#endif
342#ifdef CONFIG_AUDIO_COREAUDIO
71830221
KZ
343 case AUDIODEV_DRIVER_COREAUDIO:
344 return qapi_AudiodevCoreaudioPerDirectionOptions_base(
345 dev->u.coreaudio.TYPE);
7a92a857
DB
346#endif
347#ifdef CONFIG_DBUS_DISPLAY
739362d4
MAL
348 case AUDIODEV_DRIVER_DBUS:
349 return dev->u.dbus.TYPE;
7a92a857
DB
350#endif
351#ifdef CONFIG_AUDIO_DSOUND
71830221
KZ
352 case AUDIODEV_DRIVER_DSOUND:
353 return dev->u.dsound.TYPE;
7a92a857
DB
354#endif
355#ifdef CONFIG_AUDIO_JACK
2e445703
GM
356 case AUDIODEV_DRIVER_JACK:
357 return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE);
7a92a857
DB
358#endif
359#ifdef CONFIG_AUDIO_OSS
71830221
KZ
360 case AUDIODEV_DRIVER_OSS:
361 return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
7a92a857
DB
362#endif
363#ifdef CONFIG_AUDIO_PA
71830221
KZ
364 case AUDIODEV_DRIVER_PA:
365 return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
7a92a857
DB
366#endif
367#ifdef CONFIG_AUDIO_SDL
71830221 368 case AUDIODEV_DRIVER_SDL:
5a0926c2 369 return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
7a92a857
DB
370#endif
371#ifdef CONFIG_AUDIO_SNDIO
663df1cc
AR
372 case AUDIODEV_DRIVER_SNDIO:
373 return dev->u.sndio.TYPE;
7a92a857
DB
374#endif
375#ifdef CONFIG_SPICE
71830221
KZ
376 case AUDIODEV_DRIVER_SPICE:
377 return dev->u.spice.TYPE;
7a92a857 378#endif
71830221
KZ
379 case AUDIODEV_DRIVER_WAV:
380 return dev->u.wav.TYPE;
381
382 case AUDIODEV_DRIVER__MAX:
383 break;
384 }
385 abort();
386}
387
526fb058 388static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as)
1d14ffa9
FB
389{
390 HW *hw;
71830221 391 AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
1d14ffa9 392
1930616b 393 if (!pdo->mixing_engine || pdo->fixed_settings) {
526fb058 394 hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
1930616b 395 if (!pdo->mixing_engine || hw) {
1d14ffa9
FB
396 return hw;
397 }
398 }
399
526fb058 400 hw = glue(audio_pcm_hw_find_specific_, TYPE)(s, NULL, as);
1d14ffa9
FB
401 if (hw) {
402 return hw;
403 }
404
526fb058 405 hw = glue(audio_pcm_hw_add_new_, TYPE)(s, as);
1d14ffa9
FB
406 if (hw) {
407 return hw;
408 }
409
526fb058 410 return glue(audio_pcm_hw_find_any_, TYPE)(s, NULL);
1d14ffa9
FB
411}
412
526fb058
KZ
413static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
414 AudioState *s,
c0fe3827 415 const char *sw_name,
1ea879e5 416 struct audsettings *as
1d14ffa9
FB
417 )
418{
419 SW *sw;
420 HW *hw;
1ea879e5 421 struct audsettings hw_as;
71830221 422 AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
1d14ffa9 423
71830221
KZ
424 if (pdo->fixed_settings) {
425 hw_as = audiodev_to_audsettings(pdo);
6c6886bd 426 } else {
c0fe3827 427 hw_as = *as;
1d14ffa9
FB
428 }
429
470bcabd 430 sw = audio_calloc(__func__, 1, sizeof(*sw));
1d14ffa9 431 if (!sw) {
e7cad338 432 dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
c0fe3827 433 sw_name ? sw_name : "unknown", sizeof (*sw));
1d14ffa9
FB
434 goto err1;
435 }
526fb058 436 sw->s = s;
1d14ffa9 437
526fb058 438 hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
1d14ffa9 439 if (!hw) {
90394fe1 440 dolog("Could not create a backend for voice `%s'\n", sw_name);
1d14ffa9
FB
441 goto err2;
442 }
443
444 glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
445
d929eba5 446 if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
1d14ffa9
FB
447 goto err3;
448 }
449
450 return sw;
451
452err3:
453 glue (audio_pcm_hw_del_sw_, TYPE) (sw);
1a7dafce 454 glue (audio_pcm_hw_gc_, TYPE) (&hw);
1d14ffa9 455err2:
7267c094 456 g_free (sw);
1d14ffa9
FB
457err1:
458 return NULL;
459}
460
1a7dafce 461static void glue (audio_close_, TYPE) (SW *sw)
c0fe3827
FB
462{
463 glue (audio_pcm_sw_fini_, TYPE) (sw);
464 glue (audio_pcm_hw_del_sw_, TYPE) (sw);
1a7dafce 465 glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
7267c094 466 g_free (sw);
c0fe3827 467}
571ec3d6 468
c0fe3827 469void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
1d14ffa9
FB
470{
471 if (sw) {
470bcabd 472 if (audio_bug(__func__, !card)) {
1a7dafce 473 dolog ("card=%p\n", card);
12f4abf6 474 return;
c0fe3827
FB
475 }
476
1a7dafce 477 glue (audio_close_, TYPE) (sw);
1d14ffa9
FB
478 }
479}
480
481SW *glue (AUD_open_, TYPE) (
c0fe3827 482 QEMUSoundCard *card,
1d14ffa9
FB
483 SW *sw,
484 const char *name,
485 void *callback_opaque ,
cb4f03e8 486 audio_callback_fn callback_fn,
1ea879e5 487 struct audsettings *as
1d14ffa9
FB
488 )
489{
d1670b20
KZ
490 AudioState *s;
491 AudiodevPerDirectionOptions *pdo;
1d14ffa9 492
470bcabd 493 if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
1a7dafce 494 dolog ("card=%p name=%p callback_fn=%p as=%p\n",
495 card, name, callback_fn, as);
12f4abf6 496 goto fail;
1d14ffa9
FB
497 }
498
d1670b20
KZ
499 s = card->state;
500 pdo = glue(audio_get_pdo_, TYPE)(s->dev);
501
93b65997
SW
502 ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
503 name, as->freq, as->nchannels, as->fmt);
504
470bcabd 505 if (audio_bug(__func__, audio_validate_settings(as))) {
c0fe3827 506 audio_print_settings (as);
12f4abf6 507 goto fail;
1d14ffa9
FB
508 }
509
470bcabd 510 if (audio_bug(__func__, !s->drv)) {
c0fe3827 511 dolog ("Can not open `%s' (no host audio driver)\n", name);
12f4abf6 512 goto fail;
1d14ffa9
FB
513 }
514
c0fe3827 515 if (sw && audio_pcm_info_eq (&sw->info, as)) {
1d14ffa9
FB
516 return sw;
517 }
518
71830221 519 if (!pdo->fixed_settings && sw) {
c0fe3827 520 glue (AUD_close_, TYPE) (card, sw);
1d14ffa9
FB
521 sw = NULL;
522 }
523
524 if (sw) {
525 HW *hw = sw->hw;
526
527 if (!hw) {
b637a61c
VR
528 dolog("Internal logic error: voice `%s' has no backend\n",
529 SW_NAME(sw));
1d14ffa9
FB
530 goto fail;
531 }
532
571ec3d6 533 glue (audio_pcm_sw_fini_, TYPE) (sw);
d929eba5 534 if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
1d14ffa9
FB
535 goto fail;
536 }
6c6886bd 537 } else {
526fb058 538 sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
1d14ffa9 539 if (!sw) {
571ec3d6 540 return NULL;
1d14ffa9
FB
541 }
542 }
543
7cbb28ed 544 sw->card = card;
545 sw->vol = nominal_volume;
546 sw->callback.fn = callback_fn;
547 sw->callback.opaque = callback_opaque;
1d14ffa9 548
1d14ffa9 549#ifdef DEBUG_AUDIO
7cbb28ed 550 dolog ("%s\n", name);
551 audio_pcm_print_info ("hw", &sw->hw->info);
552 audio_pcm_print_info ("sw", &sw->info);
1d14ffa9 553#endif
1d14ffa9
FB
554
555 return sw;
556
557 fail:
c0fe3827 558 glue (AUD_close_, TYPE) (card, sw);
1d14ffa9
FB
559 return NULL;
560}
561
562int glue (AUD_is_active_, TYPE) (SW *sw)
563{
564 return sw ? sw->active : 0;
565}
566
567void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
568{
569 if (!sw) {
570 return;
571 }
572
573 ts->old_ts = sw->hw->ts_helper;
574}
575
c0fe3827 576uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
1d14ffa9
FB
577{
578 uint64_t delta, cur_ts, old_ts;
579
580 if (!sw) {
581 return 0;
582 }
583
584 cur_ts = sw->hw->ts_helper;
585 old_ts = ts->old_ts;
0bfcd599 586 /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
1d14ffa9
FB
587
588 if (cur_ts >= old_ts) {
589 delta = cur_ts - old_ts;
6c6886bd 590 } else {
1d14ffa9
FB
591 delta = UINT64_MAX - old_ts + cur_ts;
592 }
593
594 if (!delta) {
595 return 0;
596 }
597
4f4cc0ef 598 return muldiv64 (delta, sw->hw->info.freq, 1000000);
1d14ffa9
FB
599}
600
601#undef TYPE
602#undef HW
603#undef SW
571ec3d6
FB
604#undef HWBUF
605#undef NAME