2 * OS/2 KAI audio output driver
4 * Copyright (c) 2010 by KO Myung-Hun (komh@chollian.net)
6 * This file is part of MPlayer.
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.
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.
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.
24 #define INCL_DOSERRORS
35 #include "libaf/af_format.h"
36 #include "audio_out.h"
37 #include "audio_out_internal.h"
39 #include "libvo/fastmemcpy.h"
40 #include "subopt-helper.h"
41 #include "libavutil/fifo.h"
43 static const ao_info_t info
= {
46 "KO Myung-Hun <komh@chollian.net>",
52 #define OUTBURST_SAMPLES 512
53 #define DEFAULT_SAMPLES (OUTBURST_SAMPLES << 2)
55 #define CHUNK_SIZE ao_data.outburst
57 static AVFifoBuffer
*m_audioBuf
;
59 static int m_nBufSize
= 0;
61 static volatile int m_fQuit
= FALSE
;
63 static KAISPEC m_kaiSpec
;
67 static int write_buffer(unsigned char *data
, int len
)
69 int nFree
= av_fifo_space(m_audioBuf
);
71 len
= FFMIN(len
, nFree
);
73 return av_fifo_generic_write(m_audioBuf
, data
, len
, NULL
);
76 static int read_buffer(unsigned char *data
, int len
)
78 int nBuffered
= av_fifo_size(m_audioBuf
);
80 len
= FFMIN(len
, nBuffered
);
82 av_fifo_generic_read(m_audioBuf
, data
, len
, NULL
);
86 // end ring buffer stuff
88 static ULONG APIENTRY
kai_audio_callback(PVOID pCBData
, PVOID pBuffer
,
93 nReadLen
= read_buffer(pBuffer
, ulSize
);
94 if (nReadLen
< ulSize
&& !m_fQuit
) {
95 memset((uint8_t *)pBuffer
+ nReadLen
, m_kaiSpec
.bSilence
, ulSize
- nReadLen
);
102 // to set/get/query special features/parameters
103 static int control(int cmd
, void *arg
)
106 case AOCONTROL_GET_VOLUME
:
108 ao_control_vol_t
*vol
= arg
;
110 vol
->left
= vol
->right
= kaiGetVolume(m_hkai
, MCI_STATUS_AUDIO_ALL
);
115 case AOCONTROL_SET_VOLUME
:
118 ao_control_vol_t
*vol
= arg
;
120 mid
= (vol
->left
+ vol
->right
) / 2;
121 kaiSetVolume(m_hkai
, MCI_SET_AUDIO_ALL
, mid
);
127 return CONTROL_UNKNOWN
;
130 static void print_help(void)
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"
138 " Use UNIAUD audio driver\n"
140 " Use DART audio driver\n"
142 " Open audio in shareable or exclusive mode\n"
144 " Set buffer size to <size> in samples(default: 2048)\n");
147 // open & set up audio device
148 // return: 1=success 0=fail
149 static int init(int rate
, int channels
, int format
, int flags
)
156 int nSamples
= DEFAULT_SAMPLES
;
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
},
168 const char *audioDriver
[] = {"DART", "UNIAUD",};
170 if (subopt_parse(ao_subdevice
, subopts
) != 0) {
175 if (fUseUniaud
&& fUseDart
)
176 mp_msg(MSGT_VO
, MSGL_WARN
,"KAI: Multiple mode specified!!!\n");
179 kaiMode
= KAIM_UNIAUD
;
185 if (kaiInit(kaiMode
)) {
186 mp_msg(MSGT_VO
, MSGL_ERR
, "KAI: Init failed!!!\n");
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
);
197 nSamples
= DEFAULT_SAMPLES
;
199 mp_msg(MSGT_AO
, MSGL_V
, "KAI: open in %s mode, buffer size = %d sample(s)\n",
200 fShare
? "shareable" : "exclusive", nSamples
);
203 case AF_FORMAT_S16_LE
:
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
));
214 nBytesPerSample
= (af_fmt2bits(format
) >> 3) * channels
;
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
;
228 if (kaiOpen(&ksWanted
, &m_kaiSpec
, &m_hkai
)) {
229 mp_msg(MSGT_VO
, MSGL_ERR
, "KAI: Open failed!!!\n");
233 mp_msg(MSGT_AO
, MSGL_V
, "KAI: obtained buffer count = %lu, size = %lu bytes\n",
234 m_kaiSpec
.ulNumBuffers
, m_kaiSpec
.ulBufferSize
);
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
;
245 m_nBufSize
= (m_kaiSpec
.ulBufferSize
* m_kaiSpec
.ulNumBuffers
) << 2;
247 // multiple of CHUNK_SIZE
248 m_nBufSize
= (m_nBufSize
/ CHUNK_SIZE
) * CHUNK_SIZE
;
250 // and one more chunk plus round up
251 m_nBufSize
+= 2 * CHUNK_SIZE
;
253 mp_msg(MSGT_AO
, MSGL_V
, "KAI: internal audio buffer size = %d bytes\n",
256 m_audioBuf
= av_fifo_alloc(m_nBufSize
);
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
);
268 // close audio device
269 static void uninit(int immed
)
274 while (kaiStatus(m_hkai
) & KAIS_PLAYING
)
281 av_fifo_free(m_audioBuf
);
284 // stop playing and empty buffers (for seeking/pause)
285 static void reset(void)
289 // Reset ring-buffer state
290 av_fifo_reset(m_audioBuf
);
295 // stop playing, keep buffers (for pause)
296 static void audio_pause(void)
301 // resume playing, after audio_pause()
302 static void audio_resume(void)
307 // return: how many bytes can be played without blocking
308 static int get_space(void)
310 return av_fifo_space(m_audioBuf
);
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
)
319 if (!(flags
& AOPLAY_FINAL_CHUNK
))
320 len
= (len
/ ao_data
.outburst
) * ao_data
.outburst
;
322 return write_buffer(data
, len
);
325 // return: delay in seconds between first and last sample in buffer
326 static float get_delay(void)
328 int nBuffered
= av_fifo_size(m_audioBuf
); // could be less
330 return (float)nBuffered
/ (float)ao_data
.bps
;