directx.c 45.3 KB
Newer Older
1
/*****************************************************************************
2
 * directx.c: Windows DirectX audio output method
3
 *****************************************************************************
4
 * Copyright (C) 2001-2009 the VideoLAN team
5
 * $Id$
6
 *
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20 21
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
Clément Stenac's avatar
Clément Stenac committed
34
#include <vlc_aout.h>
35
#include <vlc_charset.h>
36

37 38
#include "windows_audio_common.h"

39 40
#include <dsound.h>

41
#define FRAME_SIZE ((int)p_aout->output.output.i_rate/20) /* Size in samples */
Gildas Bazin's avatar
 
Gildas Bazin committed
42

43 44 45 46 47 48 49
/*****************************************************************************
 * notification_thread_t: DirectX event thread
 *****************************************************************************/
typedef struct notification_thread_t
{
    VLC_COMMON_MEMBERS

50 51 52
    aout_instance_t *p_aout;
    int i_frame_size;                          /* size in bytes of one frame */
    int i_write_slot;       /* current write position in our circular buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
53 54

    mtime_t start_date;
55
    HANDLE event;
56 57 58 59 60 61 62 63 64 65 66

} notification_thread_t;

/*****************************************************************************
 * aout_sys_t: directx audio output method descriptor
 *****************************************************************************
 * This structure is part of the audio output thread descriptor.
 * It describes the direct sound specific properties of an audio device.
 *****************************************************************************/
struct aout_sys_t
{
Gildas Bazin's avatar
 
Gildas Bazin committed
67
    HINSTANCE           hdsound_dll;      /* handle of the opened dsound dll */
68

69
    char *              psz_device;              /* user defined device name */
70 71
    LPGUID              p_device_guid;

72 73 74 75 76
    LPDIRECTSOUND       p_dsobject;              /* main Direct Sound object */
    LPDIRECTSOUNDBUFFER p_dsbuffer;   /* the sound buffer we use (direct sound
                                       * takes care of mixing all the
                                       * secondary buffers into the primary) */

Gildas Bazin's avatar
 
Gildas Bazin committed
77
    notification_thread_t *p_notif;                  /* DirectSoundThread id */
78

79
    int      b_playing;                                    /* playing status */
80

81
    int      i_frame_size;                     /* Size in bytes of one frame */
Gildas Bazin's avatar
 
Gildas Bazin committed
82

83
    int      i_speaker_setup;                      /* Speaker setup override */
84

85 86
    bool     b_chan_reorder;                /* do we need channel reordering */
    int      pi_chan_table[AOUT_CHAN_MAX];
Gildas Bazin's avatar
 
Gildas Bazin committed
87
    uint32_t i_channel_mask;
88 89
    uint32_t i_bits_per_sample;
    uint32_t i_channels;
90 91 92 93 94
};

/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
95 96 97
static int  OpenAudio  ( vlc_object_t * );
static void CloseAudio ( vlc_object_t * );
static void Play       ( aout_instance_t * );
98 99

/* local functions */
Gildas Bazin's avatar
 
Gildas Bazin committed
100 101
static void Probe             ( aout_instance_t * );
static int  InitDirectSound   ( aout_instance_t * );
102
static int  CreateDSBuffer    ( aout_instance_t *, int, int, int, int, int, bool );
103
static int  CreateDSBufferPCM ( aout_instance_t *, vlc_fourcc_t*, int, int, int, bool );
Gildas Bazin's avatar
 
Gildas Bazin committed
104
static void DestroyDSBuffer   ( aout_instance_t * );
105
static void* DirectSoundThread( vlc_object_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
106 107
static int  FillBuffer        ( aout_instance_t *, int, aout_buffer_t * );

108 109 110
static int ReloadDirectXDevices( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );

111 112 113
/* Speaker setup override options list */
static const char *const speaker_list[] = { "Windows default", "Mono", "Stereo",
                                            "Quad", "5.1", "7.1" };
114 115
static const char *const ppsz_adev[] = {"default",  };
static const char *const ppsz_adev_text[] = {"default", };
116

Gildas Bazin's avatar
 
Gildas Bazin committed
117 118 119
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
120
#define DEVICE_TEXT N_("Output device")
121
#define DEVICE_LONGTEXT N_("Select your audio output device")
122

123
#define SPEAKER_TEXT N_("Speaker configuration")
124 125
#define SPEAKER_LONGTEXT N_("Select speaker configuration you want to use. " \
    "This option doesn't upmix! So NO e.g. Stereo -> 5.1 conversion." )
126

127 128 129 130 131 132
vlc_module_begin ()
    set_description( N_("DirectX audio output") )
    set_shortname( "DirectX" )
    set_capability( "audio output", 100 )
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_AOUT )
133
    add_shortcut( "directx", "directsound" )
134

135
    add_string( "directx-audio-device-name", "default",
136
             DEVICE_TEXT, DEVICE_LONGTEXT, false )
137 138 139 140
        add_deprecated_alias( "directx-audio-device" ) /* Since 1.1.0 */
        change_string_list( ppsz_adev, ppsz_adev_text, ReloadDirectXDevices )
        change_action_add( ReloadDirectXDevices, N_("Refresh list") )
        change_need_restart ()
Rémi Duraffort's avatar
Rémi Duraffort committed
141
    add_bool( "directx-audio-float32", false, NULL, FLOAT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
142
              FLOAT_LONGTEXT, true )
143
    add_string( "directx-audio-speaker", "Windows default",
144 145 146
                 SPEAKER_TEXT, SPEAKER_LONGTEXT, true )
        change_string_list( speaker_list, 0, 0 )
        change_need_restart ()
147

148 149
    set_callbacks( OpenAudio, CloseAudio )
vlc_module_end ()
Gildas Bazin's avatar
 
Gildas Bazin committed
150

151 152 153 154 155
/*****************************************************************************
 * OpenAudio: open the audio device
 *****************************************************************************
 * This function opens and setups Direct Sound.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
156
static int OpenAudio( vlc_object_t *p_this )
157
{
Gildas Bazin's avatar
 
Gildas Bazin committed
158
    aout_instance_t * p_aout = (aout_instance_t *)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
159
    vlc_value_t val;
160 161 162 163
    char * psz_speaker;
    int i = 0;

    const char * const * ppsz_compare = speaker_list;
164

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
165
    msg_Dbg( p_aout, "Opening DirectSound Audio Output" );
166 167

   /* Allocate structure */
Gildas Bazin's avatar
 
Gildas Bazin committed
168 169
    p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
    if( p_aout->output.p_sys == NULL )
170
        return VLC_ENOMEM;
171 172

    /* Initialize some variables */
Gildas Bazin's avatar
 
Gildas Bazin committed
173 174 175
    p_aout->output.p_sys->p_dsobject = NULL;
    p_aout->output.p_sys->p_dsbuffer = NULL;
    p_aout->output.p_sys->p_notif = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
176
    p_aout->output.p_sys->b_playing = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
177 178

    p_aout->output.pf_play = Play;
179
    aout_VolumeSoftInit( p_aout );
180

181 182 183
    /* Retrieve config values */
    var_Create( p_aout, "directx-audio-float32",
                VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
184
    psz_speaker = var_CreateGetString( p_aout, "directx-audio-speaker" );
185 186 187 188 189 190 191 192 193 194 195 196

    while ( *ppsz_compare != NULL )
    {
        if ( !strncmp( *ppsz_compare, psz_speaker, strlen(*ppsz_compare) ) )
        {
            break;
        }
        ppsz_compare++; i++;
    }

    if ( *ppsz_compare == NULL )
    {
197
        msg_Err( p_aout, "(%s) isn't valid speaker setup option", psz_speaker );
198 199 200
        msg_Err( p_aout, "Defaulting to Windows default speaker config");
        i = 0;
    }
201
    free( psz_speaker );
202 203
    p_aout->output.p_sys->i_speaker_setup = i;

204 205
    p_aout->output.p_sys->p_device_guid = 0;

206
    /* Initialise DirectSound */
Gildas Bazin's avatar
 
Gildas Bazin committed
207
    if( InitDirectSound( p_aout ) )
208
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
209 210
        msg_Err( p_aout, "cannot initialize DirectSound" );
        goto error;
211 212
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
213 214 215 216 217 218 219 220
    if( var_Type( p_aout, "audio-device" ) == 0 )
    {
        Probe( p_aout );
    }

    if( var_Get( p_aout, "audio-device", &val ) < 0 )
    {
        /* Probe() has failed. */
Gildas Bazin's avatar
 
Gildas Bazin committed
221
        goto error;
Gildas Bazin's avatar
 
Gildas Bazin committed
222 223 224
    }

    /* Open the device */
Gildas Bazin's avatar
 
Gildas Bazin committed
225
    if( val.i_int == AOUT_VAR_SPDIF )
226
    {
227
        p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
Gildas Bazin's avatar
 
Gildas Bazin committed
228 229 230 231 232 233 234 235

        /* Calculate the frame size in bytes */
        p_aout->output.i_nb_samples = A52_FRAME_NB;
        p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
        p_aout->output.output.i_frame_length = A52_FRAME_NB;
        p_aout->output.p_sys->i_frame_size =
            p_aout->output.output.i_bytes_per_frame;

236
        if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
Gildas Bazin's avatar
 
Gildas Bazin committed
237 238 239
                            p_aout->output.output.i_physical_channels,
                            aout_FormatNbChannels( &p_aout->output.output ),
                            p_aout->output.output.i_rate,
240
                            p_aout->output.p_sys->i_frame_size, false )
Gildas Bazin's avatar
 
Gildas Bazin committed
241 242
            != VLC_SUCCESS )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
243
            msg_Err( p_aout, "cannot open directx audio device" );
Gildas Bazin's avatar
 
Gildas Bazin committed
244 245 246 247 248 249 250 251
            free( p_aout->output.p_sys );
            return VLC_EGENERIC;
        }

        aout_VolumeNoneInit( p_aout );
    }
    else
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
252
        if( val.i_int == AOUT_VAR_5_1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
253 254 255 256 257 258
        {
            p_aout->output.output.i_physical_channels
                = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                   | AOUT_CHAN_LFE;
        }
259 260 261 262 263 264 265 266
        else if( val.i_int == AOUT_VAR_7_1 )
        {
                    p_aout->output.output.i_physical_channels
                        = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
                           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                           | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT
                           | AOUT_CHAN_LFE;
        }
267 268 269 270 271 272
        else if( val.i_int == AOUT_VAR_3F2R )
        {
            p_aout->output.output.i_physical_channels
                = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
273
        else if( val.i_int == AOUT_VAR_2F2R )
Gildas Bazin's avatar
 
Gildas Bazin committed
274 275 276 277 278
        {
            p_aout->output.output.i_physical_channels
                = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
                   | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
279
        else if( val.i_int == AOUT_VAR_MONO )
Gildas Bazin's avatar
 
Gildas Bazin committed
280 281 282 283 284 285 286 287
        {
            p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
        }
        else
        {
            p_aout->output.output.i_physical_channels
                = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
        }
288

Gildas Bazin's avatar
 
Gildas Bazin committed
289 290 291
        if( CreateDSBufferPCM( p_aout, &p_aout->output.output.i_format,
                               p_aout->output.output.i_physical_channels,
                               aout_FormatNbChannels( &p_aout->output.output ),
292
                               p_aout->output.output.i_rate, false )
Gildas Bazin's avatar
 
Gildas Bazin committed
293
            != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
294
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
295
            msg_Err( p_aout, "cannot open directx audio device" );
Gildas Bazin's avatar
 
Gildas Bazin committed
296 297
            free( p_aout->output.p_sys );
            return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
298
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
299 300 301 302 303

        /* Calculate the frame size in bytes */
        p_aout->output.i_nb_samples = FRAME_SIZE;
        aout_FormatPrepare( &p_aout->output.output );
        aout_VolumeSoftInit( p_aout );
Gildas Bazin's avatar
 
Gildas Bazin committed
304
    }
305

306 307 308 309 310 311 312 313 314
    /* Now we need to setup our DirectSound play notification structure */
    p_aout->output.p_sys->p_notif =
        vlc_object_create( p_aout, sizeof(notification_thread_t) );
    p_aout->output.p_sys->p_notif->p_aout = p_aout;

    p_aout->output.p_sys->p_notif->event = CreateEvent( 0, FALSE, FALSE, 0 );
    p_aout->output.p_sys->p_notif->i_frame_size =
        p_aout->output.p_sys->i_frame_size;

Christophe Massiot's avatar
Christophe Massiot committed
315 316 317 318
    /* then launch the notification thread */
    msg_Dbg( p_aout, "creating DirectSoundThread" );
    if( vlc_thread_create( p_aout->output.p_sys->p_notif,
                           "DirectSound Notification Thread",
Gildas Bazin's avatar
 
Gildas Bazin committed
319
                           DirectSoundThread,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
320
                           VLC_THREAD_PRIORITY_HIGHEST ) )
Christophe Massiot's avatar
Christophe Massiot committed
321 322
    {
        msg_Err( p_aout, "cannot create DirectSoundThread" );
323
        CloseHandle( p_aout->output.p_sys->p_notif->event );
324
        vlc_object_release( p_aout->output.p_sys->p_notif );
325
        p_aout->output.p_sys->p_notif = NULL;
Christophe Massiot's avatar
Christophe Massiot committed
326 327 328 329 330
        goto error;
    }

    vlc_object_attach( p_aout->output.p_sys->p_notif, p_aout );

Gildas Bazin's avatar
 
Gildas Bazin committed
331
    return VLC_SUCCESS;
Christophe Massiot's avatar
Christophe Massiot committed
332 333

 error:
Gildas Bazin's avatar
 
Gildas Bazin committed
334
    CloseAudio( VLC_OBJECT(p_aout) );
335
    return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
336 337
}

Gildas Bazin's avatar
 
Gildas Bazin committed
338 339 340 341 342
/*****************************************************************************
 * Probe: probe the audio device for available formats and channels
 *****************************************************************************/
static void Probe( aout_instance_t * p_aout )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
343
    vlc_value_t val, text;
344
    vlc_fourcc_t i_format;
Gildas Bazin's avatar
 
Gildas Bazin committed
345 346
    unsigned int i_physical_channels;
    DWORD ui_speaker_config;
347
    bool is_default_output_set = false;
Gildas Bazin's avatar
 
Gildas Bazin committed
348

Gildas Bazin's avatar
 
Gildas Bazin committed
349
    var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
350
    text.psz_string = _("Audio Device");
Gildas Bazin's avatar
 
Gildas Bazin committed
351
    var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
Gildas Bazin's avatar
 
Gildas Bazin committed
352 353 354 355 356 357 358 359

    /* Test for 5.1 support */
    i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                          AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
                          AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
    if( p_aout->output.output.i_physical_channels == i_physical_channels )
    {
        if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 6,
360
                               p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
361 362
            == VLC_SUCCESS )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
363
            val.i_int = AOUT_VAR_5_1;
364
            text.psz_string = (char*) "5.1";
Gildas Bazin's avatar
 
Gildas Bazin committed
365 366
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
367 368
            var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
            is_default_output_set = true;
Gildas Bazin's avatar
 
Gildas Bazin committed
369 370 371 372
            msg_Dbg( p_aout, "device supports 5.1 channels" );
        }
    }

373 374 375 376 377
    /* Test for 7.1 support */
    i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                             AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
                             AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
                             AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
Rémi Duraffort's avatar
Rémi Duraffort committed
378 379 380
    if( p_aout->output.output.i_physical_channels == i_physical_channels )
    {
        if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 8,
381
                                  p_aout->output.output.i_rate, true )
Rémi Duraffort's avatar
Rémi Duraffort committed
382 383 384 385 386 387 388 389 390 391 392
            == VLC_SUCCESS )
        {
            val.i_int = AOUT_VAR_7_1;
            text.psz_string = (char*) "7.1";
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
            var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
            is_default_output_set = true;
            msg_Dbg( p_aout, "device supports 7.1 channels" );
        }
    }
393

394 395 396 397 398 399 400
    /* Test for 3 Front 2 Rear support */
    i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                          AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
                          AOUT_CHAN_REARRIGHT;
    if( p_aout->output.output.i_physical_channels == i_physical_channels )
    {
        if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 5,
401
                               p_aout->output.output.i_rate, true )
402 403 404
            == VLC_SUCCESS )
        {
            val.i_int = AOUT_VAR_3F2R;
405
            text.psz_string = _("3 Front 2 Rear");
406 407
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
408 409 410 411 412
            if(!is_default_output_set)
            {
                var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
                is_default_output_set = true;
            }
413 414 415 416
            msg_Dbg( p_aout, "device supports 5 channels" );
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
417 418 419 420 421 422 423
    /* Test for 2 Front 2 Rear support */
    i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                          AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
    if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
        == i_physical_channels )
    {
        if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 4,
424
                               p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
425 426
            == VLC_SUCCESS )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
427
            val.i_int = AOUT_VAR_2F2R;
428
            text.psz_string = _("2 Front 2 Rear");
Gildas Bazin's avatar
 
Gildas Bazin committed
429 430
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
431 432 433 434 435
            if(!is_default_output_set)
            {
                var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
                is_default_output_set = true;
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
436 437 438 439 440 441 442
            msg_Dbg( p_aout, "device supports 4 channels" );
        }
    }

    /* Test for stereo support */
    i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
    if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 2,
443
                           p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
444 445
        == VLC_SUCCESS )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
446
        val.i_int = AOUT_VAR_STEREO;
447
        text.psz_string = _("Stereo");
Gildas Bazin's avatar
 
Gildas Bazin committed
448
        var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
449 450 451 452 453 454
        if(!is_default_output_set)
        {
            var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
            is_default_output_set = true;
            msg_Dbg( p_aout, "device supports 2 channels (DEFAULT!)" );
        }
455
        else msg_Dbg( p_aout, "device supports 2 channels" );
Gildas Bazin's avatar
 
Gildas Bazin committed
456 457 458 459 460
    }

    /* Test for mono support */
    i_physical_channels = AOUT_CHAN_CENTER;
    if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 1,
461
                           p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
462 463
        == VLC_SUCCESS )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
464
        val.i_int = AOUT_VAR_MONO;
465
        text.psz_string = _("Mono");
Gildas Bazin's avatar
 
Gildas Bazin committed
466
        var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
Gildas Bazin's avatar
 
Gildas Bazin committed
467 468 469 470 471 472 473 474 475
        msg_Dbg( p_aout, "device supports 1 channel" );
    }

    /* Check the speaker configuration to determine which channel config should
     * be the default */
    if FAILED( IDirectSound_GetSpeakerConfig( p_aout->output.p_sys->p_dsobject,
                                              &ui_speaker_config ) )
    {
        ui_speaker_config = DSSPEAKER_STEREO;
476
        msg_Dbg( p_aout, "GetSpeakerConfig failed" );
Gildas Bazin's avatar
 
Gildas Bazin committed
477 478 479
    }
    switch( DSSPEAKER_CONFIG(ui_speaker_config) )
    {
480
    case DSSPEAKER_7POINT1:
481
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is 7.1" );
482 483
        val.i_int = AOUT_VAR_7_1;
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
484
    case DSSPEAKER_5POINT1:
485
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is 5.1" );
Gildas Bazin's avatar
 
Gildas Bazin committed
486
        val.i_int = AOUT_VAR_5_1;
Gildas Bazin's avatar
 
Gildas Bazin committed
487 488
        break;
    case DSSPEAKER_QUAD:
489
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is Quad" );
Gildas Bazin's avatar
 
Gildas Bazin committed
490
        val.i_int = AOUT_VAR_2F2R;
Gildas Bazin's avatar
 
Gildas Bazin committed
491
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
492 493
#if 0 /* Lots of people just get their settings wrong and complain that
       * this is a problem with VLC so just don't ever set mono by default. */
Gildas Bazin's avatar
 
Gildas Bazin committed
494
    case DSSPEAKER_MONO:
Gildas Bazin's avatar
 
Gildas Bazin committed
495
        val.i_int = AOUT_VAR_MONO;
Gildas Bazin's avatar
 
Gildas Bazin committed
496
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
497
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
498
    case DSSPEAKER_SURROUND:
499
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is surround" );
Gildas Bazin's avatar
 
Gildas Bazin committed
500
    case DSSPEAKER_STEREO:
501
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is stereo" );
Gildas Bazin's avatar
 
Gildas Bazin committed
502
    default:
503
        /* If nothing else is found, choose stereo output */
Gildas Bazin's avatar
 
Gildas Bazin committed
504
        val.i_int = AOUT_VAR_STEREO;
Gildas Bazin's avatar
 
Gildas Bazin committed
505 506
        break;
    }
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

    /* Check if we want to override speaker config */
    switch( p_aout->output.p_sys->i_speaker_setup )
    {
    case 0: /* Default value aka Windows default speaker setup */
        break;
    case 1: /* Mono */
        msg_Dbg( p_aout, "SpeakerConfig is forced to Mono" );
        val.i_int = AOUT_VAR_MONO;
        break;
    case 2: /* Stereo */
        msg_Dbg( p_aout, "SpeakerConfig is forced to Stereo" );
        val.i_int = AOUT_VAR_STEREO;
        break;
    case 3: /* Quad */
        msg_Dbg( p_aout, "SpeakerConfig is forced to Quad" );
        val.i_int = AOUT_VAR_2F2R;
        break;
    case 4: /* 5.1 */
        msg_Dbg( p_aout, "SpeakerConfig is forced to 5.1" );
        val.i_int = AOUT_VAR_5_1;
        break;
    case 5: /* 7.1 */
        msg_Dbg( p_aout, "SpeakerConfig is forced to 7.1" );
        val.i_int = AOUT_VAR_7_1;
        break;
    default:
        msg_Dbg( p_aout, "SpeakerConfig is forced to non-existing value" );
        break;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
538 539
    var_Set( p_aout, "audio-device", val );

Gildas Bazin's avatar
 
Gildas Bazin committed
540 541 542
    /* Test for SPDIF support */
    if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
    {
543
        if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
Gildas Bazin's avatar
 
Gildas Bazin committed
544 545 546
                            p_aout->output.output.i_physical_channels,
                            aout_FormatNbChannels( &p_aout->output.output ),
                            p_aout->output.output.i_rate,
547
                            AOUT_SPDIF_SIZE, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
548 549 550
            == VLC_SUCCESS )
        {
            msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
Gildas Bazin's avatar
 
Gildas Bazin committed
551
            val.i_int = AOUT_VAR_SPDIF;
552
            text.psz_string = _("A/52 over S/PDIF");
Gildas Bazin's avatar
 
Gildas Bazin committed
553 554
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
555
            if( var_InheritBool( p_aout, "spdif" ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
556 557 558 559
                var_Set( p_aout, "audio-device", val );
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
560 561 562 563 564 565 566 567
    var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
    if( val.i_int <= 0 )
    {
        /* Probe() has failed. */
        var_Destroy( p_aout, "audio-device" );
        return;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
568
    var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
569
    var_SetBool( p_aout, "intf-change", true );
Gildas Bazin's avatar
 
Gildas Bazin committed
570 571
}

Gildas Bazin's avatar
 
Gildas Bazin committed
572
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
573 574 575
 * Play: we'll start playing the directsound buffer here because at least here
 *       we know the first buffer has been put in the aout fifo and we also
 *       know its date.
Gildas Bazin's avatar
 
Gildas Bazin committed
576
 *****************************************************************************/
577
static void Play( aout_instance_t *p_aout )
Gildas Bazin's avatar
 
Gildas Bazin committed
578
{
Gildas Bazin's avatar
 
Gildas Bazin committed
579 580 581 582 583 584 585 586 587 588 589
    if( !p_aout->output.p_sys->b_playing )
    {
        aout_buffer_t *p_buffer;

        p_aout->output.p_sys->b_playing = 1;

        /* get the playing date of the first aout buffer */
        p_aout->output.p_sys->p_notif->start_date =
            aout_FifoFirstDate( p_aout, &p_aout->output.fifo );

        /* fill in the first samples */
590
        for( int i = 0; i < FRAMES_NUM; i++ )
591 592 593 594 595
        {
            p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
            if( !p_buffer ) break;
            FillBuffer( p_aout, i, p_buffer );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
596 597

        /* wake up the audio output thread */
598
        SetEvent( p_aout->output.p_sys->p_notif->event );
Gildas Bazin's avatar
 
Gildas Bazin committed
599
    }
600 601 602 603 604
}

/*****************************************************************************
 * CloseAudio: close the audio device
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
605
static void CloseAudio( vlc_object_t *p_this )
606
{
Gildas Bazin's avatar
 
Gildas Bazin committed
607
    aout_instance_t * p_aout = (aout_instance_t *)p_this;
608
    aout_sys_t *p_sys = p_aout->output.p_sys;
609

610
    msg_Dbg( p_aout, "closing audio device" );
611 612

    /* kill the position notification thread, if any */
613
    if( p_sys->p_notif )
614
    {
615 616 617
        vlc_object_kill( p_sys->p_notif );
        /* wake up the audio thread if needed */
        if( !p_sys->b_playing ) SetEvent( p_sys->p_notif->event );
Gildas Bazin's avatar
 
Gildas Bazin committed
618

619
        vlc_thread_join( p_sys->p_notif );
620
        vlc_object_release( p_sys->p_notif );
621 622 623
    }

    /* release the secondary buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
624
    DestroyDSBuffer( p_aout );
625 626

    /* finally release the DirectSound object */
627
    if( p_sys->p_dsobject ) IDirectSound_Release( p_sys->p_dsobject );
628

629
    /* free DSOUND.DLL */
630
    if( p_sys->hdsound_dll ) FreeLibrary( p_sys->hdsound_dll );
Gildas Bazin's avatar
 
Gildas Bazin committed
631

632
    free( p_aout->output.p_sys->p_device_guid );
633
    free( p_sys );
634 635
}

636 637 638
/*****************************************************************************
 * CallBackDirectSoundEnum: callback to enumerate available devices
 *****************************************************************************/
639 640
static int CALLBACK CallBackDirectSoundEnum( LPGUID p_guid, LPCWSTR psz_desc,
                                             LPCWSTR psz_mod, LPVOID _p_aout )
641
{
642 643
    VLC_UNUSED( psz_mod );

644 645
    aout_instance_t *p_aout = (aout_instance_t *)_p_aout;

646 647
    char *psz_device = FromWide( psz_desc );
    msg_Dbg( p_aout, "found device: %s", psz_device );
648

649 650
    if( p_aout->output.p_sys->psz_device &&
        !strcmp(p_aout->output.p_sys->psz_device, psz_device) && p_guid )
651
    {
652
        /* Use the device corresponding to psz_device */
653 654
        p_aout->output.p_sys->p_device_guid = malloc( sizeof( GUID ) );
        *p_aout->output.p_sys->p_device_guid = *p_guid;
655
        msg_Dbg( p_aout, "using device: %s", psz_device );
656
    }
657 658 659 660 661
    else
    {
        /* If no default device has been selected, chose the first one */
        if( !p_aout->output.p_sys->psz_device && p_guid )
        {
662
            p_aout->output.p_sys->psz_device = strdup( psz_device );
663 664
            p_aout->output.p_sys->p_device_guid = malloc( sizeof( GUID ) );
            *p_aout->output.p_sys->p_device_guid = *p_guid;
665
            msg_Dbg( p_aout, "using device: %s", psz_device );
666 667
        }
    }
668 669

    free( psz_device );
670
    return true;
671 672
}

673
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
674
 * InitDirectSound: handle all the gory details of DirectSound initialisation
675
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
676
static int InitDirectSound( aout_instance_t *p_aout )
677 678
{
    HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
679
    HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKW, LPVOID);
680

Gildas Bazin's avatar
 
Gildas Bazin committed
681 682
    p_aout->output.p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL");
    if( p_aout->output.p_sys->hdsound_dll == NULL )
683
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
684 685
        msg_Warn( p_aout, "cannot open DSOUND.DLL" );
        goto error;
686 687
    }

688 689 690
    OurDirectSoundCreate = (void *)
        GetProcAddress( p_aout->output.p_sys->hdsound_dll,
                        "DirectSoundCreate" );
691 692
    if( OurDirectSoundCreate == NULL )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
693 694
        msg_Warn( p_aout, "GetProcAddress FAILED" );
        goto error;
695 696
    }

697 698 699
    /* Get DirectSoundEnumerate */
    OurDirectSoundEnumerate = (void *)
       GetProcAddress( p_aout->output.p_sys->hdsound_dll,
700
                       "DirectSoundEnumerateW" );
701 702
    if( OurDirectSoundEnumerate )
    {
703
        p_aout->output.p_sys->psz_device = var_InheritString(p_aout, "directx-audio-device-name");
704
        /* Attempt enumeration */
705
        if( FAILED( OurDirectSoundEnumerate( CallBackDirectSoundEnum,
706 707 708 709 710 711
                                             p_aout ) ) )
        {
            msg_Dbg( p_aout, "enumeration of DirectSound devices failed" );
        }
    }

712
    /* Create the direct sound object */
713
    if FAILED( OurDirectSoundCreate( p_aout->output.p_sys->p_device_guid,
714
                                     &p_aout->output.p_sys->p_dsobject,
Gildas Bazin's avatar
 
Gildas Bazin committed
715
                                     NULL ) )
716 717
    {
        msg_Warn( p_aout, "cannot create a direct sound device" );
Gildas Bazin's avatar
 
Gildas Bazin committed
718
        goto error;
719 720 721 722 723 724 725 726 727 728 729 730
    }

    /* Set DirectSound Cooperative level, ie what control we want over Windows
     * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
     * settings of the primary buffer, but also that only the sound of our
     * application will be hearable when it will have the focus.
     * !!! (this is not really working as intended yet because to set the
     * cooperative level you need the window handle of your application, and
     * I don't know of any easy way to get it. Especially since we might play
     * sound without any video, and so what window handle should we use ???
     * The hack for now is to use the Desktop window handle - it seems to be
     * working */
Gildas Bazin's avatar
 
Gildas Bazin committed
731 732 733
    if( IDirectSound_SetCooperativeLevel( p_aout->output.p_sys->p_dsobject,
                                          GetDesktopWindow(),
                                          DSSCL_EXCLUSIVE) )
734 735 736 737
    {
        msg_Warn( p_aout, "cannot set direct sound cooperative level" );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
738
    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
739 740 741 742 743 744 745 746

 error:
    p_aout->output.p_sys->p_dsobject = NULL;
    if( p_aout->output.p_sys->hdsound_dll )
    {
        FreeLibrary( p_aout->output.p_sys->hdsound_dll );
        p_aout->output.p_sys->hdsound_dll = NULL;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
747
    return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
748

749 750 751
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
752
 * CreateDSBuffer: Creates a direct sound buffer of the required format.
753 754 755 756 757 758 759 760
 *****************************************************************************
 * This function creates the buffer we'll use to play audio.
 * In DirectSound there are two kinds of buffers:
 * - the primary buffer: which is the actual buffer that the soundcard plays
 * - the secondary buffer(s): these buffers are the one actually used by
 *    applications and DirectSound takes care of mixing them into the primary.
 *
 * Once you create a secondary buffer, you cannot change its format anymore so
Gildas Bazin's avatar
 
Gildas Bazin committed
761
 * you have to release the current one and create another.
762
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
763 764
static int CreateDSBuffer( aout_instance_t *p_aout, int i_format,
                           int i_channels, int i_nb_channels, int i_rate,
765
                           int i_bytes_per_frame, bool b_probe )
766
{
Gildas Bazin's avatar
 
Gildas Bazin committed
767
    WAVEFORMATEXTENSIBLE waveformat;
768
    DSBUFFERDESC         dsbdesc;
Gildas Bazin's avatar
 
Gildas Bazin committed
769
    unsigned int         i;
770

Gildas Bazin's avatar
 
Gildas Bazin committed
771 772
    /* First set the sound buffer format */
    waveformat.dwChannelMask = 0;
773
    for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
774
    {
775 776
        if( i_channels & pi_channels_src[i] )
            waveformat.dwChannelMask |= pi_channels_in[i];
777
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
778

Gildas Bazin's avatar
 
Gildas Bazin committed
779
    switch( i_format )
Gildas Bazin's avatar
 
Gildas Bazin committed
780
    {
781
    case VLC_CODEC_SPDIFL:
Gildas Bazin's avatar
 
Gildas Bazin committed
782
        i_nb_channels = 2;
Gildas Bazin's avatar
 
Gildas Bazin committed
783 784
        /* To prevent channel re-ordering */
        waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
Gildas Bazin's avatar
 
Gildas Bazin committed
785 786 787 788
        waveformat.Format.wBitsPerSample = 16;
        waveformat.Samples.wValidBitsPerSample =
            waveformat.Format.wBitsPerSample;
        waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
Gildas Bazin's avatar
 
Gildas Bazin committed
789
        waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
Gildas Bazin's avatar
 
Gildas Bazin committed
790
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
791

792
    case VLC_CODEC_FL32:
Gildas Bazin's avatar
 
Gildas Bazin committed
793 794 795 796
        waveformat.Format.wBitsPerSample = sizeof(float) * 8;
        waveformat.Samples.wValidBitsPerSample =
            waveformat.Format.wBitsPerSample;
        waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
Gildas Bazin's avatar
 
Gildas Bazin committed
797
        waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
Gildas Bazin's avatar
 
Gildas Bazin committed
798 799
        break;

800
    case VLC_CODEC_S16L:
Gildas Bazin's avatar
 
Gildas Bazin committed
801 802 803 804
        waveformat.Format.wBitsPerSample = 16;
        waveformat.Samples.wValidBitsPerSample =
            waveformat.Format.wBitsPerSample;
        waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
Gildas Bazin's avatar
 
Gildas Bazin committed
805
        waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
Gildas Bazin's avatar
 
Gildas Bazin committed
806 807
        break;
    }
808

Gildas Bazin's avatar
 
Gildas Bazin committed
809 810 811 812 813 814 815
    waveformat.Format.nChannels = i_nb_channels;
    waveformat.Format.nSamplesPerSec = i_rate;
    waveformat.Format.nBlockAlign =
        waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
    waveformat.Format.nAvgBytesPerSec =
        waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;

816 817 818
    p_aout->output.p_sys->i_bits_per_sample = waveformat.Format.wBitsPerSample;
    p_aout->output.p_sys->i_channels = i_nb_channels;

819 820 821 822 823 824
    /* Then fill in the direct sound descriptor */
    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
                    | DSBCAPS_GLOBALFOCUS;      /* Allows background playing */

Gildas Bazin's avatar
 
Gildas Bazin committed
825 826 827 828 829 830 831 832 833 834
    /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
    if( i_nb_channels <= 2 )
    {
        waveformat.Format.cbSize = 0;
    }
    else
    {
        waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
        waveformat.Format.cbSize =
            sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
Gildas Bazin's avatar
 
Gildas Bazin committed
835

836 837 838
        /* Needed for 5.1 on emu101k */
        dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
839 840 841 842 843 844 845 846

    dsbdesc.dwBufferBytes = FRAMES_NUM * i_bytes_per_frame;   /* buffer size */
    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;

    if FAILED( IDirectSound_CreateSoundBuffer(
                   p_aout->output.p_sys->p_dsobject, &dsbdesc,
                   &p_aout->output.p_sys->p_dsbuffer, NULL) )
    {
847 848 849 850 851
        if( dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE )
        {
            /* Try without DSBCAPS_LOCHARDWARE */
            dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
            if FAILED( IDirectSound_CreateSoundBuffer(
Gildas Bazin's avatar
 
Gildas Bazin committed
852 853
                   p_aout->output.p_sys->p_dsobject, &dsbdesc,
                   &p_aout->output.p_sys->p_dsbuffer, NULL) )
854 855 856 857 858 859 860
            {
                return VLC_EGENERIC;
            }
            if( !b_probe )
                msg_Dbg( p_aout, "couldn't use hardware sound buffer" );
        }
        else
Gildas Bazin's avatar
 
Gildas Bazin committed
861 862 863
        {
            return VLC_EGENERIC;
        }
864 865
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
866 867 868 869 870 871 872
    /* Stop here if we were just probing */
    if( b_probe )
    {
        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );
        p_aout->output.p_sys->p_dsbuffer = NULL;
        return VLC_SUCCESS;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
873

874
    p_aout->output.p_sys->i_frame_size = i_bytes_per_frame;
Gildas Bazin's avatar
 
Gildas Bazin committed
875
    p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask;
876 877 878 879 880 881 882 883 884
    p_aout->output.p_sys->b_chan_reorder =
        aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
                                  waveformat.dwChannelMask, i_nb_channels,
                                  p_aout->output.p_sys->pi_chan_table );

    if( p_aout->output.p_sys->b_chan_reorder )
    {
        msg_Dbg( p_aout, "channel reordering needed" );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
885

Gildas Bazin's avatar
 
Gildas Bazin committed
886
    return VLC_SUCCESS;
887 888 889
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
890 891 892 893 894
 * CreateDSBufferPCM: creates a PCM direct sound buffer.
 *****************************************************************************
 * We first try to create a WAVE_FORMAT_IEEE_FLOAT buffer if supported by
 * the hardware, otherwise we create a WAVE_FORMAT_PCM buffer.
 ****************************************************************************/
895
static int CreateDSBufferPCM( aout_instance_t *p_aout, vlc_fourcc_t *i_format,
Gildas Bazin's avatar
 
Gildas Bazin committed
896
                              int i_channels, int i_nb_channels, int i_rate,
897
                              bool b_probe )
Gildas Bazin's avatar
 
Gildas Bazin committed
898
{
Gildas Bazin's avatar
 
Gildas Bazin committed
899
    /* Float32 audio samples are not supported for 5.1 output on the emu101k */
900 901
    if( !var_GetBool( p_aout, "directx-audio-float32" ) ||
        i_nb_channels > 2 ||
902
        CreateDSBuffer( p_aout, VLC_CODEC_FL32,
Gildas Bazin's avatar
 
Gildas Bazin committed
903 904 905 906
                        i_channels, i_nb_channels, i_rate,
                        FRAME_SIZE * 4 * i_nb_channels, b_probe )
        != VLC_SUCCESS )
    {
907
        if ( CreateDSBuffer( p_aout, VLC_CODEC_S16L,
Gildas Bazin's avatar
 
Gildas Bazin committed
908 909 910 911 912 913 914 915
                             i_channels, i_nb_channels, i_rate,
                             FRAME_SIZE * 2 * i_nb_channels, b_probe )
             != VLC_SUCCESS )
        {
            return VLC_EGENERIC;
        }
        else
        {
916
            *i_format = VLC_CODEC_S16L;
Gildas Bazin's avatar
 
Gildas Bazin committed
917 918 919 920 921
            return VLC_SUCCESS;
        }
    }
    else
    {
922
        *i_format = VLC_CODEC_FL32;
Gildas Bazin's avatar
 
Gildas Bazin committed
923 924 925 926 927 928
        return VLC_SUCCESS;
    }
}

/*****************************************************************************
 * DestroyDSBuffer
929
 *****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
930
 * This function destroys the secondary buffer.
931
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
932
static void DestroyDSBuffer( aout_instance_t *p_aout )
933
{