qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

audio: basic support for multi backend audio

Audio functions no longer access glob_audio_state, instead they get an
AudioState as a parameter. This is required in order to support
multiple backends.

glob_audio_state is also gone, and replaced with a tailq so we can store
more than one states.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Message-id: 67aef54f9e729a7160fe95c465351115e392164b.1566168923.git.DirtY.iCE.hu@gmail.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

authored by

Kővágó, Zoltán and committed by
Gerd Hoffmann
ecd97e95 526fb058

+95 -33
+78 -24
audio/audio.c
··· 87 87 return NULL; 88 88 } 89 89 90 - static AudioState glob_audio_state; 90 + static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states = 91 + QTAILQ_HEAD_INITIALIZER(audio_states); 91 92 92 93 const struct mixeng_volume nominal_volume = { 93 94 .mute = 0, ··· 1238 1239 1239 1240 void audio_run (const char *msg) 1240 1241 { 1241 - AudioState *s = &glob_audio_state; 1242 + AudioState *s; 1243 + 1244 + QTAILQ_FOREACH(s, &audio_states, list) { 1245 + audio_run_out(s); 1246 + audio_run_in(s); 1247 + audio_run_capture(s); 1248 + } 1242 1249 1243 - audio_run_out (s); 1244 - audio_run_in (s); 1245 - audio_run_capture (s); 1246 1250 #ifdef DEBUG_POLL 1247 1251 { 1248 1252 static double prevtime; ··· 1306 1310 return is_cleaning_up; 1307 1311 } 1308 1312 1309 - void audio_cleanup(void) 1313 + static void free_audio_state(AudioState *s) 1310 1314 { 1311 - AudioState *s = &glob_audio_state; 1312 1315 HWVoiceOut *hwo, *hwon; 1313 1316 HWVoiceIn *hwi, *hwin; 1314 1317 1315 - is_cleaning_up = true; 1316 1318 QLIST_FOREACH_SAFE(hwo, &s->hw_head_out, entries, hwon) { 1317 1319 SWVoiceCap *sc; 1318 1320 ··· 1349 1351 qapi_free_Audiodev(s->dev); 1350 1352 s->dev = NULL; 1351 1353 } 1354 + g_free(s); 1355 + } 1356 + 1357 + void audio_cleanup(void) 1358 + { 1359 + is_cleaning_up = true; 1360 + while (!QTAILQ_EMPTY(&audio_states)) { 1361 + AudioState *s = QTAILQ_FIRST(&audio_states); 1362 + QTAILQ_REMOVE(&audio_states, s, list); 1363 + free_audio_state(s); 1364 + } 1352 1365 } 1353 1366 1354 1367 static const VMStateDescription vmstate_audio = { ··· 1375 1388 return NULL; 1376 1389 } 1377 1390 1378 - static int audio_init(Audiodev *dev) 1391 + /* 1392 + * if we have dev, this function was called because of an -audiodev argument => 1393 + * initialize a new state with it 1394 + * if dev == NULL => legacy implicit initialization, return the already created 1395 + * state or create a new one 1396 + */ 1397 + static AudioState *audio_init(Audiodev *dev) 1379 1398 { 1399 + static bool atexit_registered; 1380 1400 size_t i; 1381 1401 int done = 0; 1382 1402 const char *drvname = NULL; 1383 1403 VMChangeStateEntry *e; 1384 - AudioState *s = &glob_audio_state; 1404 + AudioState *s; 1385 1405 struct audio_driver *driver; 1386 1406 /* silence gcc warning about uninitialized variable */ 1387 1407 AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head); 1388 1408 1389 - if (s->drv) { 1390 - if (dev) { 1391 - dolog("Cannot create more than one audio backend, sorry\n"); 1392 - qapi_free_Audiodev(dev); 1393 - } 1394 - return -1; 1395 - } 1396 - 1397 1409 if (dev) { 1398 1410 /* -audiodev option */ 1399 1411 drvname = AudiodevDriver_str(dev->driver); 1412 + } else if (!QTAILQ_EMPTY(&audio_states)) { 1413 + /* 1414 + * todo: check for -audiodev once we have normal audiodev selection 1415 + * support 1416 + */ 1417 + return QTAILQ_FIRST(&audio_states); 1400 1418 } else { 1401 1419 /* legacy implicit initialization */ 1402 1420 head = audio_handle_legacy_opts(); ··· 1410 1428 dev = QSIMPLEQ_FIRST(&head)->dev; 1411 1429 audio_validate_opts(dev, &error_abort); 1412 1430 } 1431 + 1432 + s = g_malloc0(sizeof(AudioState)); 1413 1433 s->dev = dev; 1414 1434 1415 1435 QLIST_INIT (&s->hw_head_out); 1416 1436 QLIST_INIT (&s->hw_head_in); 1417 1437 QLIST_INIT (&s->cap_head); 1418 - atexit(audio_cleanup); 1438 + if (!atexit_registered) { 1439 + atexit(audio_cleanup); 1440 + atexit_registered = true; 1441 + } 1442 + QTAILQ_INSERT_TAIL(&audio_states, s, list); 1419 1443 1420 1444 s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); 1421 1445 ··· 1480 1504 1481 1505 QLIST_INIT (&s->card_head); 1482 1506 vmstate_register (NULL, 0, &vmstate_audio, s); 1483 - return 0; 1507 + return s; 1484 1508 } 1485 1509 1486 1510 void audio_free_audiodev_list(AudiodevListHead *head) ··· 1495 1519 1496 1520 void AUD_register_card (const char *name, QEMUSoundCard *card) 1497 1521 { 1498 - audio_init(NULL); 1522 + if (!card->state) { 1523 + card->state = audio_init(NULL); 1524 + } 1525 + 1499 1526 card->name = g_strdup (name); 1500 1527 memset (&card->entries, 0, sizeof (card->entries)); 1501 - QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries); 1528 + QLIST_INSERT_HEAD(&card->state->card_head, card, entries); 1502 1529 } 1503 1530 1504 1531 void AUD_remove_card (QEMUSoundCard *card) ··· 1508 1535 } 1509 1536 1510 1537 1511 - CaptureVoiceOut *AUD_add_capture ( 1538 + CaptureVoiceOut *AUD_add_capture( 1539 + AudioState *s, 1512 1540 struct audsettings *as, 1513 1541 struct audio_capture_ops *ops, 1514 1542 void *cb_opaque 1515 1543 ) 1516 1544 { 1517 - AudioState *s = &glob_audio_state; 1518 1545 CaptureVoiceOut *cap; 1519 1546 struct capture_callback *cb; 1547 + 1548 + if (!s) { 1549 + /* todo: remove when we have normal audiodev selection support */ 1550 + s = audio_init(NULL); 1551 + } 1520 1552 1521 1553 if (audio_validate_settings (as)) { 1522 1554 dolog ("Invalid settings were passed when trying to add capture\n"); ··· 1807 1839 return audio_buffer_samples(pdo, as, def_usecs) * 1808 1840 audioformat_bytes_per_sample(as->fmt); 1809 1841 } 1842 + 1843 + AudioState *audio_state_by_name(const char *name) 1844 + { 1845 + AudioState *s; 1846 + QTAILQ_FOREACH(s, &audio_states, list) { 1847 + assert(s->dev); 1848 + if (strcmp(name, s->dev->id) == 0) { 1849 + return s; 1850 + } 1851 + } 1852 + return NULL; 1853 + } 1854 + 1855 + const char *audio_get_id(QEMUSoundCard *card) 1856 + { 1857 + if (card->state) { 1858 + assert(card->state->dev); 1859 + return card->state->dev->id; 1860 + } else { 1861 + return ""; 1862 + } 1863 + }
+9 -3
audio/audio.h
··· 78 78 typedef struct CaptureVoiceOut CaptureVoiceOut; 79 79 typedef struct SWVoiceIn SWVoiceIn; 80 80 81 + typedef struct AudioState AudioState; 81 82 typedef struct QEMUSoundCard { 82 83 char *name; 84 + AudioState *state; 83 85 QLIST_ENTRY (QEMUSoundCard) entries; 84 86 } QEMUSoundCard; 85 87 ··· 92 94 93 95 void AUD_register_card (const char *name, QEMUSoundCard *card); 94 96 void AUD_remove_card (QEMUSoundCard *card); 95 - CaptureVoiceOut *AUD_add_capture ( 97 + CaptureVoiceOut *AUD_add_capture( 98 + AudioState *s, 96 99 struct audsettings *as, 97 100 struct audio_capture_ops *ops, 98 101 void *opaque ··· 160 163 #define audio_MAX(a, b) ((a)<(b)?(b):(a)) 161 164 #endif 162 165 163 - int wav_start_capture (CaptureState *s, const char *path, int freq, 164 - int bits, int nchannels); 166 + int wav_start_capture(AudioState *state, CaptureState *s, const char *path, 167 + int freq, int bits, int nchannels); 165 168 166 169 bool audio_is_cleaning_up(void); 167 170 void audio_cleanup(void); ··· 174 177 void audio_parse_option(const char *opt); 175 178 void audio_init_audiodevs(void); 176 179 void audio_legacy_help(void); 180 + 181 + AudioState *audio_state_by_name(const char *name); 182 + const char *audio_get_id(QEMUSoundCard *card); 177 183 178 184 #endif /* QEMU_AUDIO_H */
+2
audio/audio_int.h
··· 196 196 197 197 bool timer_running; 198 198 uint64_t timer_last; 199 + 200 + QTAILQ_ENTRY(AudioState) list; 199 201 } AudioState; 200 202 201 203 extern const struct mixeng_volume nominal_volume;
+1 -1
audio/audio_template.h
··· 428 428 struct audsettings *as 429 429 ) 430 430 { 431 - AudioState *s = &glob_audio_state; 431 + AudioState *s = card->state; 432 432 AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev); 433 433 434 434 if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
+3 -3
audio/wavcapture.c
··· 104 104 .info = wav_capture_info 105 105 }; 106 106 107 - int wav_start_capture (CaptureState *s, const char *path, int freq, 108 - int bits, int nchannels) 107 + int wav_start_capture(AudioState *state, CaptureState *s, const char *path, 108 + int freq, int bits, int nchannels) 109 109 { 110 110 WAVState *wav; 111 111 uint8_t hdr[] = { ··· 170 170 goto error_free; 171 171 } 172 172 173 - cap = AUD_add_capture (&as, &ops, wav); 173 + cap = AUD_add_capture(state, &as, &ops, wav); 174 174 if (!cap) { 175 175 error_report("Failed to add audio capture"); 176 176 goto error_free;
+1 -1
monitor/misc.c
··· 1156 1156 bits = has_bits ? bits : 16; 1157 1157 nchannels = has_channels ? nchannels : 2; 1158 1158 1159 - if (wav_start_capture (s, path, freq, bits, nchannels)) { 1159 + if (wav_start_capture(NULL, s, path, freq, bits, nchannels)) { 1160 1160 monitor_printf(mon, "Failed to add wave capture\n"); 1161 1161 g_free (s); 1162 1162 return;
+1 -1
ui/vnc.c
··· 1224 1224 ops.destroy = audio_capture_destroy; 1225 1225 ops.capture = audio_capture; 1226 1226 1227 - vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs); 1227 + vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs); 1228 1228 if (!vs->audio_cap) { 1229 1229 error_report("Failed to add audio capture"); 1230 1230 }