directx.c 49.5 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 20
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
21
 * 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

Gildas Bazin's avatar
 
Gildas Bazin committed
37
#include <windows.h>
38 39 40
#include <mmsystem.h>
#include <dsound.h>

41 42
#define FRAME_SIZE ((int)p_aout->output.output.i_rate/20) /* Size in samples */
#define FRAMES_NUM 8                                      /* Needs to be > 3 */
Gildas Bazin's avatar
 
Gildas Bazin committed
43

44 45 46 47 48 49 50
/*****************************************************************************
 * DirectSound GUIDs.
 * Defining them here allows us to get rid of the dxguid library during
 * the linking stage.
 *****************************************************************************/
#include <initguid.h>

Gildas Bazin's avatar
 
Gildas Bazin committed
51 52 53 54 55 56 57
/*****************************************************************************
 * Useful macros
 *****************************************************************************/
#ifndef WAVE_FORMAT_IEEE_FLOAT
#   define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif

Gildas Bazin's avatar
 
Gildas Bazin committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
#   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
#endif

#ifndef WAVE_FORMAT_EXTENSIBLE
#define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
#endif

#ifndef SPEAKER_FRONT_LEFT
#   define SPEAKER_FRONT_LEFT             0x1
#   define SPEAKER_FRONT_RIGHT            0x2
#   define SPEAKER_FRONT_CENTER           0x4
#   define SPEAKER_LOW_FREQUENCY          0x8
#   define SPEAKER_BACK_LEFT              0x10
#   define SPEAKER_BACK_RIGHT             0x20
#   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
#   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
#   define SPEAKER_BACK_CENTER            0x100
#   define SPEAKER_SIDE_LEFT              0x200
#   define SPEAKER_SIDE_RIGHT             0x400
#   define SPEAKER_TOP_CENTER             0x800
#   define SPEAKER_TOP_FRONT_LEFT         0x1000
#   define SPEAKER_TOP_FRONT_CENTER       0x2000
#   define SPEAKER_TOP_FRONT_RIGHT        0x4000
#   define SPEAKER_TOP_BACK_LEFT          0x8000
#   define SPEAKER_TOP_BACK_CENTER        0x10000
#   define SPEAKER_TOP_BACK_RIGHT         0x20000
#   define SPEAKER_RESERVED               0x80000000
#endif

88 89 90
#ifndef DSSPEAKER_DSSPEAKER_DIRECTOUT
#   define DSSPEAKER_DSSPEAKER_DIRECTOUT         0x00000000
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
#ifndef DSSPEAKER_HEADPHONE
#   define DSSPEAKER_HEADPHONE         0x00000001
#endif
#ifndef DSSPEAKER_MONO
#   define DSSPEAKER_MONO              0x00000002
#endif
#ifndef DSSPEAKER_QUAD
#   define DSSPEAKER_QUAD              0x00000003
#endif
#ifndef DSSPEAKER_STEREO
#   define DSSPEAKER_STEREO            0x00000004
#endif
#ifndef DSSPEAKER_SURROUND
#   define DSSPEAKER_SURROUND          0x00000005
#endif
#ifndef DSSPEAKER_5POINT1
#   define DSSPEAKER_5POINT1           0x00000006
#endif
109 110 111 112 113 114 115 116 117
#ifndef DSSPEAKER_7POINT1
#   define DSSPEAKER_7POINT1           0x00000007
#endif
#ifndef DSSPEAKER_7POINT1_SURROUND
#   define DSSPEAKER_7POINT1_SURROUND           0x00000008
#endif
#ifndef DSSPEAKER_7POINT1_WIDE
#   define DSSPEAKER_7POINT1_WIDE           DSSPEAKER_7POINT1
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
118

Gildas Bazin's avatar
 
Gildas Bazin committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132
#ifndef _WAVEFORMATEXTENSIBLE_
typedef struct {
    WAVEFORMATEX    Format;
    union {
        WORD wValidBitsPerSample;       /* bits of precision  */
        WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
        WORD wReserved;                 /* If neither applies, set to zero. */
    } Samples;
    DWORD           dwChannelMask;      /* which channels are */
                                        /* present in stream  */
    GUID            SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
#endif

Gildas Bazin's avatar
 
Gildas Bazin committed
133 134 135
DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
Gildas Bazin's avatar
 
Gildas Bazin committed
136

137 138 139 140 141 142 143
/*****************************************************************************
 * notification_thread_t: DirectX event thread
 *****************************************************************************/
typedef struct notification_thread_t
{
    VLC_COMMON_MEMBERS

144 145 146
    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
147 148

    mtime_t start_date;
149
    HANDLE event;
150 151 152 153 154 155 156 157 158 159 160

} 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
161
    HINSTANCE           hdsound_dll;      /* handle of the opened dsound dll */
162

163
    char *              psz_device;         /* user defined device name */
164 165
    LPGUID              p_device_guid;

166 167 168 169 170
    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
171
    notification_thread_t *p_notif;                  /* DirectSoundThread id */
172

Gildas Bazin's avatar
 
Gildas Bazin committed
173
    int b_playing;                                         /* playing status */
174

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

177 178
    int i_speaker_setup;                 /* Speaker setup override */

179
    bool b_chan_reorder;              /* do we need channel reordering */
180
    int pi_chan_table[AOUT_CHAN_MAX];
Gildas Bazin's avatar
 
Gildas Bazin committed
181
    uint32_t i_channel_mask;
182 183
    uint32_t i_bits_per_sample;
    uint32_t i_channels;
184 185
};

186
static const uint32_t pi_channels_src[] =
Gildas Bazin's avatar
 
Gildas Bazin committed
187
    { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
188
      AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
189
      AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
190 191 192 193
      AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
static const uint32_t pi_channels_in[] =
    { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
      SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
194
      SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, SPEAKER_BACK_CENTER,
195
      SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
Gildas Bazin's avatar
 
Gildas Bazin committed
196 197
static const uint32_t pi_channels_out[] =
    { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
198
      SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
Gildas Bazin's avatar
 
Gildas Bazin committed
199
      SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
200
      SPEAKER_BACK_CENTER,
201
      SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
Gildas Bazin's avatar
 
Gildas Bazin committed
202

203 204 205
/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
206 207 208
static int  OpenAudio  ( vlc_object_t * );
static void CloseAudio ( vlc_object_t * );
static void Play       ( aout_instance_t * );
209 210

/* local functions */
Gildas Bazin's avatar
 
Gildas Bazin committed
211 212
static void Probe             ( aout_instance_t * );
static int  InitDirectSound   ( aout_instance_t * );
213
static int  CreateDSBuffer    ( aout_instance_t *, int, int, int, int, int, bool );
214
static int  CreateDSBufferPCM ( aout_instance_t *, vlc_fourcc_t*, int, int, int, bool );
Gildas Bazin's avatar
 
Gildas Bazin committed
215
static void DestroyDSBuffer   ( aout_instance_t * );
216
static void* DirectSoundThread( vlc_object_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
217 218
static int  FillBuffer        ( aout_instance_t *, int, aout_buffer_t * );

219 220 221
static int ReloadDirectXDevices( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );

222 223 224
/* Speaker setup override options list */
static const char *const speaker_list[] = { "Windows default", "Mono", "Stereo",
                                            "Quad", "5.1", "7.1" };
225 226
static const char *const ppsz_adev[] = {"default",  };
static const char *const ppsz_adev_text[] = {"default", };
227

Gildas Bazin's avatar
 
Gildas Bazin committed
228 229 230
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
231
#define DEVICE_TEXT N_("Output device")
232
#define DEVICE_LONGTEXT N_("Select your audio output device")
233 234 235 236
#define FLOAT_TEXT N_("Use float32 output")
#define FLOAT_LONGTEXT N_( \
    "The option allows you to enable or disable the high-quality float32 " \
    "audio output mode (which is not well supported by some soundcards)." )
237
#define SPEAKER_TEXT N_("Speaker configuration")
238 239
#define SPEAKER_LONGTEXT N_("Select speaker configuration you want to use. " \
    "This option doesn't upmix! So NO e.g. Stereo -> 5.1 conversion." )
240

241 242 243 244 245 246 247
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 )
    add_shortcut( "directx" )
248 249 250 251
    add_string( "directx-audio-device-name", "default", NULL,
             DEVICE_TEXT, DEVICE_LONGTEXT, false )
    change_string_list( ppsz_adev, ppsz_adev_text, ReloadDirectXDevices )
    change_action_add( ReloadDirectXDevices, N_("Refresh list") )
Rémi Duraffort's avatar
Rémi Duraffort committed
252
    add_bool( "directx-audio-float32", false, NULL, FLOAT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
253
              FLOAT_LONGTEXT, true )
254 255 256 257
    add_string( "directx-audio-speaker", "Windows default", NULL,
                 SPEAKER_TEXT, SPEAKER_LONGTEXT, true )
        change_string_list( speaker_list, 0, 0 )
        change_need_restart ()
258

259 260
    set_callbacks( OpenAudio, CloseAudio )
vlc_module_end ()
Gildas Bazin's avatar
 
Gildas Bazin committed
261

262 263 264 265 266
/*****************************************************************************
 * OpenAudio: open the audio device
 *****************************************************************************
 * This function opens and setups Direct Sound.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
267
static int OpenAudio( vlc_object_t *p_this )
268
{
Gildas Bazin's avatar
 
Gildas Bazin committed
269
    aout_instance_t * p_aout = (aout_instance_t *)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
270
    vlc_value_t val;
271 272 273 274
    char * psz_speaker;
    int i = 0;

    const char * const * ppsz_compare = speaker_list;
275

Gildas Bazin's avatar
 
Gildas Bazin committed
276
    msg_Dbg( p_aout, "OpenAudio" );
277 278

   /* Allocate structure */
Gildas Bazin's avatar
 
Gildas Bazin committed
279 280
    p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
    if( p_aout->output.p_sys == NULL )
281
        return VLC_ENOMEM;
282 283

    /* Initialize some variables */
Gildas Bazin's avatar
 
Gildas Bazin committed
284 285 286
    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
287
    p_aout->output.p_sys->b_playing = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
288 289

    p_aout->output.pf_play = Play;
290
    aout_VolumeSoftInit( p_aout );
291

292 293 294
    /* Retrieve config values */
    var_Create( p_aout, "directx-audio-float32",
                VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
295
    psz_speaker = var_CreateGetString( p_aout, "directx-audio-speaker" );
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

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

    if ( *ppsz_compare == NULL )
    {
        msg_Err( p_aout, "(%s) isn't valid speaker setup option",
                 psz_speaker );
        msg_Err( p_aout, "Defaulting to Windows default speaker config");
        i = 0;
    }
313
    free( psz_speaker );
314 315
    p_aout->output.p_sys->i_speaker_setup = i;

316 317
    p_aout->output.p_sys->p_device_guid = 0;

318
    /* Initialise DirectSound */
Gildas Bazin's avatar
 
Gildas Bazin committed
319
    if( InitDirectSound( p_aout ) )
320
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
321 322
        msg_Err( p_aout, "cannot initialize DirectSound" );
        goto error;
323 324
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
325 326 327 328 329 330 331 332
    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
333
        goto error;
Gildas Bazin's avatar
 
Gildas Bazin committed
334 335 336
    }

    /* Open the device */
Gildas Bazin's avatar
 
Gildas Bazin committed
337
    if( val.i_int == AOUT_VAR_SPDIF )
338
    {
339
        p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
Gildas Bazin's avatar
 
Gildas Bazin committed
340 341 342 343 344 345 346 347

        /* 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;

348
        if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
Gildas Bazin's avatar
 
Gildas Bazin committed
349 350 351
                            p_aout->output.output.i_physical_channels,
                            aout_FormatNbChannels( &p_aout->output.output ),
                            p_aout->output.output.i_rate,
352
                            p_aout->output.p_sys->i_frame_size, false )
Gildas Bazin's avatar
 
Gildas Bazin committed
353 354
            != VLC_SUCCESS )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
355
            msg_Err( p_aout, "cannot open directx audio device" );
Gildas Bazin's avatar
 
Gildas Bazin committed
356 357 358 359 360 361 362 363
            free( p_aout->output.p_sys );
            return VLC_EGENERIC;
        }

        aout_VolumeNoneInit( p_aout );
    }
    else
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
364
        if( val.i_int == AOUT_VAR_5_1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
365 366 367 368 369 370
        {
            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;
        }
371 372 373 374 375 376 377 378
        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;
        }
379 380 381 382 383 384
        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
385
        else if( val.i_int == AOUT_VAR_2F2R )
Gildas Bazin's avatar
 
Gildas Bazin committed
386 387 388 389 390
        {
            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
391
        else if( val.i_int == AOUT_VAR_MONO )
Gildas Bazin's avatar
 
Gildas Bazin committed
392 393 394 395 396 397 398 399
        {
            p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
        }
        else
        {
            p_aout->output.output.i_physical_channels
                = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
        }
400

Gildas Bazin's avatar
 
Gildas Bazin committed
401 402 403
        if( CreateDSBufferPCM( p_aout, &p_aout->output.output.i_format,
                               p_aout->output.output.i_physical_channels,
                               aout_FormatNbChannels( &p_aout->output.output ),
404
                               p_aout->output.output.i_rate, false )
Gildas Bazin's avatar
 
Gildas Bazin committed
405
            != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
406
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
407
            msg_Err( p_aout, "cannot open directx audio device" );
Gildas Bazin's avatar
 
Gildas Bazin committed
408 409
            free( p_aout->output.p_sys );
            return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
410
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
411 412 413 414 415

        /* 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
416
    }
417

418 419 420 421 422 423 424 425 426
    /* 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
427 428 429 430
    /* 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
431
                           DirectSoundThread,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
432
                           VLC_THREAD_PRIORITY_HIGHEST ) )
Christophe Massiot's avatar
Christophe Massiot committed
433 434
    {
        msg_Err( p_aout, "cannot create DirectSoundThread" );
435
        CloseHandle( p_aout->output.p_sys->p_notif->event );
436
        vlc_object_release( p_aout->output.p_sys->p_notif );
437
        p_aout->output.p_sys->p_notif = NULL;
Christophe Massiot's avatar
Christophe Massiot committed
438 439 440 441 442
        goto error;
    }

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

Gildas Bazin's avatar
 
Gildas Bazin committed
443
    return VLC_SUCCESS;
Christophe Massiot's avatar
Christophe Massiot committed
444 445

 error:
Gildas Bazin's avatar
 
Gildas Bazin committed
446
    CloseAudio( VLC_OBJECT(p_aout) );
447
    return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
448 449
}

Gildas Bazin's avatar
 
Gildas Bazin committed
450 451 452 453 454
/*****************************************************************************
 * 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
455
    vlc_value_t val, text;
456
    vlc_fourcc_t i_format;
Gildas Bazin's avatar
 
Gildas Bazin committed
457 458
    unsigned int i_physical_channels;
    DWORD ui_speaker_config;
459
    bool is_default_output_set = false;
Gildas Bazin's avatar
 
Gildas Bazin committed
460

Gildas Bazin's avatar
 
Gildas Bazin committed
461
    var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
462
    text.psz_string = _("Audio Device");
Gildas Bazin's avatar
 
Gildas Bazin committed
463
    var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
Gildas Bazin's avatar
 
Gildas Bazin committed
464 465 466 467 468 469 470 471

    /* 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,
472
                               p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
473 474
            == VLC_SUCCESS )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
475
            val.i_int = AOUT_VAR_5_1;
476
            text.psz_string = (char*) "5.1";
Gildas Bazin's avatar
 
Gildas Bazin committed
477 478
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
479 480
            var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
            is_default_output_set = true;
Gildas Bazin's avatar
 
Gildas Bazin committed
481 482 483 484
            msg_Dbg( p_aout, "device supports 5.1 channels" );
        }
    }

485 486 487 488 489
    /* 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
490 491 492
    if( p_aout->output.output.i_physical_channels == i_physical_channels )
    {
        if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 8,
493
                                  p_aout->output.output.i_rate, true )
Rémi Duraffort's avatar
Rémi Duraffort committed
494 495 496 497 498 499 500 501 502 503 504
            == 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" );
        }
    }
505

506 507 508 509 510 511 512
    /* 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,
513
                               p_aout->output.output.i_rate, true )
514 515 516
            == VLC_SUCCESS )
        {
            val.i_int = AOUT_VAR_3F2R;
517
            text.psz_string = _("3 Front 2 Rear");
518 519
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
520 521 522 523 524
            if(!is_default_output_set)
            {
                var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
                is_default_output_set = true;
            }
525 526 527 528
            msg_Dbg( p_aout, "device supports 5 channels" );
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
529 530 531 532 533 534 535
    /* 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,
536
                               p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
537 538
            == VLC_SUCCESS )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
539
            val.i_int = AOUT_VAR_2F2R;
540
            text.psz_string = _("2 Front 2 Rear");
Gildas Bazin's avatar
 
Gildas Bazin committed
541 542
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
543 544 545 546 547
            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
548 549 550 551 552 553 554
            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,
555
                           p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
556 557
        == VLC_SUCCESS )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
558
        val.i_int = AOUT_VAR_STEREO;
559
        text.psz_string = _("Stereo");
Gildas Bazin's avatar
 
Gildas Bazin committed
560
        var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
561 562 563 564 565 566
        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!)" );
        }
567
        else msg_Dbg( p_aout, "device supports 2 channels" );
Gildas Bazin's avatar
 
Gildas Bazin committed
568 569 570 571 572
    }

    /* Test for mono support */
    i_physical_channels = AOUT_CHAN_CENTER;
    if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 1,
573
                           p_aout->output.output.i_rate, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
574 575
        == VLC_SUCCESS )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
576
        val.i_int = AOUT_VAR_MONO;
577
        text.psz_string = _("Mono");
Gildas Bazin's avatar
 
Gildas Bazin committed
578
        var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
Gildas Bazin's avatar
 
Gildas Bazin committed
579 580 581 582 583 584 585 586 587
        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;
588
        msg_Dbg( p_aout, "GetSpeakerConfig failed" );
Gildas Bazin's avatar
 
Gildas Bazin committed
589 590 591
    }
    switch( DSSPEAKER_CONFIG(ui_speaker_config) )
    {
592
    case DSSPEAKER_7POINT1:
593
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is 7.1" );
594 595
        val.i_int = AOUT_VAR_7_1;
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
596
    case DSSPEAKER_5POINT1:
597
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is 5.1" );
Gildas Bazin's avatar
 
Gildas Bazin committed
598
        val.i_int = AOUT_VAR_5_1;
Gildas Bazin's avatar
 
Gildas Bazin committed
599 600
        break;
    case DSSPEAKER_QUAD:
601
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is Quad" );
Gildas Bazin's avatar
 
Gildas Bazin committed
602
        val.i_int = AOUT_VAR_2F2R;
Gildas Bazin's avatar
 
Gildas Bazin committed
603
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
604 605
#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
606
    case DSSPEAKER_MONO:
Gildas Bazin's avatar
 
Gildas Bazin committed
607
        val.i_int = AOUT_VAR_MONO;
Gildas Bazin's avatar
 
Gildas Bazin committed
608
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
609
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
610
    case DSSPEAKER_SURROUND:
611
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is surround" );
Gildas Bazin's avatar
 
Gildas Bazin committed
612
    case DSSPEAKER_STEREO:
613
        msg_Dbg( p_aout, "Windows says your SpeakerConfig is stereo" );
Gildas Bazin's avatar
 
Gildas Bazin committed
614
    default:
615
        /* If nothing else is found, choose stereo output */
Gildas Bazin's avatar
 
Gildas Bazin committed
616
        val.i_int = AOUT_VAR_STEREO;
Gildas Bazin's avatar
 
Gildas Bazin committed
617 618
        break;
    }
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649

    /* 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
650 651
    var_Set( p_aout, "audio-device", val );

Gildas Bazin's avatar
 
Gildas Bazin committed
652 653 654
    /* Test for SPDIF support */
    if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
    {
655
        if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
Gildas Bazin's avatar
 
Gildas Bazin committed
656 657 658
                            p_aout->output.output.i_physical_channels,
                            aout_FormatNbChannels( &p_aout->output.output ),
                            p_aout->output.output.i_rate,
659
                            AOUT_SPDIF_SIZE, true )
Gildas Bazin's avatar
 
Gildas Bazin committed
660 661 662
            == VLC_SUCCESS )
        {
            msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
Gildas Bazin's avatar
 
Gildas Bazin committed
663
            val.i_int = AOUT_VAR_SPDIF;
664
            text.psz_string = _("A/52 over S/PDIF");
Gildas Bazin's avatar
 
Gildas Bazin committed
665 666
            var_Change( p_aout, "audio-device",
                        VLC_VAR_ADDCHOICE, &val, &text );
Gildas Bazin's avatar
 
Gildas Bazin committed
667 668 669 670 671
            if( config_GetInt( p_aout, "spdif" ) )
                var_Set( p_aout, "audio-device", val );
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
672 673 674 675 676 677 678 679
    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
680
    var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
681
    var_SetBool( p_aout, "intf-change", true );
Gildas Bazin's avatar
 
Gildas Bazin committed
682 683
}

Gildas Bazin's avatar
 
Gildas Bazin committed
684
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
685 686 687
 * 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
688
 *****************************************************************************/
689
static void Play( aout_instance_t *p_aout )
Gildas Bazin's avatar
 
Gildas Bazin committed
690
{
Gildas Bazin's avatar
 
Gildas Bazin committed
691 692 693
    if( !p_aout->output.p_sys->b_playing )
    {
        aout_buffer_t *p_buffer;
694
        int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
695 696 697 698 699 700 701 702

        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 */
703 704 705 706 707 708
        for( i = 0; i < FRAMES_NUM; i++ )
        {
            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
709 710

        /* wake up the audio output thread */
711
        SetEvent( p_aout->output.p_sys->p_notif->event );
Gildas Bazin's avatar
 
Gildas Bazin committed
712
    }
713 714 715 716 717
}

/*****************************************************************************
 * CloseAudio: close the audio device
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
718
static void CloseAudio( vlc_object_t *p_this )
719
{
Gildas Bazin's avatar
 
Gildas Bazin committed
720
    aout_instance_t * p_aout = (aout_instance_t *)p_this;
721
    aout_sys_t *p_sys = p_aout->output.p_sys;
722

723
    msg_Dbg( p_aout, "closing audio device" );
724 725

    /* kill the position notification thread, if any */
726
    if( p_sys->p_notif )
727
    {
728
        vlc_object_detach( p_sys->p_notif );
729 730 731
        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
732

733
        vlc_thread_join( p_sys->p_notif );
734
        vlc_object_release( p_sys->p_notif );
735 736 737
    }

    /* release the secondary buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
738
    DestroyDSBuffer( p_aout );
739 740

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

743
    /* free DSOUND.DLL */
744
    if( p_sys->hdsound_dll ) FreeLibrary( p_sys->hdsound_dll );
Gildas Bazin's avatar
 
Gildas Bazin committed
745

746
    free( p_aout->output.p_sys->p_device_guid );
747
    free( p_sys );
748 749
}

750 751 752 753 754 755
/*****************************************************************************
 * CallBackDirectSoundEnum: callback to enumerate available devices
 *****************************************************************************/
static int CALLBACK CallBackDirectSoundEnum( LPGUID p_guid, LPCSTR psz_desc,
                                             LPCSTR psz_mod, LPVOID _p_aout )
{
756 757
    VLC_UNUSED( psz_mod );

758 759 760 761
    aout_instance_t *p_aout = (aout_instance_t *)_p_aout;

    msg_Dbg( p_aout, "found device: %s", psz_desc );

762
    if( p_aout->output.p_sys->psz_device && !strcmp(p_aout->output.p_sys->psz_device, psz_desc) && p_guid )
763
    {
764
        /* Use the device corresponding to psz_device */
765 766 767 768
        p_aout->output.p_sys->p_device_guid = malloc( sizeof( GUID ) );
        *p_aout->output.p_sys->p_device_guid = *p_guid;
        msg_Dbg( p_aout, "using device: %s", psz_desc );
    }
769 770 771 772 773 774 775 776 777 778 779
    else
    {
        /* If no default device has been selected, chose the first one */
        if( !p_aout->output.p_sys->psz_device && p_guid )
        {
            p_aout->output.p_sys->psz_device = strdup( psz_desc );
            p_aout->output.p_sys->p_device_guid = malloc( sizeof( GUID ) );
            *p_aout->output.p_sys->p_device_guid = *p_guid;
            msg_Dbg( p_aout, "using device: %s", psz_desc );
        }
    }
780 781 782
    return 1;
}

783
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
784
 * InitDirectSound: handle all the gory details of DirectSound initialisation
785
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
786
static int InitDirectSound( aout_instance_t *p_aout )
787 788
{
    HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
789
    HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACK, LPVOID);
790

Gildas Bazin's avatar
 
Gildas Bazin committed
791 792
    p_aout->output.p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL");
    if( p_aout->output.p_sys->hdsound_dll == NULL )
793
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
794 795
        msg_Warn( p_aout, "cannot open DSOUND.DLL" );
        goto error;
796 797
    }

798 799 800
    OurDirectSoundCreate = (void *)
        GetProcAddress( p_aout->output.p_sys->hdsound_dll,
                        "DirectSoundCreate" );
801 802
    if( OurDirectSoundCreate == NULL )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
803 804
        msg_Warn( p_aout, "GetProcAddress FAILED" );
        goto error;
805 806
    }

807 808 809 810 811 812
    /* Get DirectSoundEnumerate */
    OurDirectSoundEnumerate = (void *)
       GetProcAddress( p_aout->output.p_sys->hdsound_dll,
                       "DirectSoundEnumerateA" );
    if( OurDirectSoundEnumerate )
    {
813
        p_aout->output.p_sys->psz_device = config_GetPsz(p_aout, "directx-audio-device-name");
814
        /* Attempt enumeration */
815
        if( FAILED( OurDirectSoundEnumerate( CallBackDirectSoundEnum,
816 817 818 819 820 821
                                             p_aout ) ) )
        {
            msg_Dbg( p_aout, "enumeration of DirectSound devices failed" );
        }
    }

822
    /* Create the direct sound object */
823
    if FAILED( OurDirectSoundCreate( p_aout->output.p_sys->p_device_guid,
824
                                     &p_aout->output.p_sys->p_dsobject,
Gildas Bazin's avatar
 
Gildas Bazin committed
825
                                     NULL ) )
826 827
    {
        msg_Warn( p_aout, "cannot create a direct sound device" );
Gildas Bazin's avatar
 
Gildas Bazin committed
828
        goto error;
829 830 831 832 833 834 835 836 837 838 839 840
    }

    /* 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
841 842 843
    if( IDirectSound_SetCooperativeLevel( p_aout->output.p_sys->p_dsobject,
                                          GetDesktopWindow(),
                                          DSSCL_EXCLUSIVE) )
844 845 846 847
    {
        msg_Warn( p_aout, "cannot set direct sound cooperative level" );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
848
    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
849 850 851 852 853 854 855 856

 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
857
    return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
858

859 860 861
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
862
 * CreateDSBuffer: Creates a direct sound buffer of the required format.
863 864 865 866 867 868 869 870
 *****************************************************************************
 * 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
871
 * you have to release the current one and create another.
872
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
873 874
static int CreateDSBuffer( aout_instance_t *p_aout, int i_format,
                           int i_channels, int i_nb_channels, int i_rate,
875
                           int i_bytes_per_frame, bool b_probe )
876
{
Gildas Bazin's avatar
 
Gildas Bazin committed
877
    WAVEFORMATEXTENSIBLE waveformat;
878
    DSBUFFERDESC         dsbdesc;
Gildas Bazin's avatar
 
Gildas Bazin committed
879
    unsigned int         i;
880

Gildas Bazin's avatar
 
Gildas Bazin committed
881 882
    /* First set the sound buffer format */
    waveformat.dwChannelMask = 0;
883
    for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
884
    {
885 886
        if( i_channels & pi_channels_src[i] )
            waveformat.dwChannelMask |= pi_channels_in[i];
887
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
888

Gildas Bazin's avatar
 
Gildas Bazin committed
889
    switch( i_format )
Gildas Bazin's avatar
 
Gildas Bazin committed
890
    {
891
    case VLC_CODEC_SPDIFL:
Gildas Bazin's avatar
 
Gildas Bazin committed
892
        i_nb_channels = 2;
Gildas Bazin's avatar
 
Gildas Bazin committed
893 894
        /* To prevent channel re-ordering */
        waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
Gildas Bazin's avatar
 
Gildas Bazin committed
895 896 897 898
        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
899
        waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
Gildas Bazin's avatar
 
Gildas Bazin committed
900
        break;
Gildas Bazin's avatar
 
Gildas Bazin committed
901

902
    case VLC_CODEC_FL32:
Gildas Bazin's avatar
 
Gildas Bazin committed
903 904 905 906
        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
907
        waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
Gildas Bazin's avatar
 
Gildas Bazin committed
908 909
        break;

910
    case VLC_CODEC_S16L:
Gildas Bazin's avatar
 
Gildas Bazin committed
911 912 913 914
        waveformat.Format.wBitsPerSample = 16;
        waveformat.Samples.wValidBitsPerSample =
            waveformat.Format.wBitsPerSample;
        waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
Gildas Bazin's avatar
 
Gildas Bazin committed
915
        waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
Gildas Bazin's avatar
 
Gildas Bazin committed
916 917
        break;
    }
918

Gildas Bazin's avatar
 
Gildas Bazin committed
919 920 921 922 923 924 925
    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;

926 927 928
    p_aout->output.p_sys->i_bits_per_sample = waveformat.Format.wBitsPerSample;
    p_aout->output.p_sys->i_channels = i_nb_channels;

929 930 931 932 933 934
    /* 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
935 936 937 938 939 940 941 942 943 944
    /* 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
945

946 947 948
        /* Needed for 5.1 on emu101k */
        dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
949 950 951 952 953 954 955 956

    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) )
    {
957 958 959 960 961
        if( dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE )
        {
            /* Try without DSBCAPS_LOCHARDWARE */
            dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
            if FAILED( IDirectSound_CreateSoundBuffer(
Gildas Bazin's avatar
 
Gildas Bazin committed
962 963
                   p_aout->output.p_sys->p_dsobject, &dsbdesc,
                   &p_aout->output.p_sys->p_dsbuffer, NULL) )
964 965 966 967 968 969 970
            {
                return VLC_EGENERIC;
            }
            if( !b_probe )
                msg_Dbg( p_aout, "couldn't use hardware sound buffer" );
        }
        else
Gildas Bazin's avatar
 
Gildas Bazin committed
971 972 973
        {
            return VLC_EGENERIC;
        }
974 975
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
976 977 978 979 980 981 982
    /* 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
983

984
    p_aout->output.p_sys->i_frame_size = i_bytes_per_frame;
Gildas Bazin's avatar
 
Gildas Bazin committed
985
    p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask;
986 987 988 989 990 991 992 993 994
    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
995

Gildas Bazin's avatar
 
Gildas Bazin committed
996
    return VLC_SUCCESS;
997 998 999
}

/*****************************************************************************