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
  42    if (wav->f) {
  43        le_store (rlen, rifflen, 4);
  44        le_store (dlen, datalen, 4);
  45
  46        if (fseek (wav->f, 4, SEEK_SET)) {
  47            error_report("wav_destroy: rlen fseek failed: %s",
  48                         strerror(errno));
  49            goto doclose;
  50        }
  51        if (fwrite (rlen, 4, 1, wav->f) != 1) {
  52            error_report("wav_destroy: rlen fwrite failed: %s",
  53                         strerror(errno));
  54            goto doclose;
  55        }
  56        if (fseek (wav->f, 32, SEEK_CUR)) {
  57            error_report("wav_destroy: dlen fseek failed: %s",
  58                         strerror(errno));
  59            goto doclose;
  60        }
  61        if (fwrite (dlen, 1, 4, wav->f) != 4) {
  62            error_report("wav_destroy: dlen fwrite failed: %s",
  63                         strerror(errno));
  64            goto doclose;
  65        }
  66    doclose:
  67        if (fclose (wav->f)) {
  68            error_report("wav_destroy: fclose failed: %s", strerror(errno));
  69        }
  70    }
  71
  72    g_free (wav->path);
  73}
  74
  75static void wav_capture (void *opaque, void *buf, int size)
  76{
  77    WAVState *wav = opaque;
  78
  79    if (fwrite (buf, size, 1, wav->f) != 1) {
  80        error_report("wav_capture: fwrite error: %s", strerror(errno));
  81    }
  82    wav->bytes += size;
  83}
  84
  85static void wav_capture_destroy (void *opaque)
  86{
  87    WAVState *wav = opaque;
  88
  89    AUD_del_capture (wav->cap, wav);
  90    g_free (wav);
  91}
  92
  93static void wav_capture_info (void *opaque)
  94{
  95    WAVState *wav = opaque;
  96    char *path = wav->path;
  97
  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);
 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)
 110{
 111    WAVState *wav;
 112    uint8_t hdr[] = {
 113        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
 114        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
 115        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
 116        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
 117    };
 118    struct audsettings as;
 119    struct audio_capture_ops ops;
 120    int stereo, bits16, shift;
 121    CaptureVoiceOut *cap;
 122
 123    if (bits != 8 && bits != 16) {
 124        error_report("incorrect bit count %d, must be 8 or 16", bits);
 125        return -1;
 126    }
 127
 128    if (nchannels != 1 && nchannels != 2) {
 129        error_report("incorrect channel count %d, must be 1 or 2",
 130                     nchannels);
 131        return -1;
 132    }
 133
 134    stereo = nchannels == 2;
 135    bits16 = bits == 16;
 136
 137    as.freq = freq;
 138    as.nchannels = 1 << stereo;
 139    as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
 140    as.endianness = 0;
 141
 142    ops.notify = wav_notify;
 143    ops.capture = wav_capture;
 144    ops.destroy = wav_destroy;
 145
 146    wav = g_malloc0 (sizeof (*wav));
 147
 148    shift = bits16 + stereo;
 149    hdr[34] = bits16 ? 0x10 : 0x08;
 150
 151    le_store (hdr + 22, as.nchannels, 2);
 152    le_store (hdr + 24, freq, 4);
 153    le_store (hdr + 28, freq << shift, 4);
 154    le_store (hdr + 32, 1 << shift, 2);
 155
 156    wav->f = fopen (path, "wb");
 157    if (!wav->f) {
 158        error_report("Failed to open wave file `%s': %s",
 159                     path, strerror(errno));
 160        g_free (wav);
 161        return -1;
 162    }
 163
 164    wav->path = g_strdup (path);
 165    wav->bits = bits;
 166    wav->nchannels = nchannels;
 167    wav->freq = freq;
 168
 169    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 170        error_report("Failed to write header: %s", strerror(errno));
 171        goto error_free;
 172    }
 173
 174    cap = AUD_add_capture (&as, &ops, wav);
 175    if (!cap) {
 176        error_report("Failed to add audio capture");
 177        goto error_free;
 178    }
 179
 180    wav->cap = cap;
 181    s->opaque = wav;
 182    s->ops = wav_capture_ops;
 183    return 0;
 184
 185error_free:
 186    g_free (wav->path);
 187    if (fclose (wav->f)) {
 188        error_report("Failed to close wave file: %s", strerror(errno));
 189    }
 190    g_free (wav);
 191    return -1;
 192}
 193