Mercurial > mplayer.hg
annotate libao2/ao_kai.c @ 30610:b0f5b5d43941
TOOLS/realcodecs: Remove pointless '#if 1' preprocessor directives.
author | diego |
---|---|
date | Fri, 19 Feb 2010 09:46:31 +0000 |
parents | 2675229bd06f |
children | d50e20b4e441 |
rev | line source |
---|---|
30439 | 1 /* |
2 * OS/2 KAI audio output driver | |
3 * | |
4 * Copyright (c) 2010 by KO Myung-Hun (komh@chollian.net) | |
5 * | |
6 * This file is part of MPlayer. | |
7 * | |
8 * MPlayer is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * MPlayer is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License along | |
19 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 */ | |
22 | |
23 #define INCL_DOS | |
24 #define INCL_DOSERRORS | |
25 #include <os2.h> | |
26 | |
27 #include <stdio.h> | |
28 #include <stdlib.h> | |
29 #include <sys/time.h> | |
30 #include <float.h> | |
31 | |
32 #include <kai.h> | |
33 | |
34 #include "config.h" | |
35 #include "libaf/af_format.h" | |
36 #include "audio_out.h" | |
37 #include "audio_out_internal.h" | |
38 #include "mp_msg.h" | |
39 #include "libvo/fastmemcpy.h" | |
40 #include "subopt-helper.h" | |
41 #include "libavutil/fifo.h" | |
42 | |
43 static const ao_info_t info = { | |
44 "KAI audio output", | |
45 "kai", | |
46 "KO Myung-Hun <komh@chollian.net>", | |
47 "" | |
48 }; | |
49 | |
50 LIBAO_EXTERN(kai) | |
51 | |
52 #define OUTBURST_SAMPLES 512 | |
53 #define DEFAULT_SAMPLES (OUTBURST_SAMPLES << 2) | |
54 | |
55 #define CHUNK_SIZE ao_data.outburst | |
56 | |
57 static AVFifoBuffer *m_audioBuf; | |
58 | |
59 static int m_nBufSize = 0; | |
60 | |
61 static volatile int m_fQuit = FALSE; | |
62 | |
63 static KAISPEC m_kaiSpec; | |
64 | |
65 static HKAI m_hkai; | |
66 | |
67 static int write_buffer(unsigned char *data, int len) | |
68 { | |
69 int nFree = av_fifo_space(m_audioBuf); | |
70 | |
71 len = FFMIN(len, nFree); | |
72 | |
73 return av_fifo_generic_write(m_audioBuf, data, len, NULL); | |
74 } | |
75 | |
76 static int read_buffer(unsigned char *data, int len) | |
77 { | |
78 int nBuffered = av_fifo_size(m_audioBuf); | |
79 | |
80 len = FFMIN(len, nBuffered); | |
81 | |
82 av_fifo_generic_read(m_audioBuf, data, len, NULL); | |
83 return len; | |
84 } | |
85 | |
86 // end ring buffer stuff | |
87 | |
88 static ULONG APIENTRY kai_audio_callback(PVOID pCBData, PVOID pBuffer, | |
89 ULONG ulSize) | |
90 { | |
91 int nReadLen; | |
92 | |
93 nReadLen = read_buffer(pBuffer, ulSize); | |
94 if (nReadLen < ulSize && !m_fQuit) { | |
95 memset((uint8_t *)pBuffer + nReadLen, m_kaiSpec.bSilence, ulSize - nReadLen); | |
96 nReadLen = ulSize; | |
97 } | |
98 | |
99 return nReadLen; | |
100 } | |
101 | |
102 // to set/get/query special features/parameters | |
103 static int control(int cmd, void *arg) | |
104 { | |
105 switch (cmd) { | |
106 case AOCONTROL_GET_VOLUME: | |
107 { | |
108 ao_control_vol_t *vol = arg; | |
109 | |
110 vol->left = vol->right = kaiGetVolume(m_hkai, MCI_STATUS_AUDIO_ALL); | |
111 | |
112 return CONTROL_OK; | |
113 } | |
114 | |
115 case AOCONTROL_SET_VOLUME: | |
116 { | |
117 int mid; | |
118 ao_control_vol_t *vol = arg; | |
119 | |
120 mid = (vol->left + vol->right) / 2; | |
121 kaiSetVolume(m_hkai, MCI_SET_AUDIO_ALL, mid); | |
122 | |
123 return CONTROL_OK; | |
124 } | |
125 } | |
126 | |
127 return CONTROL_UNKNOWN; | |
128 } | |
129 | |
130 static void print_help(void) | |
131 { | |
132 mp_msg(MSGT_AO, MSGL_FATAL, | |
133 "\n-ao kai commandline help:\n" | |
134 "Example: mplayer -ao kai:noshare\n" | |
135 " open audio in exclusive mode\n" | |
136 "\nOptions:\n" | |
137 " uniaud\n" | |
138 " Use UNIAUD audio driver\n" | |
139 " dart\n" | |
140 " Use DART audio driver\n" | |
141 " (no)share\n" | |
142 " Open audio in shareable or exclusive mode\n" | |
143 " bufsize=<size>\n" | |
144 " Set buffer size to <size> in samples(default: 2048)\n"); | |
145 } | |
146 | |
147 // open & set up audio device | |
148 // return: 1=success 0=fail | |
149 static int init(int rate, int channels, int format, int flags) | |
150 { | |
151 int fUseUniaud = 0; | |
152 int fUseDart = 0; | |
153 int fShare = 1; | |
154 ULONG kaiMode; | |
155 KAICAPS kc; | |
156 int nSamples = DEFAULT_SAMPLES; | |
157 int nBytesPerSample; | |
158 KAISPEC ksWanted; | |
159 | |
160 const opt_t subopts[] = { | |
161 {"uniaud", OPT_ARG_BOOL, &fUseUniaud, NULL}, | |
162 {"dart", OPT_ARG_BOOL, &fUseDart, NULL}, | |
163 {"share", OPT_ARG_BOOL, &fShare, NULL}, | |
164 {"bufsize", OPT_ARG_INT, &nSamples, int_non_neg}, | |
165 {NULL} | |
166 }; | |
167 | |
168 const char *audioDriver[] = {"DART", "UNIAUD",}; | |
169 | |
170 if (subopt_parse(ao_subdevice, subopts) != 0) { | |
171 print_help(); | |
172 return 0; | |
173 } | |
174 | |
175 if (fUseUniaud && fUseDart) | |
176 mp_msg(MSGT_VO, MSGL_WARN,"KAI: Multiple mode specified!!!\n"); | |
177 | |
178 if (fUseUniaud) | |
179 kaiMode = KAIM_UNIAUD; | |
180 else if (fUseDart) | |
181 kaiMode = KAIM_DART; | |
182 else | |
183 kaiMode = KAIM_AUTO; | |
184 | |
185 if (kaiInit(kaiMode)) { | |
186 mp_msg(MSGT_VO, MSGL_ERR, "KAI: Init failed!!!\n"); | |
187 return 0; | |
188 } | |
189 | |
190 kaiCaps(&kc); | |
191 mp_msg(MSGT_AO, MSGL_V, "KAI: selected audio driver = %s\n", | |
192 audioDriver[kc.ulMode - 1]); | |
193 mp_msg(MSGT_AO, MSGL_V, "KAI: PDD name = %s, maximum channels = %lu\n", | |
194 kc.szPDDName, kc.ulMaxChannels); | |
195 | |
196 if (!nSamples) | |
197 nSamples = DEFAULT_SAMPLES; | |
198 | |
199 mp_msg(MSGT_AO, MSGL_V, "KAI: open in %s mode, buffer size = %d sample(s)\n", | |
200 fShare ? "shareable" : "exclusive", nSamples); | |
201 | |
202 switch (format) { | |
203 case AF_FORMAT_S16_LE: | |
204 case AF_FORMAT_S8: | |
205 break; | |
206 | |
207 default: | |
208 format = AF_FORMAT_S16_LE; | |
209 mp_msg(MSGT_AO, MSGL_V, "KAI: format %s not supported defaulting to Signed 16-bit Little-Endian\n", | |
210 af_fmt2str_short(format)); | |
211 break; | |
212 } | |
213 | |
214 nBytesPerSample = (af_fmt2bits(format) >> 3) * channels; | |
215 | |
216 ksWanted.usDeviceIndex = 0; | |
217 ksWanted.ulType = KAIT_PLAY; | |
218 ksWanted.ulBitsPerSample = af_fmt2bits(format); | |
219 ksWanted.ulSamplingRate = rate; | |
220 ksWanted.ulDataFormat = MCI_WAVE_FORMAT_PCM; | |
221 ksWanted.ulChannels = channels; | |
222 ksWanted.ulNumBuffers = 2; | |
223 ksWanted.ulBufferSize = nBytesPerSample * nSamples; | |
224 ksWanted.fShareable = fShare; | |
225 ksWanted.pfnCallBack = kai_audio_callback; | |
226 ksWanted.pCallBackData = NULL; | |
227 | |
228 if (kaiOpen(&ksWanted, &m_kaiSpec, &m_hkai)) { | |
229 mp_msg(MSGT_VO, MSGL_ERR, "KAI: Open failed!!!\n"); | |
230 return 0; | |
231 } | |
232 | |
233 mp_msg(MSGT_AO, MSGL_V, "KAI: obtained buffer count = %lu, size = %lu bytes\n", | |
234 m_kaiSpec.ulNumBuffers, m_kaiSpec.ulBufferSize); | |
235 | |
236 m_fQuit = FALSE; | |
237 | |
238 ao_data.channels = channels; | |
239 ao_data.samplerate = rate; | |
240 ao_data.format = format; | |
241 ao_data.bps = nBytesPerSample * rate; | |
242 ao_data.outburst = nBytesPerSample * OUTBURST_SAMPLES; | |
243 ao_data.buffersize = m_kaiSpec.ulBufferSize; | |
244 | |
30460
2675229bd06f
Audio buffer is too large so that it takes too long time to respond to audio
komh
parents:
30439
diff
changeset
|
245 m_nBufSize = (m_kaiSpec.ulBufferSize * m_kaiSpec.ulNumBuffers) << 2; |
30439 | 246 |
247 // multiple of CHUNK_SIZE | |
248 m_nBufSize = (m_nBufSize / CHUNK_SIZE) * CHUNK_SIZE; | |
249 | |
250 // and one more chunk plus round up | |
251 m_nBufSize += 2 * CHUNK_SIZE; | |
252 | |
253 mp_msg(MSGT_AO, MSGL_V, "KAI: internal audio buffer size = %d bytes\n", | |
254 m_nBufSize); | |
255 | |
256 m_audioBuf = av_fifo_alloc(m_nBufSize); | |
257 | |
258 kaiPlay(m_hkai); | |
259 | |
260 // might cause PM DLLs to be loaded which incorrectly enable SIG_FPE, | |
261 // which AAC decoding might trigger. | |
262 // so, mask off all floating-point exceptions. | |
263 _control87(MCW_EM, MCW_EM); | |
264 | |
265 return 1; | |
266 } | |
267 | |
268 // close audio device | |
269 static void uninit(int immed) | |
270 { | |
271 m_fQuit = TRUE; | |
272 | |
273 if (!immed) | |
274 while (kaiStatus(m_hkai) & KAIS_PLAYING) | |
275 DosSleep(1); | |
276 | |
277 kaiClose(m_hkai); | |
278 | |
279 kaiDone(); | |
280 | |
281 av_fifo_free(m_audioBuf); | |
282 } | |
283 | |
284 // stop playing and empty buffers (for seeking/pause) | |
285 static void reset(void) | |
286 { | |
287 kaiPause(m_hkai); | |
288 | |
289 // Reset ring-buffer state | |
290 av_fifo_reset(m_audioBuf); | |
291 | |
292 kaiResume(m_hkai); | |
293 } | |
294 | |
295 // stop playing, keep buffers (for pause) | |
296 static void audio_pause(void) | |
297 { | |
298 kaiPause(m_hkai); | |
299 } | |
300 | |
301 // resume playing, after audio_pause() | |
302 static void audio_resume(void) | |
303 { | |
304 kaiResume(m_hkai); | |
305 } | |
306 | |
307 // return: how many bytes can be played without blocking | |
308 static int get_space(void) | |
309 { | |
310 return av_fifo_space(m_audioBuf); | |
311 } | |
312 | |
313 // plays 'len' bytes of 'data' | |
314 // it should round it down to outburst*n | |
315 // return: number of bytes played | |
316 static int play(void *data, int len, int flags) | |
317 { | |
318 | |
319 if (!(flags & AOPLAY_FINAL_CHUNK)) | |
320 len = (len / ao_data.outburst) * ao_data.outburst; | |
321 | |
322 return write_buffer(data, len); | |
323 } | |
324 | |
325 // return: delay in seconds between first and last sample in buffer | |
326 static float get_delay(void) | |
327 { | |
328 int nBuffered = av_fifo_size(m_audioBuf); // could be less | |
329 | |
330 return (float)nBuffered / (float)ao_data.bps; | |
331 } |