aout_directx.c 24 KB
Newer Older
Sam Hocevar's avatar
   
Sam Hocevar committed
1
2
3
4
/*****************************************************************************
 * aout_directx.c: Windows DirectX audio output method
 *****************************************************************************
 * Copyright (C) 1999, 2000 VideoLAN
gbazin's avatar
   
gbazin committed
5
 * $Id: aout_directx.c,v 1.6 2001/07/25 08:41:21 gbazin Exp $
Sam Hocevar's avatar
   
Sam Hocevar committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * Authors: Gildas Bazin <gbazin@netcourrier.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

#define MODULE_NAME directx
#include "modules_inner.h"

Sam Hocevar's avatar
   
Sam Hocevar committed
27
/* The most important thing to do for now is to fix the audio bug we've got
Sam Hocevar's avatar
   
Sam Hocevar committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 * on startup: the audio will start later than the video (sometimes) and
 * is trying to catching up with it.
 * At first sight it seems to be a scheduling problem
 */


/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include "defs.h"

#include <errno.h>                                                 /* ENOMEM */
#include <fcntl.h>                                       /* open(), O_WRONLY */
#include <string.h>                                            /* strerror() */
#include <unistd.h>                                      /* write(), close() */
#include <stdio.h>                                           /* "intf_msg.h" */
#include <stdlib.h>                            /* calloc(), malloc(), free() */

#include "config.h"
#include "common.h"                                     /* boolean_t, byte_t */
#include "threads.h"
#include "mtime.h"
#include "tests.h"

#include "directx.h"

#include "audio_output.h"                                   /* aout_thread_t */

#include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
#include "main.h"

#include "modules.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
60
#include "modules_export.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

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

typedef struct aout_sys_s
{
    LPDIRECTSOUND       p_dsobject;              /* main Direct Sound object */

    LPDIRECTSOUNDBUFFER p_dsbuffer_primary;     /* the actual sound card buffer
                                                   (not used directly) */

    LPDIRECTSOUNDBUFFER p_dsbuffer;   /* the sound buffer we use (direct sound
                                       * takes care of mixing all the
                                       * secondary buffers into the primary) */

Sam Hocevar's avatar
   
Sam Hocevar committed
80
81
    HINSTANCE           hdsound_dll;      /* handle of the opened dsound dll */

Sam Hocevar's avatar
   
Sam Hocevar committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    long l_buffer_size;                       /* secondary sound buffer size */
    long l_write_position;             /* next write position for the buffer */

    boolean_t b_active;

} aout_sys_t;

/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
static int     aout_Probe       ( probedata_t *p_data );
static int     aout_Open        ( aout_thread_t *p_aout );
static int     aout_SetFormat   ( aout_thread_t *p_aout );
static long    aout_GetBufInfo  ( aout_thread_t *p_aout, long l_buffer_info );
static void    aout_Play        ( aout_thread_t *p_aout,
                                  byte_t *buffer, int i_size );
static void    aout_Close       ( aout_thread_t *p_aout );

gbazin's avatar
   
gbazin committed
100
/* local functions */
Sam Hocevar's avatar
   
Sam Hocevar committed
101
102
static int DirectxCreateSecondaryBuffer( aout_thread_t *p_aout );
static int DirectxInitDSound( aout_thread_t *p_aout );
Sam Hocevar's avatar
   
Sam Hocevar committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

/*****************************************************************************
 * Functions exported as capabilities. They are declared as static so that
 * we don't pollute the namespace too much.
 *****************************************************************************/
void _M( aout_getfunctions )( function_list_t * p_function_list )
{
    p_function_list->pf_probe = aout_Probe;
    p_function_list->functions.aout.pf_open = aout_Open;
    p_function_list->functions.aout.pf_setformat = aout_SetFormat;
    p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
    p_function_list->functions.aout.pf_play = aout_Play;
    p_function_list->functions.aout.pf_close = aout_Close;
}

/*****************************************************************************
 * aout_Probe: probe the audio device and return a score
 *****************************************************************************
 * This function tries to probe for a Direct Sound  device and returns a
 * score to the plugin manager so that it can select the best plugin.
 *****************************************************************************/
static int aout_Probe( probedata_t *p_data )
{
    /* For now just assume the computer has a sound device */
    if( TestMethod( AOUT_METHOD_VAR, "directx" ) )
    {
        return( 999 );
    }
    return( 400 );
}

/*****************************************************************************
 * aout_Open: open the audio device
 *****************************************************************************
 * This function opens and setups Direct Sound.
 *****************************************************************************/
static int aout_Open( aout_thread_t *p_aout )
{
    HRESULT dsresult;
    DSBUFFERDESC dsbuffer_desc;
    WAVEFORMATEX waveformat;
Sam Hocevar's avatar
   
Sam Hocevar committed
144
145

    intf_WarnMsg( 3, "aout: DirectX aout_Open ");
Sam Hocevar's avatar
   
Sam Hocevar committed
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

   /* Allocate structure */
    p_aout->p_sys = malloc( sizeof( aout_sys_t ) );

    if( p_aout->p_sys == NULL )
    {
        intf_ErrMsg( "aout error: %s", strerror(ENOMEM) );
        return( 1 );
    }

    /* Initialize some variables */
    p_aout->p_sys->p_dsobject = NULL;
    p_aout->p_sys->p_dsbuffer_primary = NULL;
    p_aout->p_sys->p_dsbuffer = NULL;

    p_aout->psz_device = 0;
    p_aout->i_format   = AOUT_FORMAT_DEFAULT;
    p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
                                                  AOUT_STEREO_DEFAULT );
    p_aout->l_rate     = main_GetIntVariable( AOUT_RATE_VAR,
                                              AOUT_RATE_DEFAULT );

Sam Hocevar's avatar
   
Sam Hocevar committed
168
169
    /* Initialise DirectSound */
    if( DirectxInitDSound( p_aout ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
170
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
171
        intf_WarnMsg( 3, "aout: can't initialise DirectSound ");
Sam Hocevar's avatar
   
Sam Hocevar committed
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        return( 1 );
    }

    /* Obtain (not create) Direct Sound primary buffer */
    memset( &dsbuffer_desc, 0, sizeof(DSBUFFERDESC) );
    dsbuffer_desc.dwSize = sizeof(DSBUFFERDESC);
    dsbuffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER;
    intf_WarnMsg( 3, "aout: Create direct sound primary buffer ");
    dsresult = IDirectSound_CreateSoundBuffer(p_aout->p_sys->p_dsobject,
                                            &dsbuffer_desc,
                                            &p_aout->p_sys->p_dsbuffer_primary,
                                            NULL);
    if( dsresult != DS_OK )
    {
        intf_WarnMsg( 3, "aout: can't create direct sound primary buffer ");
        IDirectSound_Release( p_aout->p_sys->p_dsobject );
        p_aout->p_sys->p_dsobject = NULL;
        p_aout->p_sys->p_dsbuffer_primary = NULL;
        return( 1 );
    }

    /* Set Direct Sound primary buffer format because the default value set by
     * Windows is usually not the high quality value */
    memset(&waveformat, 0, sizeof(WAVEFORMATEX)); 
    waveformat.wFormatTag = WAVE_FORMAT_PCM; 
    waveformat.nChannels = 2; 
    waveformat.nSamplesPerSec = 44100; 
    waveformat.wBitsPerSample = 16; 
    waveformat.nBlockAlign = waveformat.wBitsPerSample / 8 *
                                 waveformat.nChannels;
    waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec *
                                     waveformat.nBlockAlign;

    dsresult = IDirectSoundBuffer_SetFormat(p_aout->p_sys->p_dsbuffer_primary,
                                            &waveformat);
    if( dsresult != DS_OK )
    {
        intf_WarnMsg( 3, "aout: can't set primary buffer format");
    }

gbazin's avatar
   
gbazin committed
212
#if 0
Sam Hocevar's avatar
   
Sam Hocevar committed
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    /* ensure the primary buffer is playing. We won't actually hear anything
     * until the secondary buffer is playing */
    dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer_primary,
                                        0,
                                        0,
                                        DSBPLAY_LOOPING);
    if( dsresult != DS_OK )
    {
        intf_WarnMsg( 3, "aout: can't play direct sound primary buffer ");
        IDirectSound_Release( p_aout->p_sys->p_dsbuffer_primary );
        IDirectSound_Release( p_aout->p_sys->p_dsobject );
        p_aout->p_sys->p_dsobject = NULL;
        p_aout->p_sys->p_dsbuffer_primary = NULL;
        return( 1 );
    }
gbazin's avatar
   
gbazin committed
228
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

    return( 0 );
}

/*****************************************************************************
 * aout_SetFormat: reset the audio device and sets its format
 *****************************************************************************
 * This functions set a new audio format.
 * For this we need to close the current secondary buffer and create another
 * one with the desired format.
 *****************************************************************************/
static int aout_SetFormat( aout_thread_t *p_aout )
{
    HRESULT dsresult;

Sam Hocevar's avatar
   
Sam Hocevar committed
244
245
    intf_WarnMsg( 3, "aout: DirectX aout_SetFormat ");

Sam Hocevar's avatar
   
Sam Hocevar committed
246
247
248
249
250
251
252
253
    /* first release the current secondary buffer */
    if( p_aout->p_sys->p_dsbuffer != NULL )
    {
        IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer );
        p_aout->p_sys->p_dsbuffer = NULL;
    }

    /* then create a new secondary buffer */
Sam Hocevar's avatar
   
Sam Hocevar committed
254
    dsresult = DirectxCreateSecondaryBuffer( p_aout );    
Sam Hocevar's avatar
   
Sam Hocevar committed
255
256
    if( dsresult != DS_OK )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
257
        intf_WarnMsg( 3, "aout: DirectX aout_SetFormat cannot create buffer");
Sam Hocevar's avatar
   
Sam Hocevar committed
258
259
        return( 1 );
    }
260
261

    p_aout->i_latency = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  
    return( 0 );
}

/*****************************************************************************
 * aout_GetBufInfo: buffer status query
 *****************************************************************************
 * returns the number of bytes in the audio buffer compared to the size of
 * l_buffer_limit...
 *****************************************************************************/
static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
{
    long l_play_position, l_notused, l_result;
    HRESULT dsresult;

    dsresult = IDirectSoundBuffer_GetCurrentPosition(p_aout->p_sys->p_dsbuffer,
                                                 &l_play_position, &l_notused);
    if( dsresult == DSERR_BUFFERLOST )
    {
        IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
        dsresult = IDirectSoundBuffer_GetCurrentPosition(
                                                 p_aout->p_sys->p_dsbuffer,
                                                 &l_play_position, &l_notused
                                                        );
    }
    if( dsresult != DS_OK )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
289
        intf_WarnMsg(3,"aout: DirectX aout_GetBufInfo cannot get current pos");
Sam Hocevar's avatar
   
Sam Hocevar committed
290
291
292
        return( l_buffer_limit );
    }

gbazin's avatar
   
gbazin committed
293
#if 0
Sam Hocevar's avatar
   
Sam Hocevar committed
294
295
296
297
298
299
300
301
    /* temporary hack. When you start playing a new file, the play position
     * doesn't start changing immediatly, even though sound is already
     * playing from the sound card */
    if( l_play_position == 0 )
    { 
       intf_WarnMsg( 5, "aout: DirectX aout_GetBufInfo: %li", l_buffer_limit);
       return( l_buffer_limit );
    }
gbazin's avatar
   
gbazin committed
302
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
303
304
305
306
307

    l_result = (p_aout->p_sys->l_write_position >= l_play_position) ?
      (p_aout->p_sys->l_write_position - l_play_position) /2
               : (p_aout->p_sys->l_buffer_size - l_play_position
                  + p_aout->p_sys->l_write_position) /2 ;
Sam Hocevar's avatar
   
Sam Hocevar committed
308

gbazin's avatar
   
gbazin committed
309
#if 0
Sam Hocevar's avatar
   
Sam Hocevar committed
310
    intf_WarnMsg( 5, "aout: DirectX aout_GetBufInfo: %li", l_result);
gbazin's avatar
   
gbazin committed
311
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
    return l_result;
}

/*****************************************************************************
 * aout_Play: play a sound buffer
 *****************************************************************************
 * This function writes a buffer of i_length bytes
 *****************************************************************************/
static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
    VOID            *p_write_position, *p_start_buffer;
    long            l_bytes1, l_bytes2;
    long            l_play_position, l_notused, l_buffer_free_length;
    HRESULT         dsresult;

Sam Hocevar's avatar
   
Sam Hocevar committed
327
    /* We want to copy data to the circular sound buffer, so we first need to
Sam Hocevar's avatar
   
Sam Hocevar committed
328
329
330
331
332
333
334
335
336
337
338
339
340
341
     * find out were in the buffer we can write our data */
    dsresult = IDirectSoundBuffer_GetCurrentPosition(p_aout->p_sys->p_dsbuffer,
                                                     &l_play_position,
                                                     &l_notused);
    if( dsresult == DSERR_BUFFERLOST )
    {
        IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
        dsresult = IDirectSoundBuffer_GetCurrentPosition(
                                                 p_aout->p_sys->p_dsbuffer,
                                                 &l_play_position, &l_notused
                                                        );
    }
    if( dsresult != DS_OK )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
342
        intf_WarnMsg( 3, "aout: DirectX aout_Play can'get buffer position");
Sam Hocevar's avatar
   
Sam Hocevar committed
343
344
    }

gbazin's avatar
   
gbazin committed
345
#if 1
Sam Hocevar's avatar
   
Sam Hocevar committed
346
347
348
349
    /* check that we are not overflowing the circular buffer (everything should
     * be alright but just in case) */
    l_buffer_free_length =  l_play_position - p_aout->p_sys->l_write_position;
    if( l_buffer_free_length <= 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
350
        l_buffer_free_length += p_aout->p_sys->l_buffer_size;
Sam Hocevar's avatar
   
Sam Hocevar committed
351
352
353

    if( i_size > l_buffer_free_length )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
354
355
        intf_WarnMsg( 3, "aout: DirectX aout_Play buffer overflow: size %i, free %i !!!", i_size, l_buffer_free_length);
        intf_WarnMsg( 3, "aout: DirectX aout_Play buffer overflow: writepos %i, readpos %i !!!", p_aout->p_sys->l_write_position, l_play_position);
Sam Hocevar's avatar
   
Sam Hocevar committed
356
        /*i_size = l_buffer_free_length;*/
Sam Hocevar's avatar
   
Sam Hocevar committed
357
358
359
360
361
362
363

        /* Update the write pointer */
        p_aout->p_sys->l_write_position = l_notused;

    }
    else
    {
gbazin's avatar
   
gbazin committed
364
#if 0
Sam Hocevar's avatar
   
Sam Hocevar committed
365
366
367
        intf_WarnMsg( 4, "aout: DirectX aout_Play buffer: size %i, free %i !!!"
                      , i_size, l_buffer_free_length);
        intf_WarnMsg( 4, "aout: DirectX aout_Play buffer: writepos %i, readpos %i !!!", p_aout->p_sys->l_write_position, l_play_position);
gbazin's avatar
   
gbazin committed
368
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
369
    }
gbazin's avatar
   
gbazin committed
370
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

    /* Before copying anything, we have to lock the buffer */
    dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
                   p_aout->p_sys->l_write_position,  /* Offset of lock start */
                   i_size,                        /* Number of bytes to lock */
                   &p_write_position,               /* Address of lock start */
                   &l_bytes1,    /* Count of bytes locked before wrap around */
                   &p_start_buffer,        /* Buffer adress (if wrap around) */
                   &l_bytes2,            /* Count of bytes after wrap around */
                   0);                                              /* Flags */
    if( dsresult == DSERR_BUFFERLOST )
    {
        IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
        dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
                                            p_aout->p_sys->l_write_position,
                                            i_size,
                                            &p_write_position,
                                            &l_bytes1,
                                            &p_start_buffer,
                                            &l_bytes2,
                                            0);

    }
    if( dsresult != DS_OK )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
396
        intf_WarnMsg( 3, "aout: DirectX aout_Play can't lock buffer");
Sam Hocevar's avatar
   
Sam Hocevar committed
397
398
399
400
401
402
        return;
    }

    /* Now do the actual memcopy (two memcpy because the buffer is circular) */
    memcpy( p_write_position, buffer, l_bytes1 );
    if( p_start_buffer != NULL )
gbazin's avatar
   
gbazin committed
403
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
404
        memcpy( p_start_buffer, buffer + l_bytes1, l_bytes2 );
gbazin's avatar
   
gbazin committed
405
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

    /* Now the data has been copied, unlock the buffer */
    IDirectSoundBuffer_Unlock( p_aout->p_sys->p_dsbuffer, 
            p_write_position, l_bytes1, p_start_buffer, l_bytes2 );

    /* Update the write position index of the buffer*/
    p_aout->p_sys->l_write_position += i_size;
    p_aout->p_sys->l_write_position %= p_aout->p_sys->l_buffer_size;

    /* The play function has no effect if the buffer is already playing */
    dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer,
                                        0,                         /* Unused */
                                        0,                         /* Unused */
                                        DSBPLAY_LOOPING );          /* Flags */
    if( dsresult == DSERR_BUFFERLOST )
    {
        IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
        dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer,
                                            0,                     /* Unused */
                                            0,                     /* Unused */
                                            DSBPLAY_LOOPING );      /* Flags */
    }
    if( dsresult != DS_OK )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
430
        intf_WarnMsg( 3, "aout: DirectX aout_Play can't play buffer");
Sam Hocevar's avatar
   
Sam Hocevar committed
431
432
433
434
435
436
437
438
439
440
        return;
    }

}

/*****************************************************************************
 * aout_Close: close the audio device
 *****************************************************************************/
static void aout_Close( aout_thread_t *p_aout )
{
Sam Hocevar's avatar
   
Sam Hocevar committed
441
442
443

    intf_WarnMsg( 3, "aout: DirectX aout_Close ");

Sam Hocevar's avatar
   
Sam Hocevar committed
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
    /* make sure the buffer isn't playing */
    if( p_aout->p_sys->p_dsbuffer != NULL )
    {
        IDirectSoundBuffer_Stop( p_aout->p_sys->p_dsbuffer );
    }

    /* first release the secondary buffer */
    if( p_aout->p_sys->p_dsbuffer != NULL )
    {
        IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer );
        p_aout->p_sys->p_dsbuffer = NULL;
    }  

    /* then release the primary buffer */
    if( p_aout->p_sys->p_dsbuffer_primary != NULL )
    {
        IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer_primary );
        p_aout->p_sys->p_dsbuffer_primary = NULL;
    }  

    /* finally release the DirectSound object */
    if( p_aout->p_sys->p_dsobject != NULL )
    {
        IDirectSound_Release( p_aout->p_sys->p_dsobject );
        p_aout->p_sys->p_dsobject = NULL;
    }  
    
Sam Hocevar's avatar
   
Sam Hocevar committed
471
472
473
474
475
476
477
    /* free DSOUND.DLL */
    if( p_aout->p_sys->hdsound_dll != NULL )
    {
       FreeLibrary( p_aout->p_sys->hdsound_dll );
       p_aout->p_sys->hdsound_dll = NULL;
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
478
479
480
481
482
483
484
485
486
    /* Close the Output. */
    if ( p_aout->p_sys != NULL )
    { 
        free( p_aout->p_sys );
        p_aout->p_sys = NULL;
    }
}

/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
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
538
539
540
541
542
543
 * DirectxInitDSound
 *****************************************************************************
 *****************************************************************************/
static int DirectxInitDSound( aout_thread_t *p_aout )
{
    HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);

    p_aout->p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL");
    if( p_aout->p_sys->hdsound_dll == NULL )
    {
      intf_WarnMsg( 3, "aout: can't open DSOUND.DLL ");
      return( 1 );
    }

    OurDirectSoundCreate = (void *)GetProcAddress( p_aout->p_sys->hdsound_dll,
                                                   "DirectSoundCreate" );

    if( OurDirectSoundCreate == NULL )
    {
      intf_WarnMsg( 3, "aout: GetProcAddress FAILED ");
      FreeLibrary( p_aout->p_sys->hdsound_dll );
      p_aout->p_sys->hdsound_dll = NULL;
      return( 1 );
    }

    /* Create the direct sound object */
    if( OurDirectSoundCreate(NULL, &p_aout->p_sys->p_dsobject, NULL) != DS_OK )
    {
        intf_WarnMsg( 3, "aout: can't create a direct sound device ");
        p_aout->p_sys->p_dsobject = NULL;
        FreeLibrary( p_aout->p_sys->hdsound_dll );
        p_aout->p_sys->hdsound_dll = NULL;
        return( 1 );
    }

    /* 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 */
    if( IDirectSound_SetCooperativeLevel(p_aout->p_sys->p_dsobject,
                                         GetDesktopWindow(),
                                         DSSCL_EXCLUSIVE) )
    {
        intf_WarnMsg( 3, "aout: can't set direct sound cooperative level ");
    }

    return( 0 );
}

/*****************************************************************************
 * DirectxCreateSecondaryBuffer
Sam Hocevar's avatar
   
Sam Hocevar committed
544
545
546
547
548
549
550
551
552
553
 *****************************************************************************
 * 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
 * you have to release the current and create another one.
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
554
static int DirectxCreateSecondaryBuffer( aout_thread_t *p_aout )
Sam Hocevar's avatar
   
Sam Hocevar committed
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
{
    WAVEFORMATEX waveformat;
    DSBUFFERDESC dsbdesc;
    DSBCAPS      dsbcaps;

    /* First set the buffer format */
    memset(&waveformat, 0, sizeof(WAVEFORMATEX)); 
    waveformat.wFormatTag = WAVE_FORMAT_PCM; 
    waveformat.nChannels = p_aout->i_channels; 
    waveformat.nSamplesPerSec = p_aout->l_rate; 
    waveformat.wBitsPerSample = 16; 
    waveformat.nBlockAlign = waveformat.wBitsPerSample / 8 *
                                 waveformat.nChannels;
    waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec *
                                     waveformat.nBlockAlign;

    /* Then fill in the descriptor */
    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); 
    dsbdesc.dwSize = sizeof(DSBUFFERDESC); 
    dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
                    | DSBCAPS_GLOBALFOCUS;      /* Allows background playing */
gbazin's avatar
   
gbazin committed
576
    dsbdesc.dwBufferBytes = waveformat.nAvgBytesPerSec * 2;  /* 2 sec buffer */
Sam Hocevar's avatar
   
Sam Hocevar committed
577
578
579
580
581
582
583
584
585
586
587
588
589
590
    dsbdesc.lpwfxFormat = &waveformat; 
 
    if( IDirectSound_CreateSoundBuffer( p_aout->p_sys->p_dsobject,
                                        &dsbdesc,
                                        &p_aout->p_sys->p_dsbuffer,
                                        NULL) != DS_OK )
    {
        intf_WarnMsg( 3, "aout: can't create direct sound secondary buffer ");
        p_aout->p_sys->p_dsbuffer = NULL;
        return( 1 );
    }

    /* backup the size of the secondary sound buffer */
    memset(&dsbcaps, 0, sizeof(DSBCAPS)); 
Sam Hocevar's avatar
   
Sam Hocevar committed
591
    dsbcaps.dwSize = sizeof(DSBCAPS);
Sam Hocevar's avatar
   
Sam Hocevar committed
592
593
594
    IDirectSoundBuffer_GetCaps( p_aout->p_sys->p_dsbuffer, &dsbcaps  );
    p_aout->p_sys->l_buffer_size = dsbcaps.dwBufferBytes;
    p_aout->p_sys->l_write_position = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
595
    intf_WarnMsg( 3, "aout: DirectX DirectxCreateSecondaryBuffer: %li",
Sam Hocevar's avatar
   
Sam Hocevar committed
596
597
598
599
                  p_aout->p_sys->l_buffer_size);

    return( 0 );
}