]> git.proxmox.com Git - qemu.git/blame - audio/wavcapture.c
qemu-iotests: exclude vmdk and qcow from 043
[qemu.git] / audio / wavcapture.c
CommitLineData
87ecb68b 1#include "hw/hw.h"
83c9089e 2#include "monitor/monitor.h"
87ecb68b 3#include "audio.h"
8ead62cf
FB
4
5typedef struct {
b04df2a4 6 FILE *f;
8ead62cf 7 int bytes;
ec36b695
FB
8 char *path;
9 int freq;
10 int bits;
11 int nchannels;
12 CaptureVoiceOut *cap;
8ead62cf
FB
13} WAVState;
14
15/* VICE code: Store number as little endian. */
16static void le_store (uint8_t *buf, uint32_t val, int len)
17{
18 int i;
19 for (i = 0; i < len; i++) {
20 buf[i] = (uint8_t) (val & 0xff);
21 val >>= 8;
22 }
23}
24
ec36b695 25static void wav_notify (void *opaque, audcnotification_e cmd)
8ead62cf 26{
ec36b695
FB
27 (void) opaque;
28 (void) cmd;
29}
8ead62cf 30
ec36b695
FB
31static void wav_destroy (void *opaque)
32{
33 WAVState *wav = opaque;
34 uint8_t rlen[4];
35 uint8_t dlen[4];
36 uint32_t datalen = wav->bytes;
37 uint32_t rifflen = datalen + 36;
b04df2a4 38 Monitor *mon = cur_mon;
8ead62cf 39
e84a4fed
FB
40 if (wav->f) {
41 le_store (rlen, rifflen, 4);
42 le_store (dlen, datalen, 4);
f941aa25 43
b04df2a4
JQ
44 if (fseek (wav->f, 4, SEEK_SET)) {
45 monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
46 strerror (errno));
47 goto doclose;
48 }
49 if (fwrite (rlen, 4, 1, wav->f) != 1) {
50 monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
51 strerror (errno));
52 goto doclose;
53 }
54 if (fseek (wav->f, 32, SEEK_CUR)) {
55 monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
56 strerror (errno));
57 goto doclose;
58 }
59 if (fwrite (dlen, 1, 4, wav->f) != 4) {
60 monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
61 strerror (errno));
62 goto doclose;
63 }
64 doclose:
65 if (fclose (wav->f)) {
66 fprintf (stderr, "wav_destroy: fclose failed: %s",
67 strerror (errno));
68 }
8ead62cf 69 }
f941aa25 70
7267c094 71 g_free (wav->path);
8ead62cf
FB
72}
73
ec36b695 74static void wav_capture (void *opaque, void *buf, int size)
8ead62cf
FB
75{
76 WAVState *wav = opaque;
77
b04df2a4
JQ
78 if (fwrite (buf, size, 1, wav->f) != 1) {
79 monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
80 strerror (errno));
81 }
8ead62cf
FB
82 wav->bytes += size;
83}
84
ec36b695
FB
85static void wav_capture_destroy (void *opaque)
86{
87 WAVState *wav = opaque;
88
89 AUD_del_capture (wav->cap, wav);
90}
91
92static void wav_capture_info (void *opaque)
93{
94 WAVState *wav = opaque;
95 char *path = wav->path;
96
b04df2a4
JQ
97 monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
98 wav->freq, wav->bits, wav->nchannels,
99 path ? path : "<not available>", wav->bytes);
ec36b695
FB
100}
101
102static struct capture_ops wav_capture_ops = {
103 .destroy = wav_capture_destroy,
104 .info = wav_capture_info
105};
106
107int wav_start_capture (CaptureState *s, const char *path, int freq,
108 int bits, int nchannels)
8ead62cf 109{
376253ec 110 Monitor *mon = cur_mon;
8ead62cf
FB
111 WAVState *wav;
112 uint8_t hdr[] = {
113 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
114 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
115 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
116 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
117 };
1ea879e5 118 struct audsettings as;
8ead62cf 119 struct audio_capture_ops ops;
ec36b695
FB
120 int stereo, bits16, shift;
121 CaptureVoiceOut *cap;
122
123 if (bits != 8 && bits != 16) {
b04df2a4 124 monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
ec36b695
FB
125 return -1;
126 }
127
128 if (nchannels != 1 && nchannels != 2) {
b04df2a4
JQ
129 monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
130 nchannels);
ec36b695
FB
131 return -1;
132 }
8ead62cf 133
ec36b695
FB
134 stereo = nchannels == 2;
135 bits16 = bits == 16;
8ead62cf
FB
136
137 as.freq = freq;
138 as.nchannels = 1 << stereo;
139 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
d929eba5 140 as.endianness = 0;
8ead62cf 141
ec36b695
FB
142 ops.notify = wav_notify;
143 ops.capture = wav_capture;
144 ops.destroy = wav_destroy;
8ead62cf 145
7267c094 146 wav = g_malloc0 (sizeof (*wav));
8ead62cf
FB
147
148 shift = bits16 + stereo;
149 hdr[34] = bits16 ? 0x10 : 0x08;
150
151 le_store (hdr + 22, as.nchannels, 2);
152 le_store (hdr + 24, freq, 4);
153 le_store (hdr + 28, freq << shift, 4);
154 le_store (hdr + 32, 1 << shift, 2);
155
b04df2a4 156 wav->f = fopen (path, "wb");
8ead62cf 157 if (!wav->f) {
b04df2a4
JQ
158 monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
159 path, strerror (errno));
7267c094 160 g_free (wav);
ec36b695 161 return -1;
8ead62cf
FB
162 }
163
7267c094 164 wav->path = g_strdup (path);
ec36b695
FB
165 wav->bits = bits;
166 wav->nchannels = nchannels;
167 wav->freq = freq;
168
b04df2a4
JQ
169 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
170 monitor_printf (mon, "Failed to write header\nReason: %s\n",
171 strerror (errno));
172 goto error_free;
173 }
ec36b695 174
1a7dafce 175 cap = AUD_add_capture (&as, &ops, wav);
ec36b695 176 if (!cap) {
b04df2a4
JQ
177 monitor_printf (mon, "Failed to add audio capture\n");
178 goto error_free;
ec36b695
FB
179 }
180
181 wav->cap = cap;
182 s->opaque = wav;
183 s->ops = wav_capture_ops;
184 return 0;
b04df2a4
JQ
185
186error_free:
187 g_free (wav->path);
188 if (fclose (wav->f)) {
189 monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
190 strerror (errno));
191 }
192 g_free (wav);
193 return -1;
8ead62cf 194}