qemu/audio/wavcapture.c
<<
>>
Prefs
   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
   8typedef 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. */
  19static 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
  28static void wav_notify (void *opaque, audcnotification_e cmd)
  29{
  30    (void) opaque;
  31    (void) cmd;
  32}
  33
  34static 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
  76static 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
  87static 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
  95static 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
 105static struct capture_ops wav_capture_ops = {
 106    .destroy = wav_capture_destroy,
 107    .info = wav_capture_info
 108};
 109
 110int 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
 189error_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}
 198