directx.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:41k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * directx.c: Windows DirectX audio output method
  3.  *****************************************************************************
  4.  * Copyright (C) 2001 VideoLAN
  5.  * $Id: directx.c 9153 2004-11-05 12:56:35Z gbazin $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <errno.h>                                                 /* ENOMEM */
  27. #include <fcntl.h>                                       /* open(), O_WRONLY */
  28. #include <string.h>                                            /* strerror() */
  29. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  30. #include <vlc/vlc.h>
  31. #include <vlc/aout.h>
  32. #include "aout_internal.h"
  33. #include <windows.h>
  34. #include <mmsystem.h>
  35. #include <dsound.h>
  36. #define FRAME_SIZE 2048              /* The size is in samples, not in bytes */
  37. #define FRAMES_NUM 8
  38. /* frame buffer status */
  39. #define FRAME_QUEUED 0
  40. #define FRAME_EMPTY 1
  41. /*****************************************************************************
  42.  * DirectSound GUIDs.
  43.  * Defining them here allows us to get rid of the dxguid library during
  44.  * the linking stage.
  45.  *****************************************************************************/
  46. #include <initguid.h>
  47. DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
  48. /*****************************************************************************
  49.  * Useful macros
  50.  *****************************************************************************/
  51. #ifndef WAVE_FORMAT_IEEE_FLOAT
  52. #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
  53. #endif
  54. #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
  55. #   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
  56. #endif
  57. #ifndef WAVE_FORMAT_EXTENSIBLE
  58. #define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
  59. #endif
  60. #ifndef SPEAKER_FRONT_LEFT
  61. #   define SPEAKER_FRONT_LEFT             0x1
  62. #   define SPEAKER_FRONT_RIGHT            0x2
  63. #   define SPEAKER_FRONT_CENTER           0x4
  64. #   define SPEAKER_LOW_FREQUENCY          0x8
  65. #   define SPEAKER_BACK_LEFT              0x10
  66. #   define SPEAKER_BACK_RIGHT             0x20
  67. #   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
  68. #   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
  69. #   define SPEAKER_BACK_CENTER            0x100
  70. #   define SPEAKER_SIDE_LEFT              0x200
  71. #   define SPEAKER_SIDE_RIGHT             0x400
  72. #   define SPEAKER_TOP_CENTER             0x800
  73. #   define SPEAKER_TOP_FRONT_LEFT         0x1000
  74. #   define SPEAKER_TOP_FRONT_CENTER       0x2000
  75. #   define SPEAKER_TOP_FRONT_RIGHT        0x4000
  76. #   define SPEAKER_TOP_BACK_LEFT          0x8000
  77. #   define SPEAKER_TOP_BACK_CENTER        0x10000
  78. #   define SPEAKER_TOP_BACK_RIGHT         0x20000
  79. #   define SPEAKER_RESERVED               0x80000000
  80. #endif
  81. #ifndef DSSPEAKER_HEADPHONE
  82. #   define DSSPEAKER_HEADPHONE         0x00000001
  83. #endif
  84. #ifndef DSSPEAKER_MONO
  85. #   define DSSPEAKER_MONO              0x00000002
  86. #endif
  87. #ifndef DSSPEAKER_QUAD
  88. #   define DSSPEAKER_QUAD              0x00000003
  89. #endif
  90. #ifndef DSSPEAKER_STEREO
  91. #   define DSSPEAKER_STEREO            0x00000004
  92. #endif
  93. #ifndef DSSPEAKER_SURROUND
  94. #   define DSSPEAKER_SURROUND          0x00000005
  95. #endif
  96. #ifndef DSSPEAKER_5POINT1
  97. #   define DSSPEAKER_5POINT1           0x00000006
  98. #endif
  99. #ifndef _WAVEFORMATEXTENSIBLE_
  100. typedef struct {
  101.     WAVEFORMATEX    Format;
  102.     union {
  103.         WORD wValidBitsPerSample;       /* bits of precision  */
  104.         WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
  105.         WORD wReserved;                 /* If neither applies, set to zero. */
  106.     } Samples;
  107.     DWORD           dwChannelMask;      /* which channels are */
  108.                                         /* present in stream  */
  109.     GUID            SubFormat;
  110. } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
  111. #endif
  112. DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
  113. DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
  114. DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
  115. /*****************************************************************************
  116.  * notification_thread_t: DirectX event thread
  117.  *****************************************************************************/
  118. typedef struct notification_thread_t
  119. {
  120.     VLC_COMMON_MEMBERS
  121.     aout_instance_t * p_aout;
  122.     int i_frame_status[FRAMES_NUM];           /* status of each frame buffer */
  123.     DSBPOSITIONNOTIFY p_events[FRAMES_NUM];      /* play notification events */
  124.     int i_frame_size;                         /* Size in bytes of one frame */
  125.     mtime_t start_date;
  126. } notification_thread_t;
  127. /*****************************************************************************
  128.  * aout_sys_t: directx audio output method descriptor
  129.  *****************************************************************************
  130.  * This structure is part of the audio output thread descriptor.
  131.  * It describes the direct sound specific properties of an audio device.
  132.  *****************************************************************************/
  133. struct aout_sys_t
  134. {
  135.     HINSTANCE           hdsound_dll;      /* handle of the opened dsound dll */
  136.     LPDIRECTSOUND       p_dsobject;              /* main Direct Sound object */
  137.     LPDIRECTSOUNDBUFFER p_dsbuffer;   /* the sound buffer we use (direct sound
  138.                                        * takes care of mixing all the
  139.                                        * secondary buffers into the primary) */
  140.     LPDIRECTSOUNDNOTIFY p_dsnotify;         /* the position notify interface */
  141.     notification_thread_t *p_notif;                  /* DirectSoundThread id */
  142.     int b_playing;                                         /* playing status */
  143.     int i_frame_size;                         /* Size in bytes of one frame */
  144.     vlc_bool_t b_chan_reorder;              /* do we need channel reordering */
  145.     int pi_chan_table[AOUT_CHAN_MAX];
  146.     uint32_t i_channel_mask;
  147.     uint32_t i_bits_per_sample;
  148.     uint32_t i_channels;
  149. };
  150. static const uint32_t pi_channels_src[] =
  151.     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
  152.       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
  153.       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
  154.       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
  155. static const uint32_t pi_channels_in[] =
  156.     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
  157.       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
  158.       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
  159.       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
  160. static const uint32_t pi_channels_out[] =
  161.     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
  162.       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
  163.       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
  164.       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
  165. /*****************************************************************************
  166.  * Local prototypes.
  167.  *****************************************************************************/
  168. static int  OpenAudio  ( vlc_object_t * );
  169. static void CloseAudio ( vlc_object_t * );
  170. static void Play       ( aout_instance_t * );
  171. /* local functions */
  172. static void Probe             ( aout_instance_t * );
  173. static int  InitDirectSound   ( aout_instance_t * );
  174. static int  CreateDSBuffer    ( aout_instance_t *, int, int, int, int, int, vlc_bool_t );
  175. static int  CreateDSBufferPCM ( aout_instance_t *, int*, int, int, int, vlc_bool_t );
  176. static void DestroyDSBuffer   ( aout_instance_t * );
  177. static void DirectSoundThread ( notification_thread_t * );
  178. static int  FillBuffer        ( aout_instance_t *, int, aout_buffer_t * );
  179. /*****************************************************************************
  180.  * Module descriptor
  181.  *****************************************************************************/
  182. vlc_module_begin();
  183.     set_description( _("DirectX audio output") );
  184.     set_capability( "audio output", 100 );
  185.     add_shortcut( "directx" );
  186.     set_callbacks( OpenAudio, CloseAudio );
  187. vlc_module_end();
  188. /*****************************************************************************
  189.  * OpenAudio: open the audio device
  190.  *****************************************************************************
  191.  * This function opens and setups Direct Sound.
  192.  *****************************************************************************/
  193. static int OpenAudio( vlc_object_t *p_this )
  194. {
  195.     aout_instance_t * p_aout = (aout_instance_t *)p_this;
  196.     vlc_value_t val;
  197.     int i;
  198.     msg_Dbg( p_aout, "OpenAudio" );
  199.    /* Allocate structure */
  200.     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
  201.     if( p_aout->output.p_sys == NULL )
  202.     {
  203.         msg_Err( p_aout, "out of memory" );
  204.         return VLC_EGENERIC;
  205.     }
  206.     /* Initialize some variables */
  207.     p_aout->output.p_sys->p_dsobject = NULL;
  208.     p_aout->output.p_sys->p_dsbuffer = NULL;
  209.     p_aout->output.p_sys->p_dsnotify = NULL;
  210.     p_aout->output.p_sys->p_notif = NULL;
  211.     p_aout->output.p_sys->b_playing = 0;
  212.     p_aout->output.pf_play = Play;
  213.     aout_VolumeSoftInit( p_aout );
  214.     /* Initialise DirectSound */
  215.     if( InitDirectSound( p_aout ) )
  216.     {
  217.         msg_Err( p_aout, "cannot initialize DirectSound" );
  218.         goto error;
  219.     }
  220.     if( var_Type( p_aout, "audio-device" ) == 0 )
  221.     {
  222.         Probe( p_aout );
  223.     }
  224.     if( var_Get( p_aout, "audio-device", &val ) < 0 )
  225.     {
  226.         /* Probe() has failed. */
  227.         goto error;
  228.     }
  229.     /* Now we need to setup our DirectSound play notification structure */
  230.     p_aout->output.p_sys->p_notif =
  231.         vlc_object_create( p_aout, sizeof(notification_thread_t) );
  232.     p_aout->output.p_sys->p_notif->p_aout = p_aout;
  233.     /* Then create the notification events */
  234.     for( i = 0; i < FRAMES_NUM; i++ )
  235.         p_aout->output.p_sys->p_notif->p_events[i].hEventNotify =
  236.             CreateEvent( NULL, FALSE, FALSE, NULL );
  237.     /* Open the device */
  238.     if( val.i_int == AOUT_VAR_SPDIF )
  239.     {
  240.         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
  241.         /* Calculate the frame size in bytes */
  242.         p_aout->output.i_nb_samples = A52_FRAME_NB;
  243.         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
  244.         p_aout->output.output.i_frame_length = A52_FRAME_NB;
  245.         p_aout->output.p_sys->i_frame_size =
  246.             p_aout->output.output.i_bytes_per_frame;
  247.         if( CreateDSBuffer( p_aout, VLC_FOURCC('s','p','d','i'),
  248.                             p_aout->output.output.i_physical_channels,
  249.                             aout_FormatNbChannels( &p_aout->output.output ),
  250.                             p_aout->output.output.i_rate,
  251.                             p_aout->output.p_sys->i_frame_size, VLC_FALSE )
  252.             != VLC_SUCCESS )
  253.         {
  254.             msg_Err( p_aout, "cannot open directx audio device" );
  255.             free( p_aout->output.p_sys );
  256.             return VLC_EGENERIC;
  257.         }
  258.         aout_VolumeNoneInit( p_aout );
  259.     }
  260.     else
  261.     {
  262.         if( val.i_int == AOUT_VAR_5_1 )
  263.         {
  264.             p_aout->output.output.i_physical_channels
  265.                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
  266.                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  267.                    | AOUT_CHAN_LFE;
  268.         }
  269.         else if( val.i_int == AOUT_VAR_3F2R )
  270.         {
  271.             p_aout->output.output.i_physical_channels
  272.                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
  273.                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  274.         }
  275.         else if( val.i_int == AOUT_VAR_2F2R )
  276.         {
  277.             p_aout->output.output.i_physical_channels
  278.                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  279.                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  280.         }
  281.         else if( val.i_int == AOUT_VAR_MONO )
  282.         {
  283.             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
  284.         }
  285.         else
  286.         {
  287.             p_aout->output.output.i_physical_channels
  288.                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  289.         }
  290.         if( CreateDSBufferPCM( p_aout, &p_aout->output.output.i_format,
  291.                                p_aout->output.output.i_physical_channels,
  292.                                aout_FormatNbChannels( &p_aout->output.output ),
  293.                                p_aout->output.output.i_rate, VLC_FALSE )
  294.             != VLC_SUCCESS )
  295.         {
  296.             msg_Err( p_aout, "cannot open directx audio device" );
  297.             free( p_aout->output.p_sys );
  298.             return VLC_EGENERIC;
  299.         }
  300.         /* Calculate the frame size in bytes */
  301.         p_aout->output.i_nb_samples = FRAME_SIZE;
  302.         aout_FormatPrepare( &p_aout->output.output );
  303.         p_aout->output.p_sys->i_frame_size =
  304.             FRAME_SIZE * p_aout->output.output.i_bytes_per_frame;
  305.         aout_VolumeSoftInit( p_aout );
  306.     }
  307.     /* then launch the notification thread */
  308.     msg_Dbg( p_aout, "creating DirectSoundThread" );
  309.     if( vlc_thread_create( p_aout->output.p_sys->p_notif,
  310.                            "DirectSound Notification Thread",
  311.                            DirectSoundThread,
  312.                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
  313.     {
  314.         msg_Err( p_aout, "cannot create DirectSoundThread" );
  315.         goto error;
  316.     }
  317.     vlc_object_attach( p_aout->output.p_sys->p_notif, p_aout );
  318.     return VLC_SUCCESS;
  319.  error:
  320.     CloseAudio( VLC_OBJECT(p_aout) );
  321.     return VLC_EGENERIC;
  322. }
  323. /*****************************************************************************
  324.  * Probe: probe the audio device for available formats and channels
  325.  *****************************************************************************/
  326. static void Probe( aout_instance_t * p_aout )
  327. {
  328.     vlc_value_t val, text;
  329.     int i_format;
  330.     unsigned int i_physical_channels;
  331.     DWORD ui_speaker_config;
  332.     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  333.     text.psz_string = _("Audio Device");
  334.     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
  335.     /* Test for 5.1 support */
  336.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
  337.                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
  338.                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
  339.     if( p_aout->output.output.i_physical_channels == i_physical_channels )
  340.     {
  341.         if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 6,
  342.                                p_aout->output.output.i_rate, VLC_TRUE )
  343.             == VLC_SUCCESS )
  344.         {
  345.             val.i_int = AOUT_VAR_5_1;
  346.             text.psz_string = N_("5.1");
  347.             var_Change( p_aout, "audio-device",
  348.                         VLC_VAR_ADDCHOICE, &val, &text );
  349.             msg_Dbg( p_aout, "device supports 5.1 channels" );
  350.         }
  351.     }
  352.     /* Test for 3 Front 2 Rear support */
  353.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
  354.                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
  355.                           AOUT_CHAN_REARRIGHT;
  356.     if( p_aout->output.output.i_physical_channels == i_physical_channels )
  357.     {
  358.         if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 5,
  359.                                p_aout->output.output.i_rate, VLC_TRUE )
  360.             == VLC_SUCCESS )
  361.         {
  362.             val.i_int = AOUT_VAR_3F2R;
  363.             text.psz_string = N_("3 Front 2 Rear");
  364.             var_Change( p_aout, "audio-device",
  365.                         VLC_VAR_ADDCHOICE, &val, &text );
  366.             msg_Dbg( p_aout, "device supports 5 channels" );
  367.         }
  368.     }
  369.     /* Test for 2 Front 2 Rear support */
  370.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
  371.                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  372.     if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
  373.         == i_physical_channels )
  374.     {
  375.         if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 4,
  376.                                p_aout->output.output.i_rate, VLC_TRUE )
  377.             == VLC_SUCCESS )
  378.         {
  379.             val.i_int = AOUT_VAR_2F2R;
  380.             text.psz_string = N_("2 Front 2 Rear");
  381.             var_Change( p_aout, "audio-device",
  382.                         VLC_VAR_ADDCHOICE, &val, &text );
  383.             msg_Dbg( p_aout, "device supports 4 channels" );
  384.         }
  385.     }
  386.     /* Test for stereo support */
  387.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  388.     if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 2,
  389.                            p_aout->output.output.i_rate, VLC_TRUE )
  390.         == VLC_SUCCESS )
  391.     {
  392.         val.i_int = AOUT_VAR_STEREO;
  393.         text.psz_string = N_("Stereo");
  394.         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
  395.         var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
  396.         msg_Dbg( p_aout, "device supports 2 channels" );
  397.     }
  398.     /* Test for mono support */
  399.     i_physical_channels = AOUT_CHAN_CENTER;
  400.     if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 1,
  401.                            p_aout->output.output.i_rate, VLC_TRUE )
  402.         == VLC_SUCCESS )
  403.     {
  404.         val.i_int = AOUT_VAR_MONO;
  405.         text.psz_string = N_("Mono");
  406.         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
  407.         msg_Dbg( p_aout, "device supports 1 channel" );
  408.     }
  409.     /* Check the speaker configuration to determine which channel config should
  410.      * be the default */
  411.     if FAILED( IDirectSound_GetSpeakerConfig( p_aout->output.p_sys->p_dsobject,
  412.                                               &ui_speaker_config ) )
  413.     {
  414.         ui_speaker_config = DSSPEAKER_STEREO;
  415.     }
  416.     switch( DSSPEAKER_CONFIG(ui_speaker_config) )
  417.     {
  418.     case DSSPEAKER_5POINT1:
  419.         val.i_int = AOUT_VAR_5_1;
  420.         break;
  421.     case DSSPEAKER_QUAD:
  422.         val.i_int = AOUT_VAR_2F2R;
  423.         break;
  424. #if 0 /* Lots of people just get their settings wrong and complain that
  425.        * this is a problem with VLC so just don't ever set mono by default. */
  426.     case DSSPEAKER_MONO:
  427.         val.i_int = AOUT_VAR_MONO;
  428.         break;
  429. #endif
  430.     case DSSPEAKER_SURROUND:
  431.     case DSSPEAKER_STEREO:
  432.     default:
  433.         val.i_int = AOUT_VAR_STEREO;
  434.         break;
  435.     }
  436.     var_Set( p_aout, "audio-device", val );
  437.     /* Test for SPDIF support */
  438.     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
  439.     {
  440.         if( CreateDSBuffer( p_aout, VLC_FOURCC('s','p','d','i'),
  441.                             p_aout->output.output.i_physical_channels,
  442.                             aout_FormatNbChannels( &p_aout->output.output ),
  443.                             p_aout->output.output.i_rate,
  444.                             AOUT_SPDIF_SIZE, VLC_TRUE )
  445.             == VLC_SUCCESS )
  446.         {
  447.             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
  448.             val.i_int = AOUT_VAR_SPDIF;
  449.             text.psz_string = N_("A/52 over S/PDIF");
  450.             var_Change( p_aout, "audio-device",
  451.                         VLC_VAR_ADDCHOICE, &val, &text );
  452.             if( config_GetInt( p_aout, "spdif" ) )
  453.                 var_Set( p_aout, "audio-device", val );
  454.         }
  455.     }
  456.     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
  457.     if( val.i_int <= 0 )
  458.     {
  459.         /* Probe() has failed. */
  460.         var_Destroy( p_aout, "audio-device" );
  461.         return;
  462.     }
  463.     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
  464.     val.b_bool = VLC_TRUE;
  465.     var_Set( p_aout, "intf-change", val );
  466. }
  467. /*****************************************************************************
  468.  * Play: we'll start playing the directsound buffer here because at least here
  469.  *       we know the first buffer has been put in the aout fifo and we also
  470.  *       know its date.
  471.  *****************************************************************************/
  472. static void Play( aout_instance_t *p_aout )
  473. {
  474.     if( !p_aout->output.p_sys->b_playing )
  475.     {
  476.         aout_buffer_t *p_buffer;
  477.         p_aout->output.p_sys->b_playing = 1;
  478.         /* get the playing date of the first aout buffer */
  479.         p_aout->output.p_sys->p_notif->start_date =
  480.             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
  481.         /* fill in the first samples */
  482.         p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
  483.         FillBuffer( p_aout, 0, p_buffer );
  484.         /* wake up the audio output thread */
  485.         SetEvent( p_aout->output.p_sys->p_notif->p_events[0].hEventNotify );
  486.     }
  487. }
  488. /*****************************************************************************
  489.  * CloseAudio: close the audio device
  490.  *****************************************************************************/
  491. static void CloseAudio( vlc_object_t *p_this )
  492. {
  493.     aout_instance_t * p_aout = (aout_instance_t *)p_this;
  494.     aout_sys_t *p_sys = p_aout->output.p_sys;
  495.     msg_Dbg( p_aout, "CloseAudio" );
  496.     /* kill the position notification thread, if any */
  497.     if( p_sys->p_notif )
  498.     {
  499.         vlc_object_detach( p_sys->p_notif );
  500.         if( p_sys->p_notif->b_thread )
  501.         {
  502.             p_sys->p_notif->b_die = 1;
  503.             if( !p_sys->b_playing )
  504.                 /* wake up the audio thread */
  505.                 SetEvent( p_sys->p_notif->p_events[0].hEventNotify );
  506.             vlc_thread_join( p_sys->p_notif );
  507.         }
  508.         vlc_object_destroy( p_sys->p_notif );
  509.     }
  510.     /* release the secondary buffer */
  511.     DestroyDSBuffer( p_aout );
  512.     /* finally release the DirectSound object */
  513.     if( p_sys->p_dsobject ) IDirectSound_Release( p_sys->p_dsobject );
  514.     
  515.     /* free DSOUND.DLL */
  516.     if( p_sys->hdsound_dll ) FreeLibrary( p_sys->hdsound_dll );
  517.     free( p_sys );
  518. }
  519. /*****************************************************************************
  520.  * InitDirectSound: handle all the gory details of DirectSound initialisation
  521.  *****************************************************************************/
  522. static int InitDirectSound( aout_instance_t *p_aout )
  523. {
  524.     HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
  525.     p_aout->output.p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL");
  526.     if( p_aout->output.p_sys->hdsound_dll == NULL )
  527.     {
  528.         msg_Warn( p_aout, "cannot open DSOUND.DLL" );
  529.         goto error;
  530.     }
  531.     OurDirectSoundCreate = (void *)GetProcAddress(
  532.                                            p_aout->output.p_sys->hdsound_dll,
  533.                                            "DirectSoundCreate" );
  534.     if( OurDirectSoundCreate == NULL )
  535.     {
  536.         msg_Warn( p_aout, "GetProcAddress FAILED" );
  537.         goto error;
  538.     }
  539.     /* Create the direct sound object */
  540.     if FAILED( OurDirectSoundCreate( NULL, &p_aout->output.p_sys->p_dsobject,
  541.                                      NULL ) )
  542.     {
  543.         msg_Warn( p_aout, "cannot create a direct sound device" );
  544.         goto error;
  545.     }
  546.     /* Set DirectSound Cooperative level, ie what control we want over Windows
  547.      * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
  548.      * settings of the primary buffer, but also that only the sound of our
  549.      * application will be hearable when it will have the focus.
  550.      * !!! (this is not really working as intended yet because to set the
  551.      * cooperative level you need the window handle of your application, and
  552.      * I don't know of any easy way to get it. Especially since we might play
  553.      * sound without any video, and so what window handle should we use ???
  554.      * The hack for now is to use the Desktop window handle - it seems to be
  555.      * working */
  556.     if( IDirectSound_SetCooperativeLevel( p_aout->output.p_sys->p_dsobject,
  557.                                           GetDesktopWindow(),
  558.                                           DSSCL_EXCLUSIVE) )
  559.     {
  560.         msg_Warn( p_aout, "cannot set direct sound cooperative level" );
  561.     }
  562.     return VLC_SUCCESS;
  563.  error:
  564.     p_aout->output.p_sys->p_dsobject = NULL;
  565.     if( p_aout->output.p_sys->hdsound_dll )
  566.     {
  567.         FreeLibrary( p_aout->output.p_sys->hdsound_dll );
  568.         p_aout->output.p_sys->hdsound_dll = NULL;
  569.     }
  570.     return VLC_EGENERIC;
  571. }
  572. /*****************************************************************************
  573.  * CreateDSBuffer: Creates a direct sound buffer of the required format.
  574.  *****************************************************************************
  575.  * This function creates the buffer we'll use to play audio.
  576.  * In DirectSound there are two kinds of buffers:
  577.  * - the primary buffer: which is the actual buffer that the soundcard plays
  578.  * - the secondary buffer(s): these buffers are the one actually used by
  579.  *    applications and DirectSound takes care of mixing them into the primary.
  580.  *
  581.  * Once you create a secondary buffer, you cannot change its format anymore so
  582.  * you have to release the current one and create another.
  583.  *****************************************************************************/
  584. static int CreateDSBuffer( aout_instance_t *p_aout, int i_format,
  585.                            int i_channels, int i_nb_channels, int i_rate,
  586.                            int i_bytes_per_frame, vlc_bool_t b_probe )
  587. {
  588.     WAVEFORMATEXTENSIBLE waveformat;
  589.     DSBUFFERDESC         dsbdesc;
  590.     unsigned int         i;
  591.     /* First set the sound buffer format */
  592.     waveformat.dwChannelMask = 0;
  593.     for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
  594.     {
  595.         if( i_channels & pi_channels_src[i] )
  596.             waveformat.dwChannelMask |= pi_channels_in[i];
  597.     }
  598.     switch( i_format )
  599.     {
  600.     case VLC_FOURCC('s','p','d','i'):
  601.         i_nb_channels = 2;
  602.         /* To prevent channel re-ordering */
  603.         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
  604.         waveformat.Format.wBitsPerSample = 16;
  605.         waveformat.Samples.wValidBitsPerSample =
  606.             waveformat.Format.wBitsPerSample;
  607.         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
  608.         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
  609.         break;
  610.     case VLC_FOURCC('f','l','3','2'):
  611.         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
  612.         waveformat.Samples.wValidBitsPerSample =
  613.             waveformat.Format.wBitsPerSample;
  614.         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
  615.         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  616.         break;
  617.     case VLC_FOURCC('s','1','6','l'):
  618.         waveformat.Format.wBitsPerSample = 16;
  619.         waveformat.Samples.wValidBitsPerSample =
  620.             waveformat.Format.wBitsPerSample;
  621.         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
  622.         waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
  623.         break;
  624.     }
  625.     waveformat.Format.nChannels = i_nb_channels;
  626.     waveformat.Format.nSamplesPerSec = i_rate;
  627.     waveformat.Format.nBlockAlign =
  628.         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
  629.     waveformat.Format.nAvgBytesPerSec =
  630.         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
  631.     p_aout->output.p_sys->i_bits_per_sample = waveformat.Format.wBitsPerSample;
  632.     p_aout->output.p_sys->i_channels = i_nb_channels;
  633.     /* Then fill in the direct sound descriptor */
  634.     memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  635.     dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  636.     dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
  637.                     | DSBCAPS_CTRLPOSITIONNOTIFY     /* We need notification */
  638.                     | DSBCAPS_GLOBALFOCUS;      /* Allows background playing */
  639.     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
  640.     if( i_nb_channels <= 2 )
  641.     {
  642.         waveformat.Format.cbSize = 0;
  643.     }
  644.     else
  645.     {
  646.         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  647.         waveformat.Format.cbSize =
  648.             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  649.         /* Needed for 5.1 on emu101k */
  650.         dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
  651.     }
  652.     dsbdesc.dwBufferBytes = FRAMES_NUM * i_bytes_per_frame;   /* buffer size */
  653.     dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;
  654.     if FAILED( IDirectSound_CreateSoundBuffer(
  655.                    p_aout->output.p_sys->p_dsobject, &dsbdesc,
  656.                    &p_aout->output.p_sys->p_dsbuffer, NULL) )
  657.     {
  658.         if( dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE )
  659.         {
  660.             /* Try without DSBCAPS_LOCHARDWARE */
  661.             dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
  662.             if FAILED( IDirectSound_CreateSoundBuffer(
  663.                    p_aout->output.p_sys->p_dsobject, &dsbdesc,
  664.                    &p_aout->output.p_sys->p_dsbuffer, NULL) )
  665.             {
  666.                 return VLC_EGENERIC;
  667.             }
  668.             if( !b_probe )
  669.                 msg_Dbg( p_aout, "couldn't use hardware sound buffer" );
  670.         }
  671.         else
  672.         {
  673.             return VLC_EGENERIC;
  674.         }
  675.     }
  676.     /* Stop here if we were just probing */
  677.     if( b_probe )
  678.     {
  679.         IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );
  680.         p_aout->output.p_sys->p_dsbuffer = NULL;
  681.         return VLC_SUCCESS;
  682.     }
  683.     /* Backup the size of a frame */
  684.     p_aout->output.p_sys->p_notif->i_frame_size = i_bytes_per_frame;
  685.     /* Now the secondary buffer is created, we need to setup its position
  686.      * notification */
  687.     for( i = 0; i < FRAMES_NUM; i++ )
  688.     {
  689.         p_aout->output.p_sys->p_notif->p_events[i].dwOffset = i *
  690.             p_aout->output.p_sys->p_notif->i_frame_size;
  691.         p_aout->output.p_sys->p_notif->i_frame_status[i] = FRAME_EMPTY;
  692.     }
  693.     /* Get the IDirectSoundNotify interface */
  694.     if FAILED( IDirectSoundBuffer_QueryInterface(
  695.                                 p_aout->output.p_sys->p_dsbuffer,
  696.                                 &IID_IDirectSoundNotify,
  697.                                 (LPVOID *)&p_aout->output.p_sys->p_dsnotify ) )
  698.     {
  699.         msg_Err( p_aout, "cannot get IDirectSoundNotify interface" );
  700.         goto error;
  701.     }
  702.     if FAILED( IDirectSoundNotify_SetNotificationPositions(
  703.                                     p_aout->output.p_sys->p_dsnotify,
  704.                                     FRAMES_NUM,
  705.                                     p_aout->output.p_sys->p_notif->p_events ) )
  706.     {
  707.         msg_Err( p_aout, "cannot set position notification" );
  708.         goto error;
  709.     }
  710.     p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask;
  711.     p_aout->output.p_sys->b_chan_reorder =
  712.         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
  713.                                   waveformat.dwChannelMask, i_nb_channels,
  714.                                   p_aout->output.p_sys->pi_chan_table );
  715.     if( p_aout->output.p_sys->b_chan_reorder )
  716.     {
  717.         msg_Dbg( p_aout, "channel reordering needed" );
  718.     }
  719.     return VLC_SUCCESS;
  720.  error:
  721.     DestroyDSBuffer( p_aout );
  722.     return VLC_EGENERIC;
  723. }
  724. /*****************************************************************************
  725.  * CreateDSBufferPCM: creates a PCM direct sound buffer.
  726.  *****************************************************************************
  727.  * We first try to create a WAVE_FORMAT_IEEE_FLOAT buffer if supported by
  728.  * the hardware, otherwise we create a WAVE_FORMAT_PCM buffer.
  729.  ****************************************************************************/
  730. static int CreateDSBufferPCM( aout_instance_t *p_aout, int *i_format,
  731.                               int i_channels, int i_nb_channels, int i_rate,
  732.                               vlc_bool_t b_probe )
  733. {
  734.     /* Float32 audio samples are not supported for 5.1 output on the emu101k */
  735.     if( i_nb_channels > 2 ||
  736.         CreateDSBuffer( p_aout, VLC_FOURCC('f','l','3','2'),
  737.                         i_channels, i_nb_channels, i_rate,
  738.                         FRAME_SIZE * 4 * i_nb_channels, b_probe )
  739.         != VLC_SUCCESS )
  740.     {
  741.         if ( CreateDSBuffer( p_aout, VLC_FOURCC('s','1','6','l'),
  742.                              i_channels, i_nb_channels, i_rate,
  743.                              FRAME_SIZE * 2 * i_nb_channels, b_probe )
  744.              != VLC_SUCCESS )
  745.         {
  746.             return VLC_EGENERIC;
  747.         }
  748.         else
  749.         {
  750.             *i_format = VLC_FOURCC('s','1','6','l');
  751.             return VLC_SUCCESS;
  752.         }
  753.     }
  754.     else
  755.     {
  756.         *i_format = VLC_FOURCC('f','l','3','2');
  757.         return VLC_SUCCESS;
  758.     }
  759. }
  760. /*****************************************************************************
  761.  * DestroyDSBuffer
  762.  *****************************************************************************
  763.  * This function destroys the secondary buffer.
  764.  *****************************************************************************/
  765. static void DestroyDSBuffer( aout_instance_t *p_aout )
  766. {
  767.     if( p_aout->output.p_sys->p_dsnotify )
  768.     {
  769.         IDirectSoundNotify_Release( p_aout->output.p_sys->p_dsnotify );
  770.         p_aout->output.p_sys->p_dsnotify = NULL;
  771.     }
  772.     if( p_aout->output.p_sys->p_dsbuffer )
  773.     {
  774.         IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );
  775.         p_aout->output.p_sys->p_dsbuffer = NULL;
  776.     }
  777. }
  778. /*****************************************************************************
  779.  * FillBuffer: Fill in one of the direct sound frame buffers.
  780.  *****************************************************************************
  781.  * Returns VLC_SUCCESS on success.
  782.  *****************************************************************************/
  783. static int FillBuffer( aout_instance_t *p_aout, int i_frame,
  784.                        aout_buffer_t *p_buffer )
  785. {
  786.     notification_thread_t *p_notif = p_aout->output.p_sys->p_notif;
  787.     aout_sys_t *p_sys = p_aout->output.p_sys;
  788.     void *p_write_position, *p_wrap_around;
  789.     long l_bytes1, l_bytes2;
  790.     HRESULT dsresult;
  791.     /* Before copying anything, we have to lock the buffer */
  792.     dsresult = IDirectSoundBuffer_Lock(
  793.                 p_sys->p_dsbuffer,                              /* DS buffer */
  794.                 i_frame * p_notif->i_frame_size,             /* Start offset */
  795.                 p_notif->i_frame_size,                    /* Number of bytes */
  796.                 &p_write_position,                  /* Address of lock start */
  797.                 &l_bytes1,       /* Count of bytes locked before wrap around */
  798.                 &p_wrap_around,            /* Buffer adress (if wrap around) */
  799.                 &l_bytes2,               /* Count of bytes after wrap around */
  800.                 0 );                                                /* Flags */
  801.     if( dsresult == DSERR_BUFFERLOST )
  802.     {
  803.         IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );
  804.         dsresult = IDirectSoundBuffer_Lock(
  805.                                p_sys->p_dsbuffer,
  806.                                i_frame * p_notif->i_frame_size,
  807.                                p_notif->i_frame_size,
  808.                                &p_write_position,
  809.                                &l_bytes1,
  810.                                &p_wrap_around,
  811.                                &l_bytes2,
  812.                                0 );
  813.     }
  814.     if( dsresult != DS_OK )
  815.     {
  816.         msg_Warn( p_notif, "cannot lock buffer" );
  817.         if( p_buffer ) aout_BufferFree( p_buffer );
  818.         return VLC_EGENERIC;
  819.     }
  820.     if( p_buffer == NULL )
  821.     {
  822.         memset( p_write_position, 0, l_bytes1 );
  823.     }
  824.     else
  825.     {
  826.         if( p_sys->b_chan_reorder )
  827.         {
  828.             /* Do the channel reordering here */
  829.             aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes,
  830.                                  p_sys->i_channels, p_sys->pi_chan_table,
  831.                                  p_sys->i_bits_per_sample );
  832.         }
  833.         p_aout->p_vlc->pf_memcpy( p_write_position, p_buffer->p_buffer,
  834.                                   l_bytes1 );
  835.         aout_BufferFree( p_buffer );
  836.     }
  837.     /* Now the data has been copied, unlock the buffer */
  838.     IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,
  839.                                p_wrap_around, l_bytes2 );
  840.     return VLC_SUCCESS;
  841. }
  842. /*****************************************************************************
  843.  * DirectSoundThread: this thread will capture play notification events. 
  844.  *****************************************************************************
  845.  * We use this thread to emulate a callback mechanism. The thread probes for
  846.  * event notification and fills up the DS secondary buffer when needed.
  847.  *****************************************************************************/
  848. static void DirectSoundThread( notification_thread_t *p_notif )
  849. {
  850.     HANDLE  notification_events[FRAMES_NUM];
  851.     HRESULT dsresult;
  852.     aout_instance_t *p_aout = p_notif->p_aout;
  853.     int i, i_which_frame, i_last_frame, i_next_frame;
  854.     mtime_t mtime;
  855.     vlc_bool_t b_sleek;
  856.     for( i = 0; i < FRAMES_NUM; i++ )
  857.         notification_events[i] = p_notif->p_events[i].hEventNotify;
  858.     /* We don't want any resampling when using S/PDIF output */
  859.     b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
  860.     /* Tell the main thread that we are ready */
  861.     vlc_thread_ready( p_notif );
  862.     msg_Dbg( p_notif, "DirectSoundThread ready" );
  863.     /* Wait here until Play() is called */
  864.     WaitForSingleObject( notification_events[0], INFINITE );
  865.     if( !p_notif->b_die )
  866.     {
  867.         mwait( p_notif->start_date - AOUT_PTS_TOLERANCE / 2 );
  868.         /* start playing the buffer */
  869.         dsresult = IDirectSoundBuffer_Play( p_aout->output.p_sys->p_dsbuffer,
  870.                                         0,                         /* Unused */
  871.                                         0,                         /* Unused */
  872.                                         DSBPLAY_LOOPING );          /* Flags */
  873.         if( dsresult == DSERR_BUFFERLOST )
  874.         {
  875.             IDirectSoundBuffer_Restore( p_aout->output.p_sys->p_dsbuffer );
  876.             dsresult = IDirectSoundBuffer_Play(
  877.                                             p_aout->output.p_sys->p_dsbuffer,
  878.                                             0,                     /* Unused */
  879.                                             0,                     /* Unused */
  880.                                             DSBPLAY_LOOPING );      /* Flags */
  881.         }
  882.         if( dsresult != DS_OK )
  883.         {
  884.             msg_Err( p_aout, "cannot start playing buffer" );
  885.         }
  886.     }
  887.     while( !p_notif->b_die )
  888.     {
  889.         aout_buffer_t *p_buffer;
  890.         long l_latency;
  891.         /* wait for the position notification */
  892.         i_which_frame = WaitForMultipleObjects( FRAMES_NUM,
  893.                                                 notification_events, 0,
  894.                                                 INFINITE ) - WAIT_OBJECT_0;
  895.         if( p_notif->b_die )
  896.             break;
  897.         mtime = mdate();
  898.         /* We take into account the current latency */
  899.         if SUCCEEDED( IDirectSoundBuffer_GetCurrentPosition(
  900.                         p_aout->output.p_sys->p_dsbuffer,
  901.                         &l_latency, NULL ) )
  902.         {
  903.             if( l_latency > (i_which_frame * FRAME_SIZE)
  904.                   && l_latency < ((i_which_frame+1) * FRAME_SIZE) )
  905.             {
  906.                 l_latency = - ( l_latency /
  907.                                 p_aout->output.output.i_bytes_per_frame %
  908.                                 FRAME_SIZE );
  909.             }
  910.             else
  911.             {
  912.                 l_latency = FRAME_SIZE - ( l_latency /
  913.                                       p_aout->output.output.i_bytes_per_frame %
  914.                                       FRAME_SIZE );
  915.             }
  916.         }
  917.         else
  918.         {
  919.             l_latency = 0;
  920.         }
  921.         /* Mark last frame as empty */
  922.         i_last_frame = (i_which_frame + FRAMES_NUM -1) % FRAMES_NUM;
  923.         i_next_frame = (i_which_frame + 1) % FRAMES_NUM;
  924.         p_notif->i_frame_status[i_last_frame] = FRAME_EMPTY;
  925.         /* Try to fill in as many frame buffers as possible */
  926.         for( i = i_next_frame; (i % FRAMES_NUM) != i_which_frame; i++ )
  927.         {
  928.             /* Check if frame buf is already filled */
  929.             if( p_notif->i_frame_status[i % FRAMES_NUM] == FRAME_QUEUED )
  930.                 continue;
  931.             p_buffer = aout_OutputNextBuffer( p_aout,
  932.                 mtime + 1000000 / p_aout->output.output.i_rate *
  933.                 ((i - i_next_frame + 1) * FRAME_SIZE + l_latency), b_sleek );
  934.             /* If there is no audio data available and we have some buffered
  935.              * already, then just wait for the next time */
  936.             if( !p_buffer && (i != i_next_frame) )
  937.             {
  938.                 //msg_Err( p_aout, "only %i frame buffers filled!",
  939.                 //         i - i_next_frame );
  940.                 break;
  941.             }
  942.             if( FillBuffer( p_aout, (i%FRAMES_NUM), p_buffer )
  943.                 != VLC_SUCCESS )
  944.                 break;
  945.             /* Mark the frame buffer as QUEUED */
  946.             p_notif->i_frame_status[i%FRAMES_NUM] = FRAME_QUEUED;
  947.         }
  948.     }
  949.     /* make sure the buffer isn't playing */
  950.     IDirectSoundBuffer_Stop( p_aout->output.p_sys->p_dsbuffer );
  951.     /* free the events */
  952.     for( i = 0; i < FRAMES_NUM; i++ )
  953.         CloseHandle( notification_events[i] );
  954.     msg_Dbg( p_notif, "DirectSoundThread exiting" );
  955. }