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