[vlc-devel] [PATCH 14/18] Add KAI audio output module for OS/2
KO Myung-Hun
komh78 at gmail.com
Fri Oct 21 16:22:22 CEST 2011
Rémi Denis-Courmont wrote:
> On Thu, 20 Oct 2011 21:30:21 +0900, KO Myung-Hun <komh at chollian.net>
> wrote:
>> ---
>> configure.ac | 23 +++
>> modules/audio_output/Modules.am | 8 +
>> modules/audio_output/kai.c | 327
>> +++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 358 insertions(+), 0 deletions(-)
>> create mode 100644 modules/audio_output/kai.c
>>
>> diff --git a/configure.ac b/configure.ac
>> index 4687149..4fcca19 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -3591,6 +3591,29 @@ 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
>>
>> diff --git a/modules/audio_output/Modules.am
>> b/modules/audio_output/Modules.am
>> index 0cbbbb7..c7d7cca 100644
>> --- a/modules/audio_output/Modules.am
>> +++ b/modules/audio_output/Modules.am
>> @@ -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
>> diff --git a/modules/audio_output/kai.c b/modules/audio_output/kai.c
>> new file mode 100644
>> index 0000000..d691410
>> --- /dev/null
>> +++ b/modules/audio_output/kai.c
>> @@ -0,0 +1,327 @@
>>
> +/*****************************************************************************
>> + * kai.c : KAI audio output plugin for vlc
>> +
>>
> *****************************************************************************
>> + * Copyright (C) 2010 the VideoLAN team
>> + *
>> + * Authors: KO Myung-Hun <komh at 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:" )
>
> Should not have trailing semicolon.
>
Colon ? If so, fixed.
>> +#define KAI_AUDIO_DEVICE_LONGTEXT N_( \
>> + "Select a proper audio device to be used by KAI" )
>
> Sentence should end with a dot.
>
Ok.
>> +
>> +#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" )
>
> Same here.
>
Fixed.
>> +
>> +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 )
>> + add_shortcut( "kai" )
>
> This should be superfluous since the module is called kai already.
>
Fixed.
>> + 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;
>> +
>> + /* 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 )
>> + {
>> + p_aout->format.i_physical_channels
>> + = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
>> + }
>> + else if ( val.i_int == AOUT_VAR_MONO )
>> + {
>> + p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
>> + }
>> + }
>
> This will corrupt p_aout->format.i_physical_channels for the next plug-in
> if kaiOpen() fails afterward.
>
Fixed.
>> +
>> + psz_mode = var_CreateGetString( p_aout, "kai-audio-device" );
>
> var_InheritString() should be enough here.
>
Ok.
>> + if( !psz_mode )
>> + psz_mode = 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( &p_aout->format );
>> + if ( i_nb_channels > 2 )
>> + {
>> + /* KAI doesn't support more than two channels. */
>> + i_nb_channels = 2;
>> + p_aout->format.i_physical_channels
>> + = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
>> + }
>
> Same problem as earlier.
>
Fixed.
>> +
>> + /* Support s16l only */
>> + p_aout->format.i_format = VLC_CODEC_S16L;
>
> And again.
>
Fixed.
>> +
>> + aout_FormatPrepare( &p_aout->format );
>
> And lastly.
>
Fixed.
>> +
>> + i_bytes_per_frame = p_aout->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 = p_aout->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_CreateGetBool( 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",
>> + p_aout->format.i_bytes_per_frame );
>> +
>> + 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 next_date;
>> + ULONG i_len = 0;
>> +
>> + next_date = mdate();
>> + while ( i_len < i_buf_size )
>> + {
>> + if( next_date < mdate())
>> + next_date = mdate();
>
> mdate() should be cached.
>
Ok.
>> +
>> + /* Get the next audio data buffer */
>> + p_aout_buffer = aout_PacketNext( p_aout, next_date );
>
> next_date should include the (estimated) latency of the audio hardware
> output and buffer. Otherwise lip sync will not work.
>
What is 'lip sync' ?
>> +
>> + if(!p_aout_buffer)
>> + {
>> + // means we are too early to request a new buffer?
>> + mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
>
> This should probably 'continue'.
Just 'continue' ? I think, it will cause CPU load to 99.9% unless we
give up time slice.
> It should even break out of the loop if
> i_len is non-zero, assuming KAI tolerates short reads.
>
Do you mean that i_len shorter than i_buf_size should be return ?
KAI recognizes a shorter return value than i_buf_size as a end signature
of a stream.
>> + 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 don't understand how you ensure that
> i_len + p_aout_buffer->i_buffer <= i_buf_size
>
I think the following codes ensures this.
aout_PacketInit( p_aout, &p_sys->packet,
ks_obtained.ulBufferSize / i_bytes_per_frame );
>> +
>> + 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;
>
> Hmm, this is VLC audio output cargo cult programming. In practice, most
> outputs do not need zeroes.
>
Even if we could not get any packets from VLC, there is no need to fill
the audio buffers for audio output such as KAI with zeros ?
--
KO Myung-Hun
Using Mozilla SeaMonkey 2.0.14
Under OS/2 Warp 4 for Korean with FixPak #15
On AMD ThunderBird 1GHz with 512 MB RAM
Korean OS/2 User Community : http://www.ecomstation.co.kr
More information about the vlc-devel
mailing list