[vlc-devel] [PATCH 25/41] Add KAI audio output module for OS/2

Rémi Denis-Courmont remi at remlab.net
Tue Oct 11 19:20:40 CEST 2011


Le lundi 10 octobre 2011 14:44:04 KO Myung-Hun, vous avez écrit :
> diff --git a/configure.ac b/configure.ac
> index f7322b2..d4b6245 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -3582,6 +3582,20 @@ dnl
>  PKG_ENABLE_MODULES_VLC([SAMPLERATE], [], [samplerate], [Resampler with
> libsamplerate], [auto])
> 
>  dnl
> +dnl  OS/2 KAI plugin
> +dnl
> +AC_ARG_ENABLE(kai,
> +  [  --enable-kai   OS/2 KAI audio module (default enabled on OS/2)])

Default value can be set as the forth parameter of AC_ARG_ENABLE.

Is "kai.h" is part of the standard eComStation SDK? Then you might as well 
just enable the plugin in modules/audio_output/Modules.am with 'if HAVE_OS2', 
like we do for OSS, ALSA and PulseAudio already.

> +if test "${enable_kai}" != "no" &&
> +  (test "${SYS}" = "os2" || test "${enable_kai}" = "yes")

Please use AS_IF() in new code.

> +then
> +  AC_CHECK_HEADERS(kai.h,
> +    [ VLC_ADD_PLUGIN([kai])
> +      VLC_ADD_LDFLAGS([kai],[-lkai])

In new code, I prefer to store flags in Modules.am.

> +    ], [ AC_MSG_ERROR([cannot find KAI headers]) ])
> +fi
> +
> +dnl
>  dnl  Interface plugins
>  dnl
> 
> diff --git a/modules/audio_output/Modules.am
> b/modules/audio_output/Modules.am index 1ac2da8..6097dfe 100644
> --- a/modules/audio_output/Modules.am
> +++ b/modules/audio_output/Modules.am
> @@ -6,6 +6,7 @@ SOURCES_auhal = auhal.c
>  SOURCES_jack = jack.c
>  SOURCES_audioqueue = audioqueue.c
>  SOURCES_opensles_android = opensles_android.c
> +SOURCES_kai = kai.c
> 
>  libadummy_plugin_la_SOURCES = adummy.c
>  libadummy_plugin_la_CFLAGS = $(AM_CFLAGS)
> diff --git a/modules/audio_output/kai.c b/modules/audio_output/kai.c
> new file mode 100644
> index 0000000..c755689
> --- /dev/null
> +++ b/modules/audio_output/kai.c
> @@ -0,0 +1,324 @@
> +/*************************************************************************
> **** + * 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;

aout_packet_t is mostly intended for legacy audio outputs that nobody cared to 
adapt to the new API. You can use it, but it's not recommended.

> +    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"), N_("DART"), N_("UNIAUD") };

I am afraid our translators will not understand what DART and UNIAUD are 
supposed to mean.

> +
> +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" )
> +    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;
> +        }
> +    }
> +
> +    psz_mode = var_CreateGetString( p_aout, "kai-audio-device" );
> +
> +    i_kai_mode = KAIM_AUTO;
> +    if( strcmp( psz_mode, "dart" ) == 0 )

Beware. psz_mode may be NULL.

> +        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 );
> +
> +    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;
> +    }
> +
> +    /* Support s16l only */
> +    p_aout->format.i_format = VLC_CODEC_S16L;
> +
> +    aout_FormatPrepare( &p_aout->format );
> +
> +    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;

Hmm? Does KAI really accept any arbitrary sample rate?

> +    ks_wanted.ulDataFormat    = MCI_WAVE_FORMAT_PCM;
> +    ks_wanted.ulChannels      = i_nb_channels;

Same questions for channel numbers.

> +    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 );
> +}

It's really weird that you call both KAI and aout_Packet here. But I probably 
don't understand.

> +
> +/*************************************************************************
> **** + * 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();
> +
> +        /* Get the next audio data buffer */
> +        p_aout_buffer = aout_PacketNext( p_aout, next_date );
> +
> +        if(!p_aout_buffer)
> +        {
> +            // means we are too early to request a new buffer?
> +            mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
> +            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;
> +}

-- 
Rémi Denis-Courmont
http://www.remlab.net/
http://fi.linkedin.com/in/remidenis



More information about the vlc-devel mailing list