Merge remote-tracking branch 'remotes/ericb/tags/pull-qapi-2018-04-10' into staging
[qemu/ar7.git] / audio / wavcapture.c
blobcf31ed652c2baf4d7fd7a716e822ca3b7f6b2205
1 #include "qemu/osdep.h"
2 #include "hw/hw.h"
3 #include "monitor/monitor.h"
4 #include "qapi/error.h"
5 #include "qemu/error-report.h"
6 #include "audio.h"
8 typedef struct {
9 FILE *f;
10 int bytes;
11 char *path;
12 int freq;
13 int bits;
14 int nchannels;
15 CaptureVoiceOut *cap;
16 } WAVState;
18 /* VICE code: Store number as little endian. */
19 static void le_store (uint8_t *buf, uint32_t val, int len)
21 int i;
22 for (i = 0; i < len; i++) {
23 buf[i] = (uint8_t) (val & 0xff);
24 val >>= 8;
28 static void wav_notify (void *opaque, audcnotification_e cmd)
30 (void) opaque;
31 (void) cmd;
34 static void wav_destroy (void *opaque)
36 WAVState *wav = opaque;
37 uint8_t rlen[4];
38 uint8_t dlen[4];
39 uint32_t datalen = wav->bytes;
40 uint32_t rifflen = datalen + 36;
41 Monitor *mon = cur_mon;
43 if (wav->f) {
44 le_store (rlen, rifflen, 4);
45 le_store (dlen, datalen, 4);
47 if (fseek (wav->f, 4, SEEK_SET)) {
48 monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
49 strerror (errno));
50 goto doclose;
52 if (fwrite (rlen, 4, 1, wav->f) != 1) {
53 monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
54 strerror (errno));
55 goto doclose;
57 if (fseek (wav->f, 32, SEEK_CUR)) {
58 monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
59 strerror (errno));
60 goto doclose;
62 if (fwrite (dlen, 1, 4, wav->f) != 4) {
63 monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
64 strerror (errno));
65 goto doclose;
67 doclose:
68 if (fclose (wav->f)) {
69 error_report("wav_destroy: fclose failed: %s", strerror(errno));
73 g_free (wav->path);
76 static void wav_capture (void *opaque, void *buf, int size)
78 WAVState *wav = opaque;
80 if (fwrite (buf, size, 1, wav->f) != 1) {
81 monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
82 strerror (errno));
84 wav->bytes += size;
87 static void wav_capture_destroy (void *opaque)
89 WAVState *wav = opaque;
91 AUD_del_capture (wav->cap, wav);
92 g_free (wav);
95 static void wav_capture_info (void *opaque)
97 WAVState *wav = opaque;
98 char *path = wav->path;
100 monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
101 wav->freq, wav->bits, wav->nchannels,
102 path ? path : "<not available>", wav->bytes);
105 static struct capture_ops wav_capture_ops = {
106 .destroy = wav_capture_destroy,
107 .info = wav_capture_info
110 int wav_start_capture (CaptureState *s, const char *path, int freq,
111 int bits, int nchannels)
113 Monitor *mon = cur_mon;
114 WAVState *wav;
115 uint8_t hdr[] = {
116 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
117 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
118 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
119 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
121 struct audsettings as;
122 struct audio_capture_ops ops;
123 int stereo, bits16, shift;
124 CaptureVoiceOut *cap;
126 if (bits != 8 && bits != 16) {
127 monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
128 return -1;
131 if (nchannels != 1 && nchannels != 2) {
132 monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
133 nchannels);
134 return -1;
137 stereo = nchannels == 2;
138 bits16 = bits == 16;
140 as.freq = freq;
141 as.nchannels = 1 << stereo;
142 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
143 as.endianness = 0;
145 ops.notify = wav_notify;
146 ops.capture = wav_capture;
147 ops.destroy = wav_destroy;
149 wav = g_malloc0 (sizeof (*wav));
151 shift = bits16 + stereo;
152 hdr[34] = bits16 ? 0x10 : 0x08;
154 le_store (hdr + 22, as.nchannels, 2);
155 le_store (hdr + 24, freq, 4);
156 le_store (hdr + 28, freq << shift, 4);
157 le_store (hdr + 32, 1 << shift, 2);
159 wav->f = fopen (path, "wb");
160 if (!wav->f) {
161 monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
162 path, strerror (errno));
163 g_free (wav);
164 return -1;
167 wav->path = g_strdup (path);
168 wav->bits = bits;
169 wav->nchannels = nchannels;
170 wav->freq = freq;
172 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
173 monitor_printf (mon, "Failed to write header\nReason: %s\n",
174 strerror (errno));
175 goto error_free;
178 cap = AUD_add_capture (&as, &ops, wav);
179 if (!cap) {
180 monitor_printf (mon, "Failed to add audio capture\n");
181 goto error_free;
184 wav->cap = cap;
185 s->opaque = wav;
186 s->ops = wav_capture_ops;
187 return 0;
189 error_free:
190 g_free (wav->path);
191 if (fclose (wav->f)) {
192 monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
193 strerror (errno));
195 g_free (wav);
196 return -1;