ao_pulse: support native mute control
[mplayer.git] / libao2 / ao_pcm.c
blob4f593618d885d25b0d133ab9153a747d4e96c622
1 /*
2 * PCM audio output driver
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include <libavutil/common.h>
29 #include "talloc.h"
31 #include "subopt-helper.h"
32 #include "libaf/af_format.h"
33 #include "libaf/reorder_ch.h"
34 #include "audio_out.h"
35 #include "mp_msg.h"
37 #ifdef __MINGW32__
38 // for GetFileType to detect pipes
39 #include <windows.h>
40 #include <io.h>
41 #endif
43 struct priv {
44 char *outputfilename;
45 int waveheader;
46 uint64_t data_length;
47 FILE *fp;
50 #define WAV_ID_RIFF 0x46464952 /* "RIFF" */
51 #define WAV_ID_WAVE 0x45564157 /* "WAVE" */
52 #define WAV_ID_FMT 0x20746d66 /* "fmt " */
53 #define WAV_ID_DATA 0x61746164 /* "data" */
54 #define WAV_ID_PCM 0x0001
55 #define WAV_ID_FLOAT_PCM 0x0003
56 #define WAV_ID_FORMAT_EXTENSIBLE 0xfffe
58 static void fput16le(uint16_t val, FILE *fp)
60 uint8_t bytes[2] = {val, val >> 8};
61 fwrite(bytes, 1, 2, fp);
64 static void fput32le(uint32_t val, FILE *fp)
66 uint8_t bytes[4] = {val, val >> 8, val >> 16, val >> 24};
67 fwrite(bytes, 1, 4, fp);
70 static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length)
72 bool use_waveex = ao->channels >= 5 && ao->channels <= 8;
73 uint16_t fmt = ao->format == AF_FORMAT_FLOAT_LE ?
74 WAV_ID_FLOAT_PCM : WAV_ID_PCM;
75 uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
76 int bits = af_fmt2bits(ao->format);
78 // Master RIFF chunk
79 fput32le(WAV_ID_RIFF, fp);
80 // RIFF chunk size: 'WAVE' + 'fmt ' + 4 + fmt_chunk_size +
81 // data chunk hdr (8) + data length
82 fput32le(12 + fmt_chunk_size + 8 + data_length, fp);
83 fput32le(WAV_ID_WAVE, fp);
85 // Format chunk
86 fput32le(WAV_ID_FMT, fp);
87 fput32le(fmt_chunk_size, fp);
88 fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp);
89 fput16le(ao->channels, fp);
90 fput32le(ao->samplerate, fp);
91 fput32le(ao->bps, fp);
92 fput16le(ao->channels * (bits / 8), fp);
93 fput16le(bits, fp);
95 if (use_waveex) {
96 // Extension chunk
97 fput16le(22, fp);
98 fput16le(bits, fp);
99 switch (ao->channels) {
100 case 5:
101 fput32le(0x0607, fp); // L R C Lb Rb
102 break;
103 case 6:
104 fput32le(0x060f, fp); // L R C Lb Rb LFE
105 break;
106 case 7:
107 fput32le(0x0727, fp); // L R C Cb Ls Rs LFE
108 break;
109 case 8:
110 fput32le(0x063f, fp); // L R C Lb Rb Ls Rs LFE
111 break;
113 // 2 bytes format + 14 bytes guid
114 fput32le(fmt, fp);
115 fput32le(0x00100000, fp);
116 fput32le(0xAA000080, fp);
117 fput32le(0x719B3800, fp);
120 // Data chunk
121 fput32le(WAV_ID_DATA, fp);
122 fput32le(data_length, fp);
125 static int init(struct ao *ao, char *params)
127 struct priv *priv = talloc_zero(ao, struct priv);
128 ao->priv = priv;
130 int fast = 0;
131 const opt_t subopts[] = {
132 {"waveheader", OPT_ARG_BOOL, &priv->waveheader, NULL},
133 {"file", OPT_ARG_MSTRZ, &priv->outputfilename, NULL},
134 {"fast", OPT_ARG_BOOL, &fast, NULL},
135 {NULL}
137 // set defaults
138 priv->waveheader = 1;
140 if (subopt_parse(params, subopts) != 0)
141 return -1;
143 if (fast)
144 mp_msg(MSGT_AO, MSGL_WARN,
145 "[AO PCM] Suboption \"fast\" is deprecated.\n"
146 "[AO PCM] Use -novideo, or -benchmark if you want "
147 "faster playback with video.\n");
148 if (!priv->outputfilename)
149 priv->outputfilename =
150 strdup(priv->waveheader ? "audiodump.wav" : "audiodump.pcm");
151 if (priv->waveheader) {
152 // WAV files must have one of the following formats
154 switch (ao->format) {
155 case AF_FORMAT_U8:
156 case AF_FORMAT_S16_LE:
157 case AF_FORMAT_S24_LE:
158 case AF_FORMAT_S32_LE:
159 case AF_FORMAT_FLOAT_LE:
160 case AF_FORMAT_AC3_BE:
161 case AF_FORMAT_AC3_LE:
162 break;
163 default:
164 ao->format = AF_FORMAT_S16_LE;
165 break;
169 ao->outburst = 65536;
170 ao->bps = ao->channels * ao->samplerate * (af_fmt2bits(ao->format) / 8);
172 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\n"
173 "PCM: Samplerate: %d Hz Channels: %d Format: %s\n",
174 priv->outputfilename,
175 priv->waveheader ? "WAVE" : "RAW PCM", ao->samplerate,
176 ao->channels, af_fmt2str_short(ao->format));
177 mp_tmsg(MSGT_AO, MSGL_INFO,
178 "[AO PCM] Info: Faster dumping is achieved with -novideo\n"
179 "[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n");
181 priv->fp = fopen(priv->outputfilename, "wb");
182 if (!priv->fp) {
183 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO PCM] Failed to open %s for writing!\n",
184 priv->outputfilename);
185 return -1;
187 if (priv->waveheader) // Reserve space for wave header
188 write_wave_header(ao, priv->fp, 0x7ffff000);
189 ao->untimed = true;
191 return 0;
194 // close audio device
195 static void uninit(struct ao *ao, bool cut_audio)
197 struct priv *priv = ao->priv;
199 if (priv->waveheader) { // Rewrite wave header
200 bool broken_seek = false;
201 #ifdef __MINGW32__
202 // Windows, in its usual idiocy "emulates" seeks on pipes so it always
203 // looks like they work. So we have to detect them brute-force.
204 broken_seek = FILE_TYPE_DISK !=
205 GetFileType((HANDLE)_get_osfhandle(_fileno(priv->fp)));
206 #endif
207 if (broken_seek || fseek(priv->fp, 0, SEEK_SET) != 0)
208 mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, "
209 "WAV size headers not updated!\n");
210 else {
211 if (priv->data_length > 0xfffff000) {
212 mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for "
213 "WAV files, may play truncated!\n");
214 priv->data_length = 0xfffff000;
216 write_wave_header(ao, priv->fp, priv->data_length);
219 fclose(priv->fp);
220 free(priv->outputfilename);
223 static int get_space(struct ao *ao)
225 return ao->outburst;
228 static int play(struct ao *ao, void *data, int len, int flags)
230 struct priv *priv = ao->priv;
232 if (ao->channels == 5 || ao->channels == 6 || ao->channels == 8) {
233 int frame_size = af_fmt2bits(ao->format) / 8;
234 len -= len % (frame_size * ao->channels);
235 reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
236 AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
237 ao->channels, len / frame_size, frame_size);
239 fwrite(data, len, 1, priv->fp);
240 priv->data_length += len;
241 return len;
244 const struct ao_driver audio_out_pcm = {
245 .is_new = true,
246 .info = &(const struct ao_info) {
247 "RAW PCM/WAVE file writer audio output",
248 "pcm",
249 "Atmosfear",
252 .init = init,
253 .uninit = uninit,
254 .get_space = get_space,
255 .play = play,