| 1 | /* |
| 2 | * Copyright (c) 2011 Jonathan Baldwin |
| 3 | * |
| 4 | * This file is part of FFmpeg. |
| 5 | * |
| 6 | * Permission to use, copy, modify, and/or distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH |
| 11 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
| 12 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, |
| 13 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
| 14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
| 15 | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 16 | * PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | /** |
| 20 | * @file |
| 21 | * OpenAL 1.1 capture device for libavdevice |
| 22 | **/ |
| 23 | |
| 24 | #include <AL/al.h> |
| 25 | #include <AL/alc.h> |
| 26 | |
| 27 | #include "libavutil/opt.h" |
| 28 | #include "libavutil/time.h" |
| 29 | #include "libavformat/internal.h" |
| 30 | #include "avdevice.h" |
| 31 | |
| 32 | typedef struct { |
| 33 | AVClass *class; |
| 34 | /** OpenAL capture device context. **/ |
| 35 | ALCdevice *device; |
| 36 | /** The number of channels in the captured audio. **/ |
| 37 | int channels; |
| 38 | /** The sample rate (in Hz) of the captured audio. **/ |
| 39 | int sample_rate; |
| 40 | /** The sample size (in bits) of the captured audio. **/ |
| 41 | int sample_size; |
| 42 | /** The OpenAL sample format of the captured audio. **/ |
| 43 | ALCenum sample_format; |
| 44 | /** The number of bytes between two consecutive samples of the same channel/component. **/ |
| 45 | ALCint sample_step; |
| 46 | /** If true, print a list of capture devices on this system and exit. **/ |
| 47 | int list_devices; |
| 48 | } al_data; |
| 49 | |
| 50 | typedef struct { |
| 51 | ALCenum al_fmt; |
| 52 | enum AVCodecID codec_id; |
| 53 | int channels; |
| 54 | } al_format_info; |
| 55 | |
| 56 | #define LOWEST_AL_FORMAT FFMIN(FFMIN(AL_FORMAT_MONO8,AL_FORMAT_MONO16),FFMIN(AL_FORMAT_STEREO8,AL_FORMAT_STEREO16)) |
| 57 | |
| 58 | /** |
| 59 | * Get information about an AL_FORMAT value. |
| 60 | * @param al_fmt the AL_FORMAT value to find information about. |
| 61 | * @return A pointer to a structure containing information about the AL_FORMAT value. |
| 62 | */ |
| 63 | static inline al_format_info* get_al_format_info(ALCenum al_fmt) |
| 64 | { |
| 65 | static al_format_info info_table[] = { |
| 66 | [AL_FORMAT_MONO8-LOWEST_AL_FORMAT] = {AL_FORMAT_MONO8, AV_CODEC_ID_PCM_U8, 1}, |
| 67 | [AL_FORMAT_MONO16-LOWEST_AL_FORMAT] = {AL_FORMAT_MONO16, AV_NE (AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), 1}, |
| 68 | [AL_FORMAT_STEREO8-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO8, AV_CODEC_ID_PCM_U8, 2}, |
| 69 | [AL_FORMAT_STEREO16-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO16, AV_NE (AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), 2}, |
| 70 | }; |
| 71 | |
| 72 | return &info_table[al_fmt-LOWEST_AL_FORMAT]; |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Get the OpenAL error code, translated into an av/errno error code. |
| 77 | * @param device The ALC device to check for errors. |
| 78 | * @param error_msg_ret A pointer to a char* in which to return the error message, or NULL if desired. |
| 79 | * @return The error code, or 0 if there is no error. |
| 80 | */ |
| 81 | static inline int al_get_error(ALCdevice *device, const char** error_msg_ret) |
| 82 | { |
| 83 | ALCenum error = alcGetError(device); |
| 84 | if (error_msg_ret) |
| 85 | *error_msg_ret = (const char*) alcGetString(device, error); |
| 86 | switch (error) { |
| 87 | case ALC_NO_ERROR: |
| 88 | return 0; |
| 89 | case ALC_INVALID_DEVICE: |
| 90 | return AVERROR(ENODEV); |
| 91 | break; |
| 92 | case ALC_INVALID_CONTEXT: |
| 93 | case ALC_INVALID_ENUM: |
| 94 | case ALC_INVALID_VALUE: |
| 95 | return AVERROR(EINVAL); |
| 96 | break; |
| 97 | case ALC_OUT_OF_MEMORY: |
| 98 | return AVERROR(ENOMEM); |
| 99 | break; |
| 100 | default: |
| 101 | return AVERROR(EIO); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | /** |
| 106 | * Print out a list of OpenAL capture devices on this system. |
| 107 | */ |
| 108 | static inline void print_al_capture_devices(void *log_ctx) |
| 109 | { |
| 110 | const char *devices; |
| 111 | |
| 112 | if (!(devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER))) |
| 113 | return; |
| 114 | |
| 115 | av_log(log_ctx, AV_LOG_INFO, "List of OpenAL capture devices on this system:\n"); |
| 116 | |
| 117 | for (; *devices != '\0'; devices += strlen(devices) + 1) |
| 118 | av_log(log_ctx, AV_LOG_INFO, " %s\n", devices); |
| 119 | } |
| 120 | |
| 121 | static int read_header(AVFormatContext *ctx) |
| 122 | { |
| 123 | al_data *ad = ctx->priv_data; |
| 124 | static const ALCenum sample_formats[2][2] = { |
| 125 | { AL_FORMAT_MONO8, AL_FORMAT_STEREO8 }, |
| 126 | { AL_FORMAT_MONO16, AL_FORMAT_STEREO16 } |
| 127 | }; |
| 128 | int error = 0; |
| 129 | const char *error_msg; |
| 130 | AVStream *st = NULL; |
| 131 | AVCodecContext *codec = NULL; |
| 132 | |
| 133 | if (ad->list_devices) { |
| 134 | print_al_capture_devices(ctx); |
| 135 | return AVERROR_EXIT; |
| 136 | } |
| 137 | |
| 138 | ad->sample_format = sample_formats[ad->sample_size/8-1][ad->channels-1]; |
| 139 | |
| 140 | /* Open device for capture */ |
| 141 | ad->device = |
| 142 | alcCaptureOpenDevice(ctx->filename[0] ? ctx->filename : NULL, |
| 143 | ad->sample_rate, |
| 144 | ad->sample_format, |
| 145 | ad->sample_rate); /* Maximum 1 second of sample data to be read at once */ |
| 146 | |
| 147 | if (error = al_get_error(ad->device, &error_msg)) goto fail; |
| 148 | |
| 149 | /* Create stream */ |
| 150 | if (!(st = avformat_new_stream(ctx, NULL))) { |
| 151 | error = AVERROR(ENOMEM); |
| 152 | goto fail; |
| 153 | } |
| 154 | |
| 155 | /* We work in microseconds */ |
| 156 | avpriv_set_pts_info(st, 64, 1, 1000000); |
| 157 | |
| 158 | /* Set codec parameters */ |
| 159 | codec = st->codec; |
| 160 | codec->codec_type = AVMEDIA_TYPE_AUDIO; |
| 161 | codec->sample_rate = ad->sample_rate; |
| 162 | codec->channels = get_al_format_info(ad->sample_format)->channels; |
| 163 | codec->codec_id = get_al_format_info(ad->sample_format)->codec_id; |
| 164 | |
| 165 | /* This is needed to read the audio data */ |
| 166 | ad->sample_step = (av_get_bits_per_sample(get_al_format_info(ad->sample_format)->codec_id) * |
| 167 | get_al_format_info(ad->sample_format)->channels) / 8; |
| 168 | |
| 169 | /* Finally, start the capture process */ |
| 170 | alcCaptureStart(ad->device); |
| 171 | |
| 172 | return 0; |
| 173 | |
| 174 | fail: |
| 175 | /* Handle failure */ |
| 176 | if (ad->device) |
| 177 | alcCaptureCloseDevice(ad->device); |
| 178 | if (error_msg) |
| 179 | av_log(ctx, AV_LOG_ERROR, "Cannot open device: %s\n", error_msg); |
| 180 | return error; |
| 181 | } |
| 182 | |
| 183 | static int read_packet(AVFormatContext* ctx, AVPacket *pkt) |
| 184 | { |
| 185 | al_data *ad = ctx->priv_data; |
| 186 | int error=0; |
| 187 | const char *error_msg; |
| 188 | ALCint nb_samples; |
| 189 | |
| 190 | /* Get number of samples available */ |
| 191 | alcGetIntegerv(ad->device, ALC_CAPTURE_SAMPLES, (ALCsizei) sizeof(ALCint), &nb_samples); |
| 192 | if (error = al_get_error(ad->device, &error_msg)) goto fail; |
| 193 | |
| 194 | /* Create a packet of appropriate size */ |
| 195 | av_new_packet(pkt, nb_samples*ad->sample_step); |
| 196 | pkt->pts = av_gettime(); |
| 197 | |
| 198 | /* Fill the packet with the available samples */ |
| 199 | alcCaptureSamples(ad->device, pkt->data, nb_samples); |
| 200 | if (error = al_get_error(ad->device, &error_msg)) goto fail; |
| 201 | |
| 202 | return pkt->size; |
| 203 | fail: |
| 204 | /* Handle failure */ |
| 205 | if (pkt->data) |
| 206 | av_destruct_packet(pkt); |
| 207 | if (error_msg) |
| 208 | av_log(ctx, AV_LOG_ERROR, "Error: %s\n", error_msg); |
| 209 | return error; |
| 210 | } |
| 211 | |
| 212 | static int read_close(AVFormatContext* ctx) |
| 213 | { |
| 214 | al_data *ad = ctx->priv_data; |
| 215 | |
| 216 | if (ad->device) { |
| 217 | alcCaptureStop(ad->device); |
| 218 | alcCaptureCloseDevice(ad->device); |
| 219 | } |
| 220 | return 0; |
| 221 | } |
| 222 | |
| 223 | #define OFFSET(x) offsetof(al_data, x) |
| 224 | |
| 225 | static const AVOption options[] = { |
| 226 | {"channels", "set number of channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AV_OPT_FLAG_DECODING_PARAM }, |
| 227 | {"sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, 192000, AV_OPT_FLAG_DECODING_PARAM }, |
| 228 | {"sample_size", "set sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64=16}, 8, 16, AV_OPT_FLAG_DECODING_PARAM }, |
| 229 | {"list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, |
| 230 | {"true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, |
| 231 | {"false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, |
| 232 | {NULL}, |
| 233 | }; |
| 234 | |
| 235 | static const AVClass class = { |
| 236 | .class_name = "openal", |
| 237 | .item_name = av_default_item_name, |
| 238 | .option = options, |
| 239 | .version = LIBAVUTIL_VERSION_INT, |
| 240 | .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, |
| 241 | }; |
| 242 | |
| 243 | AVInputFormat ff_openal_demuxer = { |
| 244 | .name = "openal", |
| 245 | .long_name = NULL_IF_CONFIG_SMALL("OpenAL audio capture device"), |
| 246 | .priv_data_size = sizeof(al_data), |
| 247 | .read_probe = NULL, |
| 248 | .read_header = read_header, |
| 249 | .read_packet = read_packet, |
| 250 | .read_close = read_close, |
| 251 | .flags = AVFMT_NOFILE, |
| 252 | .priv_class = &class |
| 253 | }; |