blob: 6eb0efe38f1e35dc73f853af6d15b1594e6c4083
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 const inline al_format_info* get_al_format_info(ALCenum al_fmt) |
64 | { |
65 | static const 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 | AVCodecParameters *par = 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 | par = st->codecpar; |
160 | par->codec_type = AVMEDIA_TYPE_AUDIO; |
161 | par->sample_rate = ad->sample_rate; |
162 | par->channels = get_al_format_info(ad->sample_format)->channels; |
163 | par->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 | for (;;) { |
191 | /* Get number of samples available */ |
192 | alcGetIntegerv(ad->device, ALC_CAPTURE_SAMPLES, (ALCsizei) sizeof(ALCint), &nb_samples); |
193 | if (error = al_get_error(ad->device, &error_msg)) goto fail; |
194 | if (nb_samples > 0) |
195 | break; |
196 | if (ctx->flags & AVFMT_FLAG_NONBLOCK) |
197 | return AVERROR(EAGAIN); |
198 | av_usleep(1000); |
199 | } |
200 | |
201 | /* Create a packet of appropriate size */ |
202 | if ((error = av_new_packet(pkt, nb_samples*ad->sample_step)) < 0) |
203 | goto fail; |
204 | pkt->pts = av_gettime(); |
205 | |
206 | /* Fill the packet with the available samples */ |
207 | alcCaptureSamples(ad->device, pkt->data, nb_samples); |
208 | if (error = al_get_error(ad->device, &error_msg)) goto fail; |
209 | |
210 | return pkt->size; |
211 | fail: |
212 | /* Handle failure */ |
213 | if (pkt->data) |
214 | av_packet_unref(pkt); |
215 | if (error_msg) |
216 | av_log(ctx, AV_LOG_ERROR, "Error: %s\n", error_msg); |
217 | return error; |
218 | } |
219 | |
220 | static int read_close(AVFormatContext* ctx) |
221 | { |
222 | al_data *ad = ctx->priv_data; |
223 | |
224 | if (ad->device) { |
225 | alcCaptureStop(ad->device); |
226 | alcCaptureCloseDevice(ad->device); |
227 | } |
228 | return 0; |
229 | } |
230 | |
231 | #define OFFSET(x) offsetof(al_data, x) |
232 | |
233 | static const AVOption options[] = { |
234 | {"channels", "set number of channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AV_OPT_FLAG_DECODING_PARAM }, |
235 | {"sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, 192000, AV_OPT_FLAG_DECODING_PARAM }, |
236 | {"sample_size", "set sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64=16}, 8, 16, AV_OPT_FLAG_DECODING_PARAM }, |
237 | {"list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, |
238 | {"true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, |
239 | {"false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, |
240 | {NULL}, |
241 | }; |
242 | |
243 | static const AVClass class = { |
244 | .class_name = "openal", |
245 | .item_name = av_default_item_name, |
246 | .option = options, |
247 | .version = LIBAVUTIL_VERSION_INT, |
248 | .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, |
249 | }; |
250 | |
251 | AVInputFormat ff_openal_demuxer = { |
252 | .name = "openal", |
253 | .long_name = NULL_IF_CONFIG_SMALL("OpenAL audio capture device"), |
254 | .priv_data_size = sizeof(al_data), |
255 | .read_probe = NULL, |
256 | .read_header = read_header, |
257 | .read_packet = read_packet, |
258 | .read_close = read_close, |
259 | .flags = AVFMT_NOFILE, |
260 | .priv_class = &class |
261 | }; |
262 |