]> Git Repo - qemu.git/blob - audio/wavcapture.c
Merge remote-tracking branch 'remotes/armbru/tags/pull-misc-2018-02-07-v4' into staging
[qemu.git] / audio / wavcapture.c
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"
7
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;
17
18 /* VICE code: Store number as little endian. */
19 static void le_store (uint8_t *buf, uint32_t val, int len)
20 {
21     int i;
22     for (i = 0; i < len; i++) {
23         buf[i] = (uint8_t) (val & 0xff);
24         val >>= 8;
25     }
26 }
27
28 static void wav_notify (void *opaque, audcnotification_e cmd)
29 {
30     (void) opaque;
31     (void) cmd;
32 }
33
34 static void wav_destroy (void *opaque)
35 {
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;
42
43     if (wav->f) {
44         le_store (rlen, rifflen, 4);
45         le_store (dlen, datalen, 4);
46
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;
51         }
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;
56         }
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;
61         }
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;
66         }
67     doclose:
68         if (fclose (wav->f)) {
69             error_report("wav_destroy: fclose failed: %s", strerror(errno));
70         }
71     }
72
73     g_free (wav->path);
74 }
75
76 static void wav_capture (void *opaque, void *buf, int size)
77 {
78     WAVState *wav = opaque;
79
80     if (fwrite (buf, size, 1, wav->f) != 1) {
81         monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
82                         strerror (errno));
83     }
84     wav->bytes += size;
85 }
86
87 static void wav_capture_destroy (void *opaque)
88 {
89     WAVState *wav = opaque;
90
91     AUD_del_capture (wav->cap, wav);
92     g_free (wav);
93 }
94
95 static void wav_capture_info (void *opaque)
96 {
97     WAVState *wav = opaque;
98     char *path = wav->path;
99
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);
103 }
104
105 static struct capture_ops wav_capture_ops = {
106     .destroy = wav_capture_destroy,
107     .info = wav_capture_info
108 };
109
110 int wav_start_capture (CaptureState *s, const char *path, int freq,
111                        int bits, int nchannels)
112 {
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
120     };
121     struct audsettings as;
122     struct audio_capture_ops ops;
123     int stereo, bits16, shift;
124     CaptureVoiceOut *cap;
125
126     if (bits != 8 && bits != 16) {
127         monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
128         return -1;
129     }
130
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;
135     }
136
137     stereo = nchannels == 2;
138     bits16 = bits == 16;
139
140     as.freq = freq;
141     as.nchannels = 1 << stereo;
142     as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
143     as.endianness = 0;
144
145     ops.notify = wav_notify;
146     ops.capture = wav_capture;
147     ops.destroy = wav_destroy;
148
149     wav = g_malloc0 (sizeof (*wav));
150
151     shift = bits16 + stereo;
152     hdr[34] = bits16 ? 0x10 : 0x08;
153
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);
158
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;
165     }
166
167     wav->path = g_strdup (path);
168     wav->bits = bits;
169     wav->nchannels = nchannels;
170     wav->freq = freq;
171
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;
176     }
177
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;
182     }
183
184     wav->cap = cap;
185     s->opaque = wav;
186     s->ops = wav_capture_ops;
187     return 0;
188
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));
194     }
195     g_free (wav);
196     return -1;
197 }
This page took 0.035121 seconds and 4 git commands to generate.