qemu/audio/wavcapture.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "qemu/qemu-print.h"
   3#include "qapi/error.h"
   4#include "qemu/error-report.h"
   5#include "audio.h"
   6
   7typedef struct {
   8    FILE *f;
   9    int bytes;
  10    char *path;
  11    int freq;
  12    int bits;
  13    int nchannels;
  14    CaptureVoiceOut *cap;
  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
  27static void wav_notify (void *opaque, audcnotification_e cmd)
  28{
  29    (void) opaque;
  30    (void) cmd;
  31}
  32
  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;
  40
  41    if (wav->f) {
  42        le_store (rlen, rifflen, 4);
  43        le_store (dlen, datalen, 4);
  44
  45        if (fseek (wav->f, 4, SEEK_SET)) {
  46            error_report("wav_destroy: rlen fseek failed: %s",
  47                         strerror(errno));
  48            goto doclose;
  49        }
  50        if (fwrite (rlen, 4, 1, wav->f) != 1) {
  51            error_report("wav_destroy: rlen fwrite failed: %s",
  52                         strerror(errno));
  53            goto doclose;
  54        }
  55        if (fseek (wav->f, 32, SEEK_CUR)) {
  56            error_report("wav_destroy: dlen fseek failed: %s",
  57                         strerror(errno));
  58            goto doclose;
  59        }
  60        if (fwrite (dlen, 1, 4, wav->f) != 4) {
  61            error_report("wav_destroy: dlen fwrite failed: %s",
  62                         strerror(errno));
  63            goto doclose;
  64        }
  65    doclose:
  66        if (fclose (wav->f)) {
  67            error_report("wav_destroy: fclose failed: %s", strerror(errno));
  68        }
  69    }
  70
  71    g_free (wav->path);
  72}
  73
  74static void wav_capture(void *opaque, const void *buf, int size)
  75{
  76    WAVState *wav = opaque;
  77
  78    if (fwrite (buf, size, 1, wav->f) != 1) {
  79        error_report("wav_capture: fwrite error: %s", strerror(errno));
  80    }
  81    wav->bytes += size;
  82}
  83
  84static void wav_capture_destroy (void *opaque)
  85{
  86    WAVState *wav = opaque;
  87
  88    AUD_del_capture (wav->cap, wav);
  89    g_free (wav);
  90}
  91
  92static void wav_capture_info (void *opaque)
  93{
  94    WAVState *wav = opaque;
  95    char *path = wav->path;
  96
  97    qemu_printf("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
  98                wav->freq, wav->bits, wav->nchannels,
  99                path ? path : "<not available>", wav->bytes);
 100}
 101
 102static struct capture_ops wav_capture_ops = {
 103    .destroy = wav_capture_destroy,
 104    .info = wav_capture_info
 105};
 106
 107int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
 108                      int freq, int bits, int nchannels)
 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    };
 117    struct audsettings as;
 118    struct audio_capture_ops ops;
 119    int stereo, bits16, shift;
 120    CaptureVoiceOut *cap;
 121
 122    if (bits != 8 && bits != 16) {
 123        error_report("incorrect bit count %d, must be 8 or 16", bits);
 124        return -1;
 125    }
 126
 127    if (nchannels != 1 && nchannels != 2) {
 128        error_report("incorrect channel count %d, must be 1 or 2",
 129                     nchannels);
 130        return -1;
 131    }
 132
 133    stereo = nchannels == 2;
 134    bits16 = bits == 16;
 135
 136    as.freq = freq;
 137    as.nchannels = 1 << stereo;
 138    as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
 139    as.endianness = 0;
 140
 141    ops.notify = wav_notify;
 142    ops.capture = wav_capture;
 143    ops.destroy = wav_destroy;
 144
 145    wav = g_malloc0 (sizeof (*wav));
 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
 155    wav->f = fopen (path, "wb");
 156    if (!wav->f) {
 157        error_report("Failed to open wave file `%s': %s",
 158                     path, strerror(errno));
 159        g_free (wav);
 160        return -1;
 161    }
 162
 163    wav->path = g_strdup (path);
 164    wav->bits = bits;
 165    wav->nchannels = nchannels;
 166    wav->freq = freq;
 167
 168    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 169        error_report("Failed to write header: %s", strerror(errno));
 170        goto error_free;
 171    }
 172
 173    cap = AUD_add_capture(state, &as, &ops, wav);
 174    if (!cap) {
 175        error_report("Failed to add audio capture");
 176        goto error_free;
 177    }
 178
 179    wav->cap = cap;
 180    s->opaque = wav;
 181    s->ops = wav_capture_ops;
 182    return 0;
 183
 184error_free:
 185    g_free (wav->path);
 186    if (fclose (wav->f)) {
 187        error_report("Failed to close wave file: %s", strerror(errno));
 188    }
 189    g_free (wav);
 190    return -1;
 191}
 192