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