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,6 +321,7 @@ endif
321 ifdef CONFIG_ADLIB 321 ifdef CONFIG_ADLIB
322 SOUND_HW += fmopl.o adlib.o 322 SOUND_HW += fmopl.o adlib.o
323 endif 323 endif
  324 +AUDIODRV+= wavcapture.o
324 325
325 # SCSI layer 326 # SCSI layer
326 VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o 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,7 +510,8 @@ static void audio_print_settings (audsettings_t *as)
510 AUD_log (NULL, "invalid(%d)", as->fmt); 510 AUD_log (NULL, "invalid(%d)", as->fmt);
511 break; 511 break;
512 } 512 }
513 - AUD_log (NULL, "endianness="); 513 +
  514 + AUD_log (NULL, " endianness=");
514 switch (as->endianness) { 515 switch (as->endianness) {
515 case 0: 516 case 0:
516 AUD_log (NULL, "little"); 517 AUD_log (NULL, "little");
@@ -525,7 +526,7 @@ static void audio_print_settings (audsettings_t *as) @@ -525,7 +526,7 @@ static void audio_print_settings (audsettings_t *as)
525 AUD_log (NULL, "\n"); 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 int invalid; 531 int invalid;
531 532
@@ -654,15 +655,25 @@ static CaptureVoiceOut *audio_pcm_capture_find_specific ( @@ -654,15 +655,25 @@ static CaptureVoiceOut *audio_pcm_capture_find_specific (
654 return NULL; 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 cap->hw.enabled = enabled; 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,29 +683,40 @@ static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
672 SWVoiceOut *sw; 683 SWVoiceOut *sw;
673 int enabled = 0; 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 if (sw->active) { 687 if (sw->active) {
677 enabled = 1; 688 enabled = 1;
678 break; 689 break;
679 } 690 }
680 } 691 }
681 - audio_notify_capture (cap, enabled); 692 + audio_capture_maybe_changed (cap, enabled);
682 } 693 }
683 694
684 static void audio_detach_capture (HWVoiceOut *hw) 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 if (sw->rate) { 705 if (sw->rate) {
690 st_rate_stop (sw->rate); 706 st_rate_stop (sw->rate);
691 sw->rate = NULL; 707 sw->rate = NULL;
692 } 708 }
693 709
694 LIST_REMOVE (sw, entries); 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,19 +726,21 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
704 726
705 audio_detach_capture (hw); 727 audio_detach_capture (hw);
706 for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { 728 for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
  729 + SWVoiceCap *sc;
707 SWVoiceOut *sw; 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 dolog ("Could not allocate soft capture voice (%zu bytes)\n", 735 dolog ("Could not allocate soft capture voice (%zu bytes)\n",
714 - sizeof (*sw)); 736 + sizeof (*sc));
715 return -1; 737 return -1;
716 } 738 }
717 739
718 - sw->info = hw->info; 740 + sc->cap = cap;
  741 + sw = &sc->sw;
719 sw->hw = hw_cap; 742 sw->hw = hw_cap;
  743 + sw->info = hw->info;
720 sw->empty = 1; 744 sw->empty = 1;
721 sw->active = hw->enabled; 745 sw->active = hw->enabled;
722 sw->conv = noop_conv; 746 sw->conv = noop_conv;
@@ -728,12 +752,14 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw) @@ -728,12 +752,14 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
728 return -1; 752 return -1;
729 } 753 }
730 LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); 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 if (sw->active) { 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 return 0; 765 return 0;
@@ -915,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) @@ -915,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
915 } 941 }
916 942
917 if (live == hwsamples) { 943 if (live == hwsamples) {
  944 +#ifdef DEBUG_OUT
  945 + dolog ("%s is full %d\n", sw->name, live);
  946 +#endif
918 return 0; 947 return 0;
919 } 948 }
920 949
@@ -1033,6 +1062,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) @@ -1033,6 +1062,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
1033 hw = sw->hw; 1062 hw = sw->hw;
1034 if (sw->active != on) { 1063 if (sw->active != on) {
1035 SWVoiceOut *temp_sw; 1064 SWVoiceOut *temp_sw;
  1065 + SWVoiceCap *sc;
1036 1066
1037 if (on) { 1067 if (on) {
1038 hw->pending_disable = 0; 1068 hw->pending_disable = 0;
@@ -1053,11 +1083,11 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) @@ -1053,11 +1083,11 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
1053 hw->pending_disable = nb_active == 1; 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 if (hw->enabled) { 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 sw->active = on; 1093 sw->active = on;
@@ -1156,9 +1186,10 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) @@ -1156,9 +1186,10 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
1156 int n; 1186 int n;
1157 1187
1158 if (hw->enabled) { 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 int rpos2 = rpos; 1193 int rpos2 = rpos;
1163 1194
1164 n = samples; 1195 n = samples;
@@ -1171,8 +1202,9 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) @@ -1171,8 +1202,9 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
1171 sw->buf = hw->mix_buf + rpos2; 1202 sw->buf = hw->mix_buf + rpos2;
1172 written = audio_pcm_sw_write (sw, NULL, bytes); 1203 written = audio_pcm_sw_write (sw, NULL, bytes);
1173 if (written - bytes) { 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 break; 1208 break;
1177 } 1209 }
1178 n -= to_write; 1210 n -= to_write;
@@ -1206,16 +1238,16 @@ static void audio_run_out (AudioState *s) @@ -1206,16 +1238,16 @@ static void audio_run_out (AudioState *s)
1206 } 1238 }
1207 1239
1208 if (hw->pending_disable && !nb_live) { 1240 if (hw->pending_disable && !nb_live) {
  1241 + SWVoiceCap *sc;
1209 #ifdef DEBUG_OUT 1242 #ifdef DEBUG_OUT
1210 dolog ("Disabling voice\n"); 1243 dolog ("Disabling voice\n");
1211 #endif 1244 #endif
1212 hw->enabled = 0; 1245 hw->enabled = 0;
1213 hw->pending_disable = 0; 1246 hw->pending_disable = 0;
1214 hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); 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 continue; 1252 continue;
1221 } 1253 }
@@ -1277,15 +1309,18 @@ static void audio_run_out (AudioState *s) @@ -1277,15 +1309,18 @@ static void audio_run_out (AudioState *s)
1277 } 1309 }
1278 1310
1279 if (cleanup_required) { 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 if (!sw->active && !sw->callback.fn) { 1317 if (!sw->active && !sw->callback.fn) {
1283 #ifdef DEBUG_PLIVE 1318 #ifdef DEBUG_PLIVE
1284 dolog ("Finishing with old voice\n"); 1319 dolog ("Finishing with old voice\n");
1285 #endif 1320 #endif
1286 audio_close_out (s, sw); 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,13 +1572,18 @@ static void audio_atexit (void)
1537 HWVoiceIn *hwi = NULL; 1572 HWVoiceIn *hwi = NULL;
1538 1573
1539 while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { 1574 while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
1540 - SWVoiceOut *sw; 1575 + SWVoiceCap *sc;
1541 1576
1542 hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); 1577 hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
1543 hwo->pcm_ops->fini_out (hwo); 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,7 +1737,7 @@ AudioState *AUD_init (void)
1697 return s; 1737 return s;
1698 } 1738 }
1699 1739
1700 -int AUD_add_capture ( 1740 +CaptureVoiceOut *AUD_add_capture (
1701 AudioState *s, 1741 AudioState *s,
1702 audsettings_t *as, 1742 audsettings_t *as,
1703 struct audio_capture_ops *ops, 1743 struct audio_capture_ops *ops,
@@ -1712,10 +1752,10 @@ int AUD_add_capture ( @@ -1712,10 +1752,10 @@ int AUD_add_capture (
1712 s = &glob_audio_state; 1752 s = &glob_audio_state;
1713 } 1753 }
1714 1754
1715 - if (audio_validate_settigs (as)) { 1755 + if (audio_validate_settings (as)) {
1716 dolog ("Invalid settings were passed when trying to add capture\n"); 1756 dolog ("Invalid settings were passed when trying to add capture\n");
1717 audio_print_settings (as); 1757 audio_print_settings (as);
1718 - return -1; 1758 + goto err0;
1719 } 1759 }
1720 1760
1721 cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); 1761 cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
@@ -1730,7 +1770,7 @@ int AUD_add_capture ( @@ -1730,7 +1770,7 @@ int AUD_add_capture (
1730 cap = audio_pcm_capture_find_specific (s, as); 1770 cap = audio_pcm_capture_find_specific (s, as);
1731 if (cap) { 1771 if (cap) {
1732 LIST_INSERT_HEAD (&cap->cb_head, cb, entries); 1772 LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
1733 - return 0; 1773 + return cap;
1734 } 1774 }
1735 else { 1775 else {
1736 HWVoiceOut *hw; 1776 HWVoiceOut *hw;
@@ -1780,7 +1820,7 @@ int AUD_add_capture ( @@ -1780,7 +1820,7 @@ int AUD_add_capture (
1780 while ((hw = audio_pcm_hw_find_any_out (s, hw))) { 1820 while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
1781 audio_attach_capture (s, hw); 1821 audio_attach_capture (s, hw);
1782 } 1822 }
1783 - return 0; 1823 + return cap;
1784 1824
1785 err3: 1825 err3:
1786 qemu_free (cap->hw.mix_buf); 1826 qemu_free (cap->hw.mix_buf);
@@ -1789,6 +1829,38 @@ int AUD_add_capture ( @@ -1789,6 +1829,38 @@ int AUD_add_capture (
1789 err1: 1829 err1:
1790 qemu_free (cb); 1830 qemu_free (cb);
1791 err0: 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,13 +49,31 @@ typedef struct {
49 int endianness; 49 int endianness;
50 } audsettings_t; 50 } audsettings_t;
51 51
  52 +typedef enum {
  53 + AUD_CNOTIFY_ENABLE,
  54 + AUD_CNOTIFY_DISABLE
  55 +} audcnotification_e;
  56 +
52 struct audio_capture_ops { 57 struct audio_capture_ops {
53 - void (*state) (void *opaque, int enabled); 58 + void (*notify) (void *opaque, audcnotification_e cmd);
54 void (*capture) (void *opaque, void *buf, int size); 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 typedef struct AudioState AudioState; 74 typedef struct AudioState AudioState;
58 typedef struct SWVoiceOut SWVoiceOut; 75 typedef struct SWVoiceOut SWVoiceOut;
  76 +typedef struct CaptureVoiceOut CaptureVoiceOut;
59 typedef struct SWVoiceIn SWVoiceIn; 77 typedef struct SWVoiceIn SWVoiceIn;
60 78
61 typedef struct QEMUSoundCard { 79 typedef struct QEMUSoundCard {
@@ -79,12 +97,13 @@ AudioState *AUD_init (void); @@ -79,12 +97,13 @@ AudioState *AUD_init (void);
79 void AUD_help (void); 97 void AUD_help (void);
80 void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); 98 void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
81 void AUD_remove_card (QEMUSoundCard *card); 99 void AUD_remove_card (QEMUSoundCard *card);
82 -int AUD_add_capture ( 100 +CaptureVoiceOut *AUD_add_capture (
83 AudioState *s, 101 AudioState *s,
84 audsettings_t *as, 102 audsettings_t *as,
85 struct audio_capture_ops *ops, 103 struct audio_capture_ops *ops,
86 void *opaque 104 void *opaque
87 ); 105 );
  106 +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
88 107
89 SWVoiceOut *AUD_open_out ( 108 SWVoiceOut *AUD_open_out (
90 QEMUSoundCard *card, 109 QEMUSoundCard *card,
audio/audio_int.h
@@ -64,10 +64,11 @@ struct audio_pcm_info { @@ -64,10 +64,11 @@ struct audio_pcm_info {
64 int swap_endianness; 64 int swap_endianness;
65 }; 65 };
66 66
  67 +typedef struct SWVoiceCap SWVoiceCap;
  68 +
67 typedef struct HWVoiceOut { 69 typedef struct HWVoiceOut {
68 int enabled; 70 int enabled;
69 int pending_disable; 71 int pending_disable;
70 - int valid;  
71 struct audio_pcm_info info; 72 struct audio_pcm_info info;
72 73
73 f_sample *clip; 74 f_sample *clip;
@@ -79,7 +80,7 @@ typedef struct HWVoiceOut { @@ -79,7 +80,7 @@ typedef struct HWVoiceOut {
79 80
80 int samples; 81 int samples;
81 LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; 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 struct audio_pcm_ops *pcm_ops; 84 struct audio_pcm_ops *pcm_ops;
84 LIST_ENTRY (HWVoiceOut) entries; 85 LIST_ENTRY (HWVoiceOut) entries;
85 } HWVoiceOut; 86 } HWVoiceOut;
@@ -116,7 +117,6 @@ struct SWVoiceOut { @@ -116,7 +117,6 @@ struct SWVoiceOut {
116 volume_t vol; 117 volume_t vol;
117 struct audio_callback callback; 118 struct audio_callback callback;
118 LIST_ENTRY (SWVoiceOut) entries; 119 LIST_ENTRY (SWVoiceOut) entries;
119 - LIST_ENTRY (SWVoiceOut) cap_entries;  
120 }; 120 };
121 121
122 struct SWVoiceIn { 122 struct SWVoiceIn {
@@ -168,12 +168,18 @@ struct capture_callback { @@ -168,12 +168,18 @@ struct capture_callback {
168 LIST_ENTRY (capture_callback) entries; 168 LIST_ENTRY (capture_callback) entries;
169 }; 169 };
170 170
171 -typedef struct CaptureVoiceOut { 171 +struct CaptureVoiceOut {
172 HWVoiceOut hw; 172 HWVoiceOut hw;
173 void *buf; 173 void *buf;
174 LIST_HEAD (cb_listhead, capture_callback) cb_head; 174 LIST_HEAD (cb_listhead, capture_callback) cb_head;
175 LIST_ENTRY (CaptureVoiceOut) entries; 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 struct AudioState { 184 struct AudioState {
179 struct audio_driver *drv; 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,7 +269,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
269 hw->pcm_ops = drv->pcm_ops; 269 hw->pcm_ops = drv->pcm_ops;
270 LIST_INIT (&hw->sw_head); 270 LIST_INIT (&hw->sw_head);
271 #ifdef DAC 271 #ifdef DAC
272 - LIST_INIT (&hw->sw_cap_head); 272 + LIST_INIT (&hw->cap_head);
273 #endif 273 #endif
274 if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { 274 if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
275 goto err0; 275 goto err0;
@@ -426,7 +426,7 @@ SW *glue (AUD_open_, TYPE) ( @@ -426,7 +426,7 @@ SW *glue (AUD_open_, TYPE) (
426 426
427 s = card->audio; 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 audio_print_settings (as); 430 audio_print_settings (as);
431 goto fail; 431 goto fail;
432 } 432 }
audio/noaudio.c
@@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw) @@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw)
102 NoVoiceIn *no = (NoVoiceIn *) hw; 102 NoVoiceIn *no = (NoVoiceIn *) hw;
103 int live = audio_pcm_hw_get_live_in (hw); 103 int live = audio_pcm_hw_get_live_in (hw);
104 int dead = hw->samples - live; 104 int dead = hw->samples - live;
105 - int samples; 105 + int samples = 0;
106 106
107 if (dead) { 107 if (dead) {
108 int64_t now = qemu_get_clock (vm_clock); 108 int64_t now = qemu_get_clock (vm_clock);
audio/wavcapture.c
@@ -3,6 +3,11 @@ @@ -3,6 +3,11 @@
3 typedef struct { 3 typedef struct {
4 QEMUFile *f; 4 QEMUFile *f;
5 int bytes; 5 int bytes;
  6 + char *path;
  7 + int freq;
  8 + int bits;
  9 + int nchannels;
  10 + CaptureVoiceOut *cap;
6 } WAVState; 11 } WAVState;
7 12
8 /* VICE code: Store number as little endian. */ 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,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 WAVState *wav = opaque; 57 WAVState *wav = opaque;
49 58
@@ -51,7 +60,30 @@ static void wav_capture_cb (void *opaque, void *buf, int size) @@ -51,7 +60,30 @@ static void wav_capture_cb (void *opaque, void *buf, int size)
51 wav->bytes += size; 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 WAVState *wav; 88 WAVState *wav;
57 uint8_t hdr[] = { 89 uint8_t hdr[] = {
@@ -62,23 +94,35 @@ void wav_capture (const char *path, int freq, int bits16, int stereo) @@ -62,23 +94,35 @@ void wav_capture (const char *path, int freq, int bits16, int stereo)
62 }; 94 };
63 audsettings_t as; 95 audsettings_t as;
64 struct audio_capture_ops ops; 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 as.freq = freq; 113 as.freq = freq;
71 as.nchannels = 1 << stereo; 114 as.nchannels = 1 << stereo;
72 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; 115 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
73 as.endianness = 0; 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 wav = qemu_mallocz (sizeof (*wav)); 122 wav = qemu_mallocz (sizeof (*wav));
79 if (!wav) { 123 if (!wav) {
80 AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav)); 124 AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav));
81 - return; 125 + return -1;
82 } 126 }
83 127
84 shift = bits16 + stereo; 128 shift = bits16 + stereo;
@@ -91,12 +135,28 @@ void wav_capture (const char *path, int freq, int bits16, int stereo) @@ -91,12 +135,28 @@ void wav_capture (const char *path, int freq, int bits16, int stereo)
91 135
92 wav->f = fopen (path, "wb"); 136 wav->f = fopen (path, "wb");
93 if (!wav->f) { 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 qemu_free (wav); 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 qemu_put_buffer (wav->f, hdr, sizeof (hdr)); 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,6 +1077,64 @@ static void do_info_profile(void)
1077 } 1077 }
1078 #endif 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 static term_cmd_t term_cmds[] = { 1138 static term_cmd_t term_cmds[] = {
1081 { "help|?", "s?", do_help, 1139 { "help|?", "s?", do_help,
1082 "[cmd]", "show the help" }, 1140 "[cmd]", "show the help" },
@@ -1133,6 +1191,13 @@ static term_cmd_t term_cmds[] = { @@ -1133,6 +1191,13 @@ static term_cmd_t term_cmds[] = {
1133 "dx dy [dz]", "send mouse move events" }, 1191 "dx dy [dz]", "send mouse move events" },
1134 { "mouse_button", "i", do_mouse_button, 1192 { "mouse_button", "i", do_mouse_button,
1135 "state", "change mouse button state (1=L, 2=M, 4=R)" }, 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 { NULL, NULL, }, 1201 { NULL, NULL, },
1137 }; 1202 };
1138 1203
@@ -1171,6 +1236,8 @@ static term_cmd_t info_cmds[] = { @@ -1171,6 +1236,8 @@ static term_cmd_t info_cmds[] = {
1171 "", "show host USB devices", }, 1236 "", "show host USB devices", },
1172 { "profile", "", do_info_profile, 1237 { "profile", "", do_info_profile,
1173 "", "show profiling information", }, 1238 "", "show profiling information", },
  1239 + { "capture", "", do_info_capture,
  1240 + "show capture information" },
1174 { NULL, NULL, }, 1241 { NULL, NULL, },
1175 }; 1242 };
1176 1243
@@ -2081,6 +2148,9 @@ static void monitor_handle_command(const char *cmdline) @@ -2081,6 +2148,9 @@ static void monitor_handle_command(const char *cmdline)
2081 case 6: 2148 case 6:
2082 cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); 2149 cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
2083 break; 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 default: 2154 default:
2085 term_printf("unsupported number of arguments: %d\n", nb_args); 2155 term_printf("unsupported number of arguments: %d\n", nb_args);
2086 goto fail; 2156 goto fail;