Commit 26564eaa authored by KO Myung-Hun's avatar KO Myung-Hun Committed by Rémi Denis-Courmont

Add KAI audio output module for OS/2

Signed-off-by: default avatarRémi Denis-Courmont <remi@remlab.net>
parent 1d623791
......@@ -3589,6 +3589,29 @@ dnl libsamplerate plugin
dnl
PKG_ENABLE_MODULES_VLC([SAMPLERATE], [], [samplerate], [Resampler with libsamplerate], [auto])
dnl
dnl OS/2 KAI plugin
dnl
AC_ARG_ENABLE(kai,
[AS_HELP_STRING([--enable-kai],
[support the K Audio Interface KAI (default enabled on OS/2)])],, [
AS_IF([test "$SYS" = "os2"], [
enable_kai="yes"
])
])
have_kai="no"
KAI_LIBS=""
AS_IF([test "$enable_kai" != "no"], [
AC_CHECK_HEADERS([kai.h], [
have_kai="yes"
AC_CHECK_LIB(kai, main, [
KAI_LIBS="-lkai"
])
])
])
AC_SUBST(KAI_LIBS)
AM_CONDITIONAL([HAVE_KAI], [test "${have_kai}" = "yes"])
dnl
dnl Interface plugins
dnl
......
......@@ -45,3 +45,11 @@ libpulse_plugin_la_DEPENDENCIES =
if HAVE_PULSE
libvlc_LTLIBRARIES += libpulse_plugin.la
endif
libkai_plugin_la_SOURCES = kai.c
libkai_plugin_la_CFLAGS = $(AM_CFLAGS)
libkai_plugin_la_LIBADD = $(AM_LIBADD) $(KAI_LIBS)
libkai_plugin_la_DEPENDENCIES =
if HAVE_KAI
libvlc_LTLIBRARIES += libkai_plugin.la
endif
/*****************************************************************************
* kai.c : KAI audio output plugin for vlc
*****************************************************************************
* Copyright (C) 2010 the VideoLAN team
*
* Authors: KO Myung-Hun <komh@chollian.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_aout.h>
#include <float.h>
#include <kai.h>
#define FRAME_SIZE 2048
/*****************************************************************************
* aout_sys_t: KAI audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the specific properties of an audio device.
*****************************************************************************/
struct aout_sys_t
{
aout_packet_t packet;
HKAI hkai;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static void Play ( audio_output_t *_p_aout, block_t *block );
static ULONG APIENTRY KaiCallback ( PVOID, PVOID, ULONG );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define KAI_AUDIO_DEVICE_TEXT N_( \
"Device" )
#define KAI_AUDIO_DEVICE_LONGTEXT N_( \
"Select a proper audio device to be used by KAI." )
#define KAI_AUDIO_EXCLUSIVE_MODE_TEXT N_( \
"Open audio in exclusive mode." )
#define KAI_AUDIO_EXCLUSIVE_MODE_LONGTEXT N_( \
"Enable this option if you want your audio not to be interrupted by the " \
"other audio." )
static const char *const ppsz_kai_audio_device[] = {
"auto", "dart", "uniaud" };
static const char *const ppsz_kai_audio_device_text[] = {
N_("Auto"), "DART", "UNIAUD" };
vlc_module_begin ()
set_shortname( "KAI" )
set_description( N_("K Audio Interface audio output") )
set_capability( "audio output", 100 )
set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_AOUT )
add_string( "kai-audio-device", ppsz_kai_audio_device[0],
KAI_AUDIO_DEVICE_TEXT, KAI_AUDIO_DEVICE_LONGTEXT, false )
change_string_list( ppsz_kai_audio_device, ppsz_kai_audio_device_text,
0 )
add_bool( "kai-audio-exclusive-mode", false,
KAI_AUDIO_EXCLUSIVE_MODE_TEXT, KAI_AUDIO_EXCLUSIVE_MODE_LONGTEXT,
true )
set_callbacks( Open, Close )
vlc_module_end ()
/*****************************************************************************
* Open: open the audio device
*****************************************************************************/
static int Open ( vlc_object_t *p_this )
{
audio_output_t *p_aout = (audio_output_t *)p_this;
aout_sys_t *p_sys;
char *psz_mode;
ULONG i_kai_mode;
KAISPEC ks_wanted, ks_obtained;
int i_nb_channels;
int i_bytes_per_frame;
vlc_value_t val, text;
audio_format_t format = p_aout->format;
/* Allocate structure */
p_aout->sys = calloc( 1, sizeof( aout_sys_t ) );
if( p_aout->sys == NULL )
return VLC_ENOMEM;
p_sys = p_aout->sys;
if( var_Get( p_aout, "audio-device", &val ) != VLC_ENOVAR )
{
/* The user has selected an audio device. */
if ( val.i_int == AOUT_VAR_STEREO )
{
format.i_physical_channels
= AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
}
else if ( val.i_int == AOUT_VAR_MONO )
{
format.i_physical_channels = AOUT_CHAN_CENTER;
}
}
psz_mode = var_InheritString( p_aout, "kai-audio-device" );
if( !psz_mode )
psz_mode = ( char * )ppsz_kai_audio_device[ 0 ]; // "auto"
i_kai_mode = KAIM_AUTO;
if( strcmp( psz_mode, "dart" ) == 0 )
i_kai_mode = KAIM_DART;
else if( strcmp( psz_mode, "uniaud" ) == 0 )
i_kai_mode = KAIM_UNIAUD;
msg_Dbg( p_aout, "selected mode = %s", psz_mode );
if( psz_mode != ppsz_kai_audio_device[ 0 ])
free( psz_mode );
i_nb_channels = aout_FormatNbChannels( &format );
if ( i_nb_channels > 2 )
{
/* KAI doesn't support more than two channels. */
i_nb_channels = 2;
format.i_physical_channels
= AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
}
/* Support s16l only */
format.i_format = VLC_CODEC_S16L;
aout_FormatPrepare( &format );
i_bytes_per_frame = format.i_bytes_per_frame;
/* Initialize library */
if( kaiInit( i_kai_mode ))
{
msg_Err( p_aout, "cannot initialize KAI");
goto exit_free_sys;
}
ks_wanted.usDeviceIndex = 0;
ks_wanted.ulType = KAIT_PLAY;
ks_wanted.ulBitsPerSample = BPS_16;
ks_wanted.ulSamplingRate = format.i_rate;
ks_wanted.ulDataFormat = MCI_WAVE_FORMAT_PCM;
ks_wanted.ulChannels = i_nb_channels;
ks_wanted.ulNumBuffers = 2;
ks_wanted.ulBufferSize = FRAME_SIZE * i_bytes_per_frame;
ks_wanted.fShareable = !var_InheritBool( p_aout,
"kai-audio-exclusive-mode");
ks_wanted.pfnCallBack = KaiCallback;
ks_wanted.pCallBackData = p_aout;
msg_Dbg( p_aout, "requested ulBufferSize = %ld", ks_wanted.ulBufferSize );
/* Open the sound device. */
if( kaiOpen( &ks_wanted, &ks_obtained, &p_sys->hkai ))
{
msg_Err( p_aout, "cannot open KAI device");
goto exit_kai_done;
}
msg_Dbg( p_aout, "open in %s mode",
ks_obtained.fShareable ? "shareable" : "exclusive" );
msg_Dbg( p_aout, "obtained i_nb_samples = %lu",
ks_obtained.ulBufferSize / i_bytes_per_frame );
msg_Dbg( p_aout, "obtained i_bytes_per_frame = %d",
format.i_bytes_per_frame );
p_aout->format = format;
p_aout->pf_play = Play;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
aout_PacketInit( p_aout, &p_sys->packet,
ks_obtained.ulBufferSize / i_bytes_per_frame );
aout_VolumeSoftInit( p_aout );
if ( var_Type( p_aout, "audio-device" ) == 0 )
{
/* First launch. */
var_Create( p_aout, "audio-device",
VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
text.psz_string = _("Audio Device");
var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
val.i_int = AOUT_VAR_STEREO;
text.psz_string = _("Stereo");
var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = AOUT_VAR_MONO;
text.psz_string = _("Mono");
var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
if ( i_nb_channels == 2 )
{
val.i_int = AOUT_VAR_STEREO;
}
else
{
val.i_int = AOUT_VAR_MONO;
}
var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
}
var_TriggerCallback( p_aout, "intf-change" );
/* Prevent SIG_FPE */
_control87(MCW_EM, MCW_EM);
return VLC_SUCCESS;
exit_kai_done :
kaiDone();
exit_free_sys :
free( p_sys );
return VLC_EGENERIC;
}
/*****************************************************************************
* Play: play a sound samples buffer
*****************************************************************************/
static void Play (audio_output_t *p_aout, block_t *block)
{
aout_sys_t *p_sys = p_aout->sys;
kaiPlay( p_sys->hkai );
aout_PacketPlay( p_aout, block );
}
/*****************************************************************************
* Close: close the audio device
*****************************************************************************/
static void Close ( vlc_object_t *p_this )
{
audio_output_t *p_aout = (audio_output_t *)p_this;
aout_sys_t *p_sys = p_aout->sys;
kaiClose( p_sys->hkai );
kaiDone();
aout_PacketDestroy( p_aout );
free( p_sys );
}
/*****************************************************************************
* KaiCallback: what to do once KAI has played sound samples
*****************************************************************************/
static ULONG APIENTRY KaiCallback( PVOID p_cb_data,
PVOID p_buffer,
ULONG i_buf_size )
{
audio_output_t *p_aout = (audio_output_t *)p_cb_data;
aout_buffer_t *p_aout_buffer;
mtime_t current_date, next_date;
ULONG i_len;
/* We have 2 buffers, and a callback function is called right after KAI
* runs out of a buffer. So we should get a packet to be played after the
* remaining buffer.
*/
next_date = mdate() + ( i_buf_size * 1000000LL
/ p_aout->format.i_bytes_per_frame
/ p_aout->format.i_rate
* p_aout->format.i_frame_length );
for (i_len = 0; i_len < i_buf_size;)
{
current_date = mdate();
if( next_date < current_date )
next_date = current_date;
/* Get the next audio data buffer */
p_aout_buffer = aout_PacketNext( p_aout, next_date );
if( p_aout_buffer == NULL )
{
/* Means we are too early to request a new buffer ?
* Try once again.
*/
msleep( AOUT_MIN_PREPARE_TIME );
next_date = mdate();
p_aout_buffer = aout_PacketNext( p_aout, next_date );
}
if ( p_aout_buffer != NULL )
{
vlc_memcpy( ( uint8_t * ) p_buffer + i_len,
p_aout_buffer->p_buffer,
p_aout_buffer->i_buffer );
i_len += p_aout_buffer->i_buffer;
next_date += p_aout_buffer->i_length;
aout_BufferFree( p_aout_buffer );
}
else
{
vlc_memset( ( uint8_t * ) p_buffer + i_len, 0, i_buf_size - i_len );
i_len = i_buf_size;
}
}
return i_buf_size;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment