Commit ec36b695b0bd054e673854fd1f02fa83e4bebea2

Authored by bellard
1 parent 63301264

audio capture to wab files (malc)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2059 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -321,6 +321,7 @@ endif
321 321 ifdef CONFIG_ADLIB
322 322 SOUND_HW += fmopl.o adlib.o
323 323 endif
  324 +AUDIODRV+= wavcapture.o
324 325  
325 326 # SCSI layer
326 327 VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
... ...
audio/audio.c
... ... @@ -510,7 +510,8 @@ static void audio_print_settings (audsettings_t *as)
510 510 AUD_log (NULL, "invalid(%d)", as->fmt);
511 511 break;
512 512 }
513   - AUD_log (NULL, "endianness=");
  513 +
  514 + AUD_log (NULL, " endianness=");
514 515 switch (as->endianness) {
515 516 case 0:
516 517 AUD_log (NULL, "little");
... ... @@ -525,7 +526,7 @@ static void audio_print_settings (audsettings_t *as)
525 526 AUD_log (NULL, "\n");
526 527 }
527 528  
528   -static int audio_validate_settigs (audsettings_t *as)
  529 +static int audio_validate_settings (audsettings_t *as)
529 530 {
530 531 int invalid;
531 532  
... ... @@ -654,15 +655,25 @@ static CaptureVoiceOut *audio_pcm_capture_find_specific (
654 655 return NULL;
655 656 }
656 657  
657   -static void audio_notify_capture (CaptureVoiceOut *cap, int enabled)
  658 +static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
658 659 {
659   - if (cap->hw.enabled != enabled) {
660   - struct capture_callback *cb;
  660 + struct capture_callback *cb;
  661 +
  662 +#ifdef DEBUG_CAPTURE
  663 + dolog ("notification %d sent\n", cmd);
  664 +#endif
  665 + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
  666 + cb->ops.notify (cb->opaque, cmd);
  667 + }
  668 +}
661 669  
  670 +static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
  671 +{
  672 + if (cap->hw.enabled != enabled) {
  673 + audcnotification_e cmd;
662 674 cap->hw.enabled = enabled;
663   - for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
664   - cb->ops.state (cb->opaque, enabled);
665   - }
  675 + cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
  676 + audio_notify_capture (cap, cmd);
666 677 }
667 678 }
668 679  
... ... @@ -672,29 +683,40 @@ static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
672 683 SWVoiceOut *sw;
673 684 int enabled = 0;
674 685  
675   - for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) {
  686 + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
676 687 if (sw->active) {
677 688 enabled = 1;
678 689 break;
679 690 }
680 691 }
681   - audio_notify_capture (cap, enabled);
  692 + audio_capture_maybe_changed (cap, enabled);
682 693 }
683 694  
684 695 static void audio_detach_capture (HWVoiceOut *hw)
685 696 {
686   - SWVoiceOut *sw;
  697 + SWVoiceCap *sc = hw->cap_head.lh_first;
  698 +
  699 + while (sc) {
  700 + SWVoiceCap *sc1 = sc->entries.le_next;
  701 + SWVoiceOut *sw = &sc->sw;
  702 + CaptureVoiceOut *cap = sc->cap;
  703 + int was_active = sw->active;
687 704  
688   - for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) {
689 705 if (sw->rate) {
690 706 st_rate_stop (sw->rate);
691 707 sw->rate = NULL;
692 708 }
693 709  
694 710 LIST_REMOVE (sw, entries);
695   - LIST_REMOVE (sw, cap_entries);
696   - qemu_free (sw);
697   - audio_recalc_and_notify_capture ((CaptureVoiceOut *) sw->hw);
  711 + LIST_REMOVE (sc, entries);
  712 + qemu_free (sc);
  713 + if (was_active) {
  714 + /* We have removed soft voice from the capture:
  715 + this might have changed the overall status of the capture
  716 + since this might have been the only active voice */
  717 + audio_recalc_and_notify_capture (cap);
  718 + }
  719 + sc = sc1;
698 720 }
699 721 }
700 722  
... ... @@ -704,19 +726,21 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
704 726  
705 727 audio_detach_capture (hw);
706 728 for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
  729 + SWVoiceCap *sc;
707 730 SWVoiceOut *sw;
708   - HWVoiceOut *hw_cap;
  731 + HWVoiceOut *hw_cap = &cap->hw;
709 732  
710   - hw_cap = &cap->hw;
711   - sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
712   - if (!sw) {
  733 + sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
  734 + if (!sc) {
713 735 dolog ("Could not allocate soft capture voice (%zu bytes)\n",
714   - sizeof (*sw));
  736 + sizeof (*sc));
715 737 return -1;
716 738 }
717 739  
718   - sw->info = hw->info;
  740 + sc->cap = cap;
  741 + sw = &sc->sw;
719 742 sw->hw = hw_cap;
  743 + sw->info = hw->info;
720 744 sw->empty = 1;
721 745 sw->active = hw->enabled;
722 746 sw->conv = noop_conv;
... ... @@ -728,12 +752,14 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
728 752 return -1;
729 753 }
730 754 LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
731   - LIST_INSERT_HEAD (&hw->sw_cap_head, sw, cap_entries);
  755 + LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
  756 +#ifdef DEBUG_CAPTURE
  757 + asprintf (&sw->name, "for %p %d,%d,%d",
  758 + hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
  759 + dolog ("Added %s active = %d\n", sw->name, sw->active);
  760 +#endif
732 761 if (sw->active) {
733   - audio_notify_capture (cap, 1);
734   - }
735   - else {
736   - audio_recalc_and_notify_capture (cap);
  762 + audio_capture_maybe_changed (cap, 1);
737 763 }
738 764 }
739 765 return 0;
... ... @@ -915,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
915 941 }
916 942  
917 943 if (live == hwsamples) {
  944 +#ifdef DEBUG_OUT
  945 + dolog ("%s is full %d\n", sw->name, live);
  946 +#endif
918 947 return 0;
919 948 }
920 949  
... ... @@ -1033,6 +1062,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
1033 1062 hw = sw->hw;
1034 1063 if (sw->active != on) {
1035 1064 SWVoiceOut *temp_sw;
  1065 + SWVoiceCap *sc;
1036 1066  
1037 1067 if (on) {
1038 1068 hw->pending_disable = 0;
... ... @@ -1053,11 +1083,11 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
1053 1083 hw->pending_disable = nb_active == 1;
1054 1084 }
1055 1085 }
1056   - for (temp_sw = hw->sw_cap_head.lh_first; temp_sw;
1057   - temp_sw = temp_sw->entries.le_next) {
1058   - temp_sw->active = hw->enabled;
  1086 +
  1087 + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
  1088 + sc->sw.active = hw->enabled;
1059 1089 if (hw->enabled) {
1060   - audio_notify_capture ((CaptureVoiceOut *) temp_sw->hw, 1);
  1090 + audio_capture_maybe_changed (sc->cap, 1);
1061 1091 }
1062 1092 }
1063 1093 sw->active = on;
... ... @@ -1156,9 +1186,10 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
1156 1186 int n;
1157 1187  
1158 1188 if (hw->enabled) {
1159   - SWVoiceOut *sw;
  1189 + SWVoiceCap *sc;
1160 1190  
1161   - for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) {
  1191 + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
  1192 + SWVoiceOut *sw = &sc->sw;
1162 1193 int rpos2 = rpos;
1163 1194  
1164 1195 n = samples;
... ... @@ -1171,8 +1202,9 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
1171 1202 sw->buf = hw->mix_buf + rpos2;
1172 1203 written = audio_pcm_sw_write (sw, NULL, bytes);
1173 1204 if (written - bytes) {
1174   - dolog ("Could not mix %d bytes into a capture buffer",
1175   - bytes);
  1205 + dolog ("Could not mix %d bytes into a capture "
  1206 + "buffer, mixed %d\n",
  1207 + bytes, written);
1176 1208 break;
1177 1209 }
1178 1210 n -= to_write;
... ... @@ -1206,16 +1238,16 @@ static void audio_run_out (AudioState *s)
1206 1238 }
1207 1239  
1208 1240 if (hw->pending_disable && !nb_live) {
  1241 + SWVoiceCap *sc;
1209 1242 #ifdef DEBUG_OUT
1210 1243 dolog ("Disabling voice\n");
1211 1244 #endif
1212 1245 hw->enabled = 0;
1213 1246 hw->pending_disable = 0;
1214 1247 hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
1215   - for (sw = hw->sw_cap_head.lh_first; sw;
1216   - sw = sw->cap_entries.le_next) {
1217   - sw->active = 0;
1218   - audio_recalc_and_notify_capture ((CaptureVoiceOut *) sw->hw);
  1248 + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
  1249 + sc->sw.active = 0;
  1250 + audio_recalc_and_notify_capture (sc->cap);
1219 1251 }
1220 1252 continue;
1221 1253 }
... ... @@ -1277,15 +1309,18 @@ static void audio_run_out (AudioState *s)
1277 1309 }
1278 1310  
1279 1311 if (cleanup_required) {
1280   - restart:
1281   - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
  1312 + SWVoiceOut *sw1;
  1313 +
  1314 + sw = hw->sw_head.lh_first;
  1315 + while (sw) {
  1316 + sw1 = sw->entries.le_next;
1282 1317 if (!sw->active && !sw->callback.fn) {
1283 1318 #ifdef DEBUG_PLIVE
1284 1319 dolog ("Finishing with old voice\n");
1285 1320 #endif
1286 1321 audio_close_out (s, sw);
1287   - goto restart; /* play it safe */
1288 1322 }
  1323 + sw = sw1;
1289 1324 }
1290 1325 }
1291 1326 }
... ... @@ -1537,13 +1572,18 @@ static void audio_atexit (void)
1537 1572 HWVoiceIn *hwi = NULL;
1538 1573  
1539 1574 while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
1540   - SWVoiceOut *sw;
  1575 + SWVoiceCap *sc;
1541 1576  
1542 1577 hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
1543 1578 hwo->pcm_ops->fini_out (hwo);
1544 1579  
1545   - for (sw = hwo->sw_cap_head.lh_first; sw; sw = sw->entries.le_next) {
1546   - audio_notify_capture ((CaptureVoiceOut *) sw->hw, 0);
  1580 + for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
  1581 + CaptureVoiceOut *cap = sc->cap;
  1582 + struct capture_callback *cb;
  1583 +
  1584 + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
  1585 + cb->ops.destroy (cb->opaque);
  1586 + }
1547 1587 }
1548 1588 }
1549 1589  
... ... @@ -1697,7 +1737,7 @@ AudioState *AUD_init (void)
1697 1737 return s;
1698 1738 }
1699 1739  
1700   -int AUD_add_capture (
  1740 +CaptureVoiceOut *AUD_add_capture (
1701 1741 AudioState *s,
1702 1742 audsettings_t *as,
1703 1743 struct audio_capture_ops *ops,
... ... @@ -1712,10 +1752,10 @@ int AUD_add_capture (
1712 1752 s = &glob_audio_state;
1713 1753 }
1714 1754  
1715   - if (audio_validate_settigs (as)) {
  1755 + if (audio_validate_settings (as)) {
1716 1756 dolog ("Invalid settings were passed when trying to add capture\n");
1717 1757 audio_print_settings (as);
1718   - return -1;
  1758 + goto err0;
1719 1759 }
1720 1760  
1721 1761 cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
... ... @@ -1730,7 +1770,7 @@ int AUD_add_capture (
1730 1770 cap = audio_pcm_capture_find_specific (s, as);
1731 1771 if (cap) {
1732 1772 LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
1733   - return 0;
  1773 + return cap;
1734 1774 }
1735 1775 else {
1736 1776 HWVoiceOut *hw;
... ... @@ -1780,7 +1820,7 @@ int AUD_add_capture (
1780 1820 while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
1781 1821 audio_attach_capture (s, hw);
1782 1822 }
1783   - return 0;
  1823 + return cap;
1784 1824  
1785 1825 err3:
1786 1826 qemu_free (cap->hw.mix_buf);
... ... @@ -1789,6 +1829,38 @@ int AUD_add_capture (
1789 1829 err1:
1790 1830 qemu_free (cb);
1791 1831 err0:
1792   - return -1;
  1832 + return NULL;
  1833 + }
  1834 +}
  1835 +
  1836 +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
  1837 +{
  1838 + struct capture_callback *cb;
  1839 +
  1840 + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
  1841 + if (cb->opaque == cb_opaque) {
  1842 + cb->ops.destroy (cb_opaque);
  1843 + LIST_REMOVE (cb, entries);
  1844 + qemu_free (cb);
  1845 +
  1846 + if (!cap->cb_head.lh_first) {
  1847 + SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
  1848 + while (sw) {
  1849 +#ifdef DEBUG_CAPTURE
  1850 + dolog ("freeing %s\n", sw->name);
  1851 +#endif
  1852 + sw1 = sw->entries.le_next;
  1853 + if (sw->rate) {
  1854 + st_rate_stop (sw->rate);
  1855 + sw->rate = NULL;
  1856 + }
  1857 + LIST_REMOVE (sw, entries);
  1858 + sw = sw1;
  1859 + }
  1860 + LIST_REMOVE (cap, entries);
  1861 + qemu_free (cap);
  1862 + }
  1863 + return;
  1864 + }
1793 1865 }
1794 1866 }
... ...
audio/audio.h
... ... @@ -49,13 +49,31 @@ typedef struct {
49 49 int endianness;
50 50 } audsettings_t;
51 51  
  52 +typedef enum {
  53 + AUD_CNOTIFY_ENABLE,
  54 + AUD_CNOTIFY_DISABLE
  55 +} audcnotification_e;
  56 +
52 57 struct audio_capture_ops {
53   - void (*state) (void *opaque, int enabled);
  58 + void (*notify) (void *opaque, audcnotification_e cmd);
54 59 void (*capture) (void *opaque, void *buf, int size);
  60 + void (*destroy) (void *opaque);
55 61 };
56 62  
  63 +struct capture_ops {
  64 + void (*info) (void *opaque);
  65 + void (*destroy) (void *opaque);
  66 +};
  67 +
  68 +typedef struct CaptureState {
  69 + void *opaque;
  70 + struct capture_ops ops;
  71 + LIST_ENTRY (CaptureState) entries;
  72 +} CaptureState;
  73 +
57 74 typedef struct AudioState AudioState;
58 75 typedef struct SWVoiceOut SWVoiceOut;
  76 +typedef struct CaptureVoiceOut CaptureVoiceOut;
59 77 typedef struct SWVoiceIn SWVoiceIn;
60 78  
61 79 typedef struct QEMUSoundCard {
... ... @@ -79,12 +97,13 @@ AudioState *AUD_init (void);
79 97 void AUD_help (void);
80 98 void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
81 99 void AUD_remove_card (QEMUSoundCard *card);
82   -int AUD_add_capture (
  100 +CaptureVoiceOut *AUD_add_capture (
83 101 AudioState *s,
84 102 audsettings_t *as,
85 103 struct audio_capture_ops *ops,
86 104 void *opaque
87 105 );
  106 +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
88 107  
89 108 SWVoiceOut *AUD_open_out (
90 109 QEMUSoundCard *card,
... ...
audio/audio_int.h
... ... @@ -64,10 +64,11 @@ struct audio_pcm_info {
64 64 int swap_endianness;
65 65 };
66 66  
  67 +typedef struct SWVoiceCap SWVoiceCap;
  68 +
67 69 typedef struct HWVoiceOut {
68 70 int enabled;
69 71 int pending_disable;
70   - int valid;
71 72 struct audio_pcm_info info;
72 73  
73 74 f_sample *clip;
... ... @@ -79,7 +80,7 @@ typedef struct HWVoiceOut {
79 80  
80 81 int samples;
81 82 LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
82   - LIST_HEAD (sw_cap_listhead, SWVoiceOut) sw_cap_head;
  83 + LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
83 84 struct audio_pcm_ops *pcm_ops;
84 85 LIST_ENTRY (HWVoiceOut) entries;
85 86 } HWVoiceOut;
... ... @@ -116,7 +117,6 @@ struct SWVoiceOut {
116 117 volume_t vol;
117 118 struct audio_callback callback;
118 119 LIST_ENTRY (SWVoiceOut) entries;
119   - LIST_ENTRY (SWVoiceOut) cap_entries;
120 120 };
121 121  
122 122 struct SWVoiceIn {
... ... @@ -168,12 +168,18 @@ struct capture_callback {
168 168 LIST_ENTRY (capture_callback) entries;
169 169 };
170 170  
171   -typedef struct CaptureVoiceOut {
  171 +struct CaptureVoiceOut {
172 172 HWVoiceOut hw;
173 173 void *buf;
174 174 LIST_HEAD (cb_listhead, capture_callback) cb_head;
175 175 LIST_ENTRY (CaptureVoiceOut) entries;
176   -} CaptureVoiceOut;
  176 +};
  177 +
  178 +struct SWVoiceCap {
  179 + SWVoiceOut sw;
  180 + CaptureVoiceOut *cap;
  181 + LIST_ENTRY (SWVoiceCap) entries;
  182 +};
177 183  
178 184 struct AudioState {
179 185 struct audio_driver *drv;
... ...
audio/audio_template.h
... ... @@ -269,7 +269,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
269 269 hw->pcm_ops = drv->pcm_ops;
270 270 LIST_INIT (&hw->sw_head);
271 271 #ifdef DAC
272   - LIST_INIT (&hw->sw_cap_head);
  272 + LIST_INIT (&hw->cap_head);
273 273 #endif
274 274 if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
275 275 goto err0;
... ... @@ -426,7 +426,7 @@ SW *glue (AUD_open_, TYPE) (
426 426  
427 427 s = card->audio;
428 428  
429   - if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
  429 + if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
430 430 audio_print_settings (as);
431 431 goto fail;
432 432 }
... ...
audio/noaudio.c
... ... @@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw)
102 102 NoVoiceIn *no = (NoVoiceIn *) hw;
103 103 int live = audio_pcm_hw_get_live_in (hw);
104 104 int dead = hw->samples - live;
105   - int samples;
  105 + int samples = 0;
106 106  
107 107 if (dead) {
108 108 int64_t now = qemu_get_clock (vm_clock);
... ...
audio/wavcapture.c
... ... @@ -3,6 +3,11 @@
3 3 typedef struct {
4 4 QEMUFile *f;
5 5 int bytes;
  6 + char *path;
  7 + int freq;
  8 + int bits;
  9 + int nchannels;
  10 + CaptureVoiceOut *cap;
6 11 } WAVState;
7 12  
8 13 /* VICE code: Store number as little endian. */
... ... @@ -15,35 +20,39 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
15 20 }
16 21 }
17 22  
18   -static void wav_state_cb (void *opaque, int enabled)
  23 +static void wav_notify (void *opaque, audcnotification_e cmd)
19 24 {
20   - WAVState *wav = opaque;
  25 + (void) opaque;
  26 + (void) cmd;
  27 +}
21 28  
22   - if (!enabled) {
23   - uint8_t rlen[4];
24   - uint8_t dlen[4];
25   - uint32_t datalen = wav->bytes;
26   - uint32_t rifflen = datalen + 36;
  29 +static void wav_destroy (void *opaque)
  30 +{
  31 + WAVState *wav = opaque;
  32 + uint8_t rlen[4];
  33 + uint8_t dlen[4];
  34 + uint32_t datalen = wav->bytes;
  35 + uint32_t rifflen = datalen + 36;
27 36  
28   - if (!wav->f) {
29   - return;
30   - }
  37 + if (!wav->f) {
  38 + return;
  39 + }
31 40  
32   - le_store (rlen, rifflen, 4);
33   - le_store (dlen, datalen, 4);
  41 + le_store (rlen, rifflen, 4);
  42 + le_store (dlen, datalen, 4);
34 43  
35   - qemu_fseek (wav->f, 4, SEEK_SET);
36   - qemu_put_buffer (wav->f, rlen, 4);
  44 + qemu_fseek (wav->f, 4, SEEK_SET);
  45 + qemu_put_buffer (wav->f, rlen, 4);
37 46  
38   - qemu_fseek (wav->f, 32, SEEK_CUR);
39   - qemu_put_buffer (wav->f, dlen, 4);
40   - }
41   - else {
42   - qemu_fseek (wav->f, 0, SEEK_END);
  47 + qemu_fseek (wav->f, 32, SEEK_CUR);
  48 + qemu_put_buffer (wav->f, dlen, 4);
  49 + fclose (wav->f);
  50 + if (wav->path) {
  51 + qemu_free (wav->path);
43 52 }
44 53 }
45 54  
46   -static void wav_capture_cb (void *opaque, void *buf, int size)
  55 +static void wav_capture (void *opaque, void *buf, int size)
47 56 {
48 57 WAVState *wav = opaque;
49 58  
... ... @@ -51,7 +60,30 @@ static void wav_capture_cb (void *opaque, void *buf, int size)
51 60 wav->bytes += size;
52 61 }
53 62  
54   -void wav_capture (const char *path, int freq, int bits16, int stereo)
  63 +static void wav_capture_destroy (void *opaque)
  64 +{
  65 + WAVState *wav = opaque;
  66 +
  67 + AUD_del_capture (wav->cap, wav);
  68 +}
  69 +
  70 +static void wav_capture_info (void *opaque)
  71 +{
  72 + WAVState *wav = opaque;
  73 + char *path = wav->path;
  74 +
  75 + term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
  76 + wav->freq, wav->bits, wav->nchannels,
  77 + path ? path : "<not available>", wav->bytes);
  78 +}
  79 +
  80 +static struct capture_ops wav_capture_ops = {
  81 + .destroy = wav_capture_destroy,
  82 + .info = wav_capture_info
  83 +};
  84 +
  85 +int wav_start_capture (CaptureState *s, const char *path, int freq,
  86 + int bits, int nchannels)
55 87 {
56 88 WAVState *wav;
57 89 uint8_t hdr[] = {
... ... @@ -62,23 +94,35 @@ void wav_capture (const char *path, int freq, int bits16, int stereo)
62 94 };
63 95 audsettings_t as;
64 96 struct audio_capture_ops ops;
65   - int shift;
  97 + int stereo, bits16, shift;
  98 + CaptureVoiceOut *cap;
  99 +
  100 + if (bits != 8 && bits != 16) {
  101 + term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
  102 + return -1;
  103 + }
  104 +
  105 + if (nchannels != 1 && nchannels != 2) {
  106 + term_printf ("incorrect channel count %d, must be 1 or 2\n", bits);
  107 + return -1;
  108 + }
66 109  
67   - stereo = !!stereo;
68   - bits16 = !!bits16;
  110 + stereo = nchannels == 2;
  111 + bits16 = bits == 16;
69 112  
70 113 as.freq = freq;
71 114 as.nchannels = 1 << stereo;
72 115 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
73 116 as.endianness = 0;
74 117  
75   - ops.state = wav_state_cb;
76   - ops.capture = wav_capture_cb;
  118 + ops.notify = wav_notify;
  119 + ops.capture = wav_capture;
  120 + ops.destroy = wav_destroy;
77 121  
78 122 wav = qemu_mallocz (sizeof (*wav));
79 123 if (!wav) {
80 124 AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav));
81   - return;
  125 + return -1;
82 126 }
83 127  
84 128 shift = bits16 + stereo;
... ... @@ -91,12 +135,28 @@ void wav_capture (const char *path, int freq, int bits16, int stereo)
91 135  
92 136 wav->f = fopen (path, "wb");
93 137 if (!wav->f) {
94   - AUD_log ("wav", "Failed to open wave file `%s'\nReason: %s\n",
95   - path, strerror (errno));
  138 + term_printf ("Failed to open wave file `%s'\nReason: %s\n",
  139 + path, strerror (errno));
96 140 qemu_free (wav);
97   - return;
  141 + return -1;
98 142 }
99 143  
  144 + wav->path = qemu_strdup (path);
  145 + wav->bits = bits;
  146 + wav->nchannels = nchannels;
  147 + wav->freq = freq;
  148 +
100 149 qemu_put_buffer (wav->f, hdr, sizeof (hdr));
101   - AUD_add_capture (NULL, &as, &ops, wav);
  150 +
  151 + cap = AUD_add_capture (NULL, &as, &ops, wav);
  152 + if (!cap) {
  153 + term_printf ("Failed to add audio capture\n");
  154 + qemu_free (wav);
  155 + return -1;
  156 + }
  157 +
  158 + wav->cap = cap;
  159 + s->opaque = wav;
  160 + s->ops = wav_capture_ops;
  161 + return 0;
102 162 }
... ...
monitor.c
... ... @@ -1077,6 +1077,64 @@ static void do_info_profile(void)
1077 1077 }
1078 1078 #endif
1079 1079  
  1080 +/* Capture support */
  1081 +static LIST_HEAD (capture_list_head, CaptureState) capture_head;
  1082 +
  1083 +static void do_info_capture (void)
  1084 +{
  1085 + int i;
  1086 + CaptureState *s;
  1087 +
  1088 + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
  1089 + term_printf ("[%d]: ", i);
  1090 + s->ops.info (s->opaque);
  1091 + }
  1092 +}
  1093 +
  1094 +static void do_stop_capture (int n)
  1095 +{
  1096 + int i;
  1097 + CaptureState *s;
  1098 +
  1099 + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
  1100 + if (i == n) {
  1101 + s->ops.destroy (s->opaque);
  1102 + LIST_REMOVE (s, entries);
  1103 + qemu_free (s);
  1104 + return;
  1105 + }
  1106 + }
  1107 +}
  1108 +
  1109 +#ifdef HAS_AUDIO
  1110 +int wav_start_capture (CaptureState *s, const char *path, int freq,
  1111 + int bits, int nchannels);
  1112 +
  1113 +static void do_wav_capture (const char *path,
  1114 + int has_freq, int freq,
  1115 + int has_bits, int bits,
  1116 + int has_channels, int nchannels)
  1117 +{
  1118 + CaptureState *s;
  1119 +
  1120 + s = qemu_mallocz (sizeof (*s));
  1121 + if (!s) {
  1122 + term_printf ("Not enough memory to add wave capture\n");
  1123 + return;
  1124 + }
  1125 +
  1126 + freq = has_freq ? freq : 44100;
  1127 + bits = has_bits ? bits : 16;
  1128 + nchannels = has_channels ? nchannels : 2;
  1129 +
  1130 + if (wav_start_capture (s, path, freq, bits, nchannels)) {
  1131 + term_printf ("Faied to add wave capture\n");
  1132 + qemu_free (s);
  1133 + }
  1134 + LIST_INSERT_HEAD (&capture_head, s, entries);
  1135 +}
  1136 +#endif
  1137 +
1080 1138 static term_cmd_t term_cmds[] = {
1081 1139 { "help|?", "s?", do_help,
1082 1140 "[cmd]", "show the help" },
... ... @@ -1133,6 +1191,13 @@ static term_cmd_t term_cmds[] = {
1133 1191 "dx dy [dz]", "send mouse move events" },
1134 1192 { "mouse_button", "i", do_mouse_button,
1135 1193 "state", "change mouse button state (1=L, 2=M, 4=R)" },
  1194 +#ifdef HAS_AUDIO
  1195 + { "wavcapture", "si?i?i?", do_wav_capture,
  1196 + "path [frequency bits channels]",
  1197 + "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
  1198 +#endif
  1199 + { "stopcapture", "i", do_stop_capture,
  1200 + "capture index", "stop capture" },
1136 1201 { NULL, NULL, },
1137 1202 };
1138 1203  
... ... @@ -1171,6 +1236,8 @@ static term_cmd_t info_cmds[] = {
1171 1236 "", "show host USB devices", },
1172 1237 { "profile", "", do_info_profile,
1173 1238 "", "show profiling information", },
  1239 + { "capture", "", do_info_capture,
  1240 + "show capture information" },
1174 1241 { NULL, NULL, },
1175 1242 };
1176 1243  
... ... @@ -2081,6 +2148,9 @@ static void monitor_handle_command(const char *cmdline)
2081 2148 case 6:
2082 2149 cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
2083 2150 break;
  2151 + case 7:
  2152 + cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
  2153 + break;
2084 2154 default:
2085 2155 term_printf("unsupported number of arguments: %d\n", nb_args);
2086 2156 goto fail;
... ...