]> git.proxmox.com Git - mirror_qemu.git/blame - audio/wavcapture.c
core: replace getpagesize() with qemu_real_host_page_size
[mirror_qemu.git] / audio / wavcapture.c
CommitLineData
6086a565 1#include "qemu/osdep.h"
83c9089e 2#include "monitor/monitor.h"
e688df6b 3#include "qapi/error.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;
8ead62cf 40
e84a4fed
FB
41 if (wav->f) {
42 le_store (rlen, rifflen, 4);
43 le_store (dlen, datalen, 4);
f941aa25 44
b04df2a4 45 if (fseek (wav->f, 4, SEEK_SET)) {
8beaac12
DDAG
46 error_report("wav_destroy: rlen fseek failed: %s",
47 strerror(errno));
b04df2a4
JQ
48 goto doclose;
49 }
50 if (fwrite (rlen, 4, 1, wav->f) != 1) {
8beaac12
DDAG
51 error_report("wav_destroy: rlen fwrite failed: %s",
52 strerror(errno));
b04df2a4
JQ
53 goto doclose;
54 }
55 if (fseek (wav->f, 32, SEEK_CUR)) {
8beaac12
DDAG
56 error_report("wav_destroy: dlen fseek failed: %s",
57 strerror(errno));
b04df2a4
JQ
58 goto doclose;
59 }
60 if (fwrite (dlen, 1, 4, wav->f) != 4) {
8beaac12
DDAG
61 error_report("wav_destroy: dlen fwrite failed: %s",
62 strerror(errno));
b04df2a4
JQ
63 goto doclose;
64 }
65 doclose:
66 if (fclose (wav->f)) {
69e99504 67 error_report("wav_destroy: fclose failed: %s", strerror(errno));
b04df2a4 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 78 if (fwrite (buf, size, 1, wav->f) != 1) {
8beaac12 79 error_report("wav_capture: fwrite error: %s", strerror(errno));
b04df2a4 80 }
8ead62cf
FB
81 wav->bytes += size;
82}
83
ec36b695
FB
84static void wav_capture_destroy (void *opaque)
85{
86 WAVState *wav = opaque;
87
88 AUD_del_capture (wav->cap, wav);
7bdfd907 89 g_free (wav);
ec36b695
FB
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
ecd97e95
KZ
107int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
108 int freq, int bits, int nchannels)
8ead62cf
FB
109{
110 WAVState *wav;
111 uint8_t hdr[] = {
112 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
113 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
114 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
115 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
116 };
1ea879e5 117 struct audsettings as;
8ead62cf 118 struct audio_capture_ops ops;
ec36b695
FB
119 int stereo, bits16, shift;
120 CaptureVoiceOut *cap;
121
122 if (bits != 8 && bits != 16) {
8beaac12 123 error_report("incorrect bit count %d, must be 8 or 16", bits);
ec36b695
FB
124 return -1;
125 }
126
127 if (nchannels != 1 && nchannels != 2) {
8beaac12
DDAG
128 error_report("incorrect channel count %d, must be 1 or 2",
129 nchannels);
ec36b695
FB
130 return -1;
131 }
8ead62cf 132
ec36b695
FB
133 stereo = nchannels == 2;
134 bits16 = bits == 16;
8ead62cf
FB
135
136 as.freq = freq;
137 as.nchannels = 1 << stereo;
85bc5852 138 as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
d929eba5 139 as.endianness = 0;
8ead62cf 140
ec36b695
FB
141 ops.notify = wav_notify;
142 ops.capture = wav_capture;
143 ops.destroy = wav_destroy;
8ead62cf 144
7267c094 145 wav = g_malloc0 (sizeof (*wav));
8ead62cf
FB
146
147 shift = bits16 + stereo;
148 hdr[34] = bits16 ? 0x10 : 0x08;
149
150 le_store (hdr + 22, as.nchannels, 2);
151 le_store (hdr + 24, freq, 4);
152 le_store (hdr + 28, freq << shift, 4);
153 le_store (hdr + 32, 1 << shift, 2);
154
b04df2a4 155 wav->f = fopen (path, "wb");
8ead62cf 156 if (!wav->f) {
8beaac12
DDAG
157 error_report("Failed to open wave file `%s': %s",
158 path, strerror(errno));
7267c094 159 g_free (wav);
ec36b695 160 return -1;
8ead62cf
FB
161 }
162
7267c094 163 wav->path = g_strdup (path);
ec36b695
FB
164 wav->bits = bits;
165 wav->nchannels = nchannels;
166 wav->freq = freq;
167
b04df2a4 168 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
8beaac12 169 error_report("Failed to write header: %s", strerror(errno));
b04df2a4
JQ
170 goto error_free;
171 }
ec36b695 172
ecd97e95 173 cap = AUD_add_capture(state, &as, &ops, wav);
ec36b695 174 if (!cap) {
8beaac12 175 error_report("Failed to add audio capture");
b04df2a4 176 goto error_free;
ec36b695
FB
177 }
178
179 wav->cap = cap;
180 s->opaque = wav;
181 s->ops = wav_capture_ops;
182 return 0;
b04df2a4
JQ
183
184error_free:
185 g_free (wav->path);
186 if (fclose (wav->f)) {
8beaac12 187 error_report("Failed to close wave file: %s", strerror(errno));
b04df2a4
JQ
188 }
189 g_free (wav);
190 return -1;
8ead62cf 191}