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/avutil.h"
42 #include "libavutil/fifo.h"
44 static const ao_info_t info
= {
47 "KO Myung-Hun <komh@chollian.net>",
53 #define OUTBURST_SAMPLES 512
54 #define DEFAULT_SAMPLES (OUTBURST_SAMPLES << 2)
56 #define CHUNK_SIZE ao_data.outburst
58 static AVFifoBuffer
*m_audioBuf
;
60 static int m_nBufSize
= 0;
62 static volatile int m_fQuit
= FALSE
;
64 static KAISPEC m_kaiSpec
;
68 static int write_buffer(unsigned char *data
, int len
)
70 int nFree
= av_fifo_space(m_audioBuf
);
72 len
= FFMIN(len
, nFree
);
74 return av_fifo_generic_write(m_audioBuf
, data
, len
, NULL
);
77 static int read_buffer(unsigned char *data
, int len
)
79 int nBuffered
= av_fifo_size(m_audioBuf
);
81 len
= FFMIN(len
, nBuffered
);
83 av_fifo_generic_read(m_audioBuf
, data
, len
, NULL
);
87 // end ring buffer stuff
89 static ULONG APIENTRY
kai_audio_callback(PVOID pCBData
, PVOID pBuffer
,
94 nReadLen
= read_buffer(pBuffer
, ulSize
);
95 if (nReadLen
< ulSize
&& !m_fQuit
) {
96 memset((uint8_t *)pBuffer
+ nReadLen
, m_kaiSpec
.bSilence
, ulSize
- nReadLen
);
103 // to set/get/query special features/parameters
104 static int control(int cmd
, void *arg
)
107 case AOCONTROL_GET_VOLUME
:
109 ao_control_vol_t
*vol
= arg
;
111 vol
->left
= vol
->right
= kaiGetVolume(m_hkai
, MCI_STATUS_AUDIO_ALL
);
116 case AOCONTROL_SET_VOLUME
:
119 ao_control_vol_t
*vol
= arg
;
121 mid
= (vol
->left
+ vol
->right
) / 2;
122 kaiSetVolume(m_hkai
, MCI_SET_AUDIO_ALL
, mid
);
128 return CONTROL_UNKNOWN
;
131 static void print_help(void)
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"
139 " Use UNIAUD audio driver\n"
141 " Use DART audio driver\n"
143 " Open audio in shareable or exclusive mode\n"
145 " Set buffer size to <size> in samples(default: 2048)\n");
148 // open & set up audio device
149 // return: 1=success 0=fail
150 static int init(int rate
, int channels
, int format
, int flags
)
157 int nSamples
= DEFAULT_SAMPLES
;
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
},
169 const char *audioDriver
[] = {"DART", "UNIAUD",};
171 if (subopt_parse(ao_subdevice
, subopts
) != 0) {
176 if (fUseUniaud
&& fUseDart
)
177 mp_msg(MSGT_VO
, MSGL_WARN
,"KAI: Multiple mode specified!!!\n");
180 kaiMode
= KAIM_UNIAUD
;
186 if (kaiInit(kaiMode
)) {
187 mp_msg(MSGT_VO
, MSGL_ERR
, "KAI: Init failed!!!\n");
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
);
198 nSamples
= DEFAULT_SAMPLES
;
200 mp_msg(MSGT_AO
, MSGL_V
, "KAI: open in %s mode, buffer size = %d sample(s)\n",
201 fShare
? "shareable" : "exclusive", nSamples
);
204 case AF_FORMAT_S16_LE
:
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
));
215 nBytesPerSample
= (af_fmt2bits(format
) >> 3) * channels
;
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
;
229 if (kaiOpen(&ksWanted
, &m_kaiSpec
, &m_hkai
)) {
230 mp_msg(MSGT_VO
, MSGL_ERR
, "KAI: Open failed!!!\n");
234 mp_msg(MSGT_AO
, MSGL_V
, "KAI: obtained buffer count = %lu, size = %lu bytes\n",
235 m_kaiSpec
.ulNumBuffers
, m_kaiSpec
.ulBufferSize
);
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
;
246 m_nBufSize
= (m_kaiSpec
.ulBufferSize
* m_kaiSpec
.ulNumBuffers
) << 2;
248 // multiple of CHUNK_SIZE
249 m_nBufSize
= (m_nBufSize
/ CHUNK_SIZE
) * CHUNK_SIZE
;
251 // and one more chunk plus round up
252 m_nBufSize
+= 2 * CHUNK_SIZE
;
254 mp_msg(MSGT_AO
, MSGL_V
, "KAI: internal audio buffer size = %d bytes\n",
257 m_audioBuf
= av_fifo_alloc(m_nBufSize
);
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
);
269 // close audio device
270 static void uninit(int immed
)
275 while (kaiStatus(m_hkai
) & KAIS_PLAYING
)
282 av_fifo_free(m_audioBuf
);
285 // stop playing and empty buffers (for seeking/pause)
286 static void reset(void)
290 // Reset ring-buffer state
291 av_fifo_reset(m_audioBuf
);
296 // stop playing, keep buffers (for pause)
297 static void audio_pause(void)
302 // resume playing, after audio_pause()
303 static void audio_resume(void)
308 // return: how many bytes can be played without blocking
309 static int get_space(void)
311 return av_fifo_space(m_audioBuf
);
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
)
320 if (!(flags
& AOPLAY_FINAL_CHUNK
))
321 len
= (len
/ ao_data
.outburst
) * ao_data
.outburst
;
323 return write_buffer(data
, len
);
326 // return: delay in seconds between first and last sample in buffer
327 static float get_delay(void)
329 int nBuffered
= av_fifo_size(m_audioBuf
); // could be less
331 return (float)nBuffered
/ (float)ao_data
.bps
;