waveout.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:44k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * waveout.c : Windows waveOut plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2001 the VideoLAN team
  5.  * $Id: 8bea3e34959b44a42524d3466b5b99a04fec0439 $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_aout.h>
  32. #include <vlc_charset.h>
  33. #include <windows.h>
  34. #include <mmsystem.h>
  35. #define FRAME_SIZE 4096              /* The size is in samples, not in bytes */
  36. #define FRAMES_NUM 8
  37. /*****************************************************************************
  38.  * Useful macros
  39.  *****************************************************************************/
  40. #ifdef UNDER_CE
  41. #   define DWORD_PTR DWORD
  42. #   ifdef waveOutGetDevCaps
  43. #       undef waveOutGetDevCaps
  44.         MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
  45. #   endif
  46. #endif
  47. #ifndef WAVE_FORMAT_IEEE_FLOAT
  48. #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
  49. #endif
  50. #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
  51. #   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
  52. #endif
  53. #ifndef WAVE_FORMAT_EXTENSIBLE
  54. #define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
  55. #endif
  56. #ifndef SPEAKER_FRONT_LEFT
  57. #   define SPEAKER_FRONT_LEFT             0x1
  58. #   define SPEAKER_FRONT_RIGHT            0x2
  59. #   define SPEAKER_FRONT_CENTER           0x4
  60. #   define SPEAKER_LOW_FREQUENCY          0x8
  61. #   define SPEAKER_BACK_LEFT              0x10
  62. #   define SPEAKER_BACK_RIGHT             0x20
  63. #   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
  64. #   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
  65. #   define SPEAKER_BACK_CENTER            0x100
  66. #   define SPEAKER_SIDE_LEFT              0x200
  67. #   define SPEAKER_SIDE_RIGHT             0x400
  68. #   define SPEAKER_TOP_CENTER             0x800
  69. #   define SPEAKER_TOP_FRONT_LEFT         0x1000
  70. #   define SPEAKER_TOP_FRONT_CENTER       0x2000
  71. #   define SPEAKER_TOP_FRONT_RIGHT        0x4000
  72. #   define SPEAKER_TOP_BACK_LEFT          0x8000
  73. #   define SPEAKER_TOP_BACK_CENTER        0x10000
  74. #   define SPEAKER_TOP_BACK_RIGHT         0x20000
  75. #   define SPEAKER_RESERVED               0x80000000
  76. #endif
  77. #ifndef _WAVEFORMATEXTENSIBLE_
  78. typedef struct {
  79.     WAVEFORMATEX    Format;
  80.     union {
  81.         WORD wValidBitsPerSample;       /* bits of precision  */
  82.         WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
  83.         WORD wReserved;                 /* If neither applies, set to zero. */
  84.     } Samples;
  85.     DWORD           dwChannelMask;      /* which channels are */
  86.                                         /* present in stream  */
  87.     GUID            SubFormat;
  88. } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
  89. #endif
  90. static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
  91. static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
  92. static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
  93. /*****************************************************************************
  94.  * Local prototypes
  95.  *****************************************************************************/
  96. static int  Open         ( vlc_object_t * );
  97. static void Close        ( vlc_object_t * );
  98. static void Play         ( aout_instance_t * );
  99. /*****************************************************************************
  100.  * notification_thread_t: waveOut event thread
  101.  *****************************************************************************/
  102. typedef struct notification_thread_t
  103. {
  104.     VLC_COMMON_MEMBERS
  105.     aout_instance_t *p_aout;
  106. } notification_thread_t;
  107. /* local functions */
  108. static void Probe        ( aout_instance_t * );
  109. static int OpenWaveOut   ( aout_instance_t *, uint32_t,
  110.                            int, int, int, int, bool );
  111. static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
  112.                            int*, int, int, int, bool );
  113. static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
  114.                            aout_buffer_t *, bool );
  115. static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
  116. static void* WaveOutThread( vlc_object_t * );
  117. static int VolumeInfos( aout_instance_t *, audio_volume_t * );
  118. static int VolumeGet( aout_instance_t *, audio_volume_t * );
  119. static int VolumeSet( aout_instance_t *, audio_volume_t );
  120. static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
  121. static int ReloadWaveoutDevices( vlc_object_t *, char const *,
  122.                                 vlc_value_t, vlc_value_t, void * );
  123. static uint32_t findDeviceID(char *);
  124. static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
  125. static const char *const ppsz_adev[] = { "wavemapper", };
  126. static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
  127. /*****************************************************************************
  128.  * Module descriptor
  129.  *****************************************************************************/
  130. #define FLOAT_TEXT N_("Use float32 output")
  131. #define FLOAT_LONGTEXT N_( 
  132.     "The option allows you to enable or disable the high-quality float32 " 
  133.     "audio output mode (which is not well supported by some soundcards)." )
  134. #define DEVICE_TEXT N_("Select Audio Device")
  135. #define DEVICE_LONG N_("Select special Audio device, or let windows "
  136.                        "decide (default), change needs VLC restart "
  137.                        "to apply.")
  138. #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
  139. vlc_module_begin ()
  140.     set_shortname( "WaveOut" )
  141.     set_description( N_("Win32 waveOut extension output") )
  142.     set_capability( "audio output", 50 )
  143.     set_category( CAT_AUDIO )
  144.     set_subcategory( SUBCAT_AUDIO_AOUT )
  145.     add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, true )
  146.     add_string( "waveout-audio-device", "wavemapper", NULL,
  147.                  DEVICE_TEXT, DEVICE_LONG, false )
  148.        add_deprecated_alias( "waveout-dev" )   /* deprecated since 0.9.3 */
  149.        change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
  150.        change_need_restart ()
  151.        change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
  152.     set_callbacks( Open, Close )
  153. vlc_module_end ()
  154. /*****************************************************************************
  155.  * aout_sys_t: waveOut audio output method descriptor
  156.  *****************************************************************************
  157.  * This structure is part of the audio output thread descriptor.
  158.  * It describes the waveOut specific properties of an audio device.
  159.  *****************************************************************************/
  160. struct aout_sys_t
  161. {
  162.     uint32_t i_wave_device_id;               /* ID of selected output device */
  163.     HWAVEOUT h_waveout;                        /* handle to waveout instance */
  164.     WAVEFORMATEXTENSIBLE waveformat;                         /* audio format */
  165.     WAVEHDR waveheader[FRAMES_NUM];
  166.     notification_thread_t *p_notif;                      /* WaveOutThread id */
  167.     HANDLE event;
  168.     HANDLE new_buffer_event;
  169.     // rental from alsa.c to synchronize startup of audiothread
  170.     int b_playing;                                         /* playing status */
  171.     mtime_t start_date;
  172.     int i_repeat_counter;
  173.     int i_buffer_size;
  174.     uint8_t *p_silence_buffer;              /* buffer we use to play silence */
  175.     bool b_chan_reorder;              /* do we need channel reordering */
  176.     int pi_chan_table[AOUT_CHAN_MAX];
  177. };
  178. static const uint32_t pi_channels_src[] =
  179.     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
  180.       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
  181.       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
  182.       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
  183. static const uint32_t pi_channels_in[] =
  184.     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
  185.       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
  186.       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, SPEAKER_BACK_CENTER,
  187.       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
  188. static const uint32_t pi_channels_out[] =
  189.     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
  190.       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
  191.       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
  192.       SPEAKER_BACK_CENTER,
  193.       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
  194. /*****************************************************************************
  195.  * Open: open the audio device
  196.  *****************************************************************************
  197.  * This function opens and setups Win32 waveOut
  198.  *****************************************************************************/
  199. static int Open( vlc_object_t *p_this )
  200. {
  201.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  202.     vlc_value_t val;
  203.     int i;
  204.     /* Allocate structure */
  205.     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
  206.     if( p_aout->output.p_sys == NULL )
  207.         return VLC_ENOMEM;
  208.     p_aout->output.pf_play = Play;
  209.     p_aout->b_die = false;
  210.     /*
  211.      initialize/update Device selection List
  212.     */
  213.     ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
  214.     /*
  215.       check for configured audio device!
  216.     */
  217.     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
  218.     p_aout->output.p_sys->i_wave_device_id =
  219.          findDeviceID( psz_waveout_dev );
  220.     if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
  221.     {
  222.        if(psz_waveout_dev &&
  223.           stricmp(psz_waveout_dev,"wavemapper"))
  224.        {
  225.            msg_Warn( p_aout, "configured audio device '%s' not available, "
  226.                          "use default instead", psz_waveout_dev );
  227.        }
  228.     }
  229.     free( psz_waveout_dev );
  230.     WAVEOUTCAPS waveoutcaps;
  231.     if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
  232.                           &waveoutcaps,
  233.                           sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
  234.     {
  235.       /* log debug some infos about driver, to know who to blame
  236.          if it doesn't work */
  237.         msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
  238.         msg_Dbg( p_aout, "Driver Version: %d.%d",
  239.                           (waveoutcaps.vDriverVersion>>8)&255,
  240.                           waveoutcaps.vDriverVersion & 255);
  241.         msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
  242.         msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
  243.     }
  244.     if( var_Type( p_aout, "audio-device" ) == 0 )
  245.     {
  246.         Probe( p_aout );
  247.     }
  248.     if( var_Get( p_aout, "audio-device", &val ) < 0 )
  249.     {
  250.         /* Probe() has failed. */
  251.         var_Destroy( p_aout, "waveout-audio-device");
  252.         free( p_aout->output.p_sys );
  253.         return VLC_EGENERIC;
  254.     }
  255.     /* Open the device */
  256.     if( val.i_int == AOUT_VAR_SPDIF )
  257.     {
  258.         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
  259.         if( OpenWaveOut( p_aout,
  260.                          p_aout->output.p_sys->i_wave_device_id,
  261.                          VLC_FOURCC('s','p','d','i'),
  262.                          p_aout->output.output.i_physical_channels,
  263.                          aout_FormatNbChannels( &p_aout->output.output ),
  264.                          p_aout->output.output.i_rate, false )
  265.             != VLC_SUCCESS )
  266.         {
  267.             msg_Err( p_aout, "cannot open waveout audio device" );
  268.             free( p_aout->output.p_sys );
  269.             return VLC_EGENERIC;
  270.         }
  271.         /* Calculate the frame size in bytes */
  272.         p_aout->output.i_nb_samples = A52_FRAME_NB;
  273.         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
  274.         p_aout->output.output.i_frame_length = A52_FRAME_NB;
  275.         p_aout->output.p_sys->i_buffer_size =
  276.             p_aout->output.output.i_bytes_per_frame;
  277.         aout_VolumeNoneInit( p_aout );
  278.     }
  279.     else
  280.     {
  281.         WAVEOUTCAPS wocaps;
  282.         switch( val.i_int )
  283.         {
  284.         case AOUT_VAR_5_1:
  285.             p_aout->output.output.i_physical_channels
  286.                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
  287.                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  288.                       | AOUT_CHAN_LFE;
  289.             break;
  290.         case AOUT_VAR_2F2R:
  291.             p_aout->output.output.i_physical_channels
  292.                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  293.                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  294.             break;
  295.         case AOUT_VAR_MONO:
  296.             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
  297.             break;
  298.         default:
  299.             p_aout->output.output.i_physical_channels
  300.                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  301.         }
  302.         if( OpenWaveOutPCM( p_aout,
  303.                             p_aout->output.p_sys->i_wave_device_id,
  304.                             &p_aout->output.output.i_format,
  305.                             p_aout->output.output.i_physical_channels,
  306.                             aout_FormatNbChannels( &p_aout->output.output ),
  307.                             p_aout->output.output.i_rate, false )
  308.             != VLC_SUCCESS )
  309.         {
  310.             msg_Err( p_aout, "cannot open waveout audio device" );
  311.             free( p_aout->output.p_sys );
  312.             return VLC_EGENERIC;
  313.         }
  314.         /* Calculate the frame size in bytes */
  315.         p_aout->output.i_nb_samples = FRAME_SIZE;
  316.         aout_FormatPrepare( &p_aout->output.output );
  317.         p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
  318.             p_aout->output.output.i_bytes_per_frame;
  319.         aout_VolumeSoftInit( p_aout );
  320.         /* Check for hardware volume support */
  321.         if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
  322.                                &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
  323.             wocaps.dwSupport & WAVECAPS_VOLUME )
  324.         {
  325.             DWORD i_dummy;
  326.             if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
  327.                 == MMSYSERR_NOERROR )
  328.             {
  329.                 p_aout->output.pf_volume_infos = VolumeInfos;
  330.                 p_aout->output.pf_volume_get = VolumeGet;
  331.                 p_aout->output.pf_volume_set = VolumeSet;
  332.             }
  333.         }
  334.     }
  335.     waveOutReset( p_aout->output.p_sys->h_waveout );
  336.     /* Allocate silence buffer */
  337.     p_aout->output.p_sys->p_silence_buffer =
  338.         malloc( p_aout->output.p_sys->i_buffer_size );
  339.     if( p_aout->output.p_sys->p_silence_buffer == NULL )
  340.     {
  341.         free( p_aout->output.p_sys );
  342.         return VLC_ENOMEM;
  343.     }
  344.     p_aout->output.p_sys->i_repeat_counter = 0;
  345.     /* Zero the buffer. WinCE doesn't have calloc(). */
  346.     memset( p_aout->output.p_sys->p_silence_buffer, 0,
  347.             p_aout->output.p_sys->i_buffer_size );
  348.     /* Now we need to setup our waveOut play notification structure */
  349.     p_aout->output.p_sys->p_notif =
  350.         vlc_object_create( p_aout, sizeof(notification_thread_t) );
  351.     p_aout->output.p_sys->p_notif->p_aout = p_aout;
  352.     p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
  353.     p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
  354.     /* define startpoint of playback on first call to play()
  355.       like alsa does (instead of playing a blank sample) */
  356.     p_aout->output.p_sys->b_playing = 0;
  357.     p_aout->output.p_sys->start_date = 0;
  358.     /* Then launch the notification thread */
  359.     if( vlc_thread_create( p_aout->output.p_sys->p_notif,
  360.                            "waveOut Notification Thread", WaveOutThread,
  361.                            VLC_THREAD_PRIORITY_OUTPUT ) )
  362.     {
  363.         msg_Err( p_aout, "cannot create WaveOutThread" );
  364.     }
  365.     /* We need to kick off the playback in order to have the callback properly
  366.      * working */
  367.     for( i = 0; i < FRAMES_NUM; i++ )
  368.     {
  369.         p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
  370.         p_aout->output.p_sys->waveheader[i].dwUser = 0;
  371.     }
  372.     return VLC_SUCCESS;
  373. }
  374. /*****************************************************************************
  375.  * Probe: probe the audio device for available formats and channels
  376.  *****************************************************************************/
  377. static void Probe( aout_instance_t * p_aout )
  378. {
  379.     vlc_value_t val, text;
  380.     int i_format;
  381.     unsigned int i_physical_channels;
  382.     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  383.     text.psz_string = _("Audio Device");
  384.     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
  385.     /* Test for 5.1 support */
  386.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
  387.                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
  388.                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
  389.     if( p_aout->output.output.i_physical_channels == i_physical_channels )
  390.     {
  391.         if( OpenWaveOutPCM( p_aout,
  392.                             p_aout->output.p_sys->i_wave_device_id,
  393.                             &i_format,
  394.                             i_physical_channels, 6,
  395.                             p_aout->output.output.i_rate, true )
  396.             == VLC_SUCCESS )
  397.         {
  398.             val.i_int = AOUT_VAR_5_1;
  399.             text.psz_string = (char *)_("5.1");
  400.             var_Change( p_aout, "audio-device",
  401.                         VLC_VAR_ADDCHOICE, &val, &text );
  402.             msg_Dbg( p_aout, "device supports 5.1 channels" );
  403.         }
  404.     }
  405.     /* Test for 2 Front 2 Rear support */
  406.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
  407.                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  408.     if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
  409.         == i_physical_channels )
  410.     {
  411.         if( OpenWaveOutPCM( p_aout,
  412.                             p_aout->output.p_sys->i_wave_device_id,
  413.                             &i_format,
  414.                             i_physical_channels, 4,
  415.                             p_aout->output.output.i_rate, true )
  416.             == VLC_SUCCESS )
  417.         {
  418.             val.i_int = AOUT_VAR_2F2R;
  419.             text.psz_string = (char *)_("2 Front 2 Rear");
  420.             var_Change( p_aout, "audio-device",
  421.                         VLC_VAR_ADDCHOICE, &val, &text );
  422.             msg_Dbg( p_aout, "device supports 4 channels" );
  423.         }
  424.     }
  425.     /* Test for stereo support */
  426.     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  427.     if( OpenWaveOutPCM( p_aout,
  428.                         p_aout->output.p_sys->i_wave_device_id,
  429.                         &i_format,
  430.                         i_physical_channels, 2,
  431.                         p_aout->output.output.i_rate, true )
  432.         == VLC_SUCCESS )
  433.     {
  434.         val.i_int = AOUT_VAR_STEREO;
  435.         text.psz_string = (char *)_("Stereo");
  436.         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
  437.         msg_Dbg( p_aout, "device supports 2 channels" );
  438.     }
  439.     /* Test for mono support */
  440.     i_physical_channels = AOUT_CHAN_CENTER;
  441.     if( OpenWaveOutPCM( p_aout,
  442.                         p_aout->output.p_sys->i_wave_device_id,
  443.                         &i_format,
  444.                         i_physical_channels, 1,
  445.                         p_aout->output.output.i_rate, true )
  446.         == VLC_SUCCESS )
  447.     {
  448.         val.i_int = AOUT_VAR_MONO;
  449.         text.psz_string = (char *)_("Mono");
  450.         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
  451.         msg_Dbg( p_aout, "device supports 1 channel" );
  452.     }
  453.     /* Test for SPDIF support */
  454.     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
  455.     {
  456.         if( OpenWaveOut( p_aout,
  457.                          p_aout->output.p_sys->i_wave_device_id,
  458.                          VLC_FOURCC('s','p','d','i'),
  459.                          p_aout->output.output.i_physical_channels,
  460.                          aout_FormatNbChannels( &p_aout->output.output ),
  461.                          p_aout->output.output.i_rate, true )
  462.             == VLC_SUCCESS )
  463.         {
  464.             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
  465.             val.i_int = AOUT_VAR_SPDIF;
  466.             text.psz_string = (char *)_("A/52 over S/PDIF");
  467.             var_Change( p_aout, "audio-device",
  468.                         VLC_VAR_ADDCHOICE, &val, &text );
  469.             if( config_GetInt( p_aout, "spdif" ) )
  470.                 var_Set( p_aout, "audio-device", val );
  471.         }
  472.     }
  473.     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
  474.     if( val.i_int <= 0 )
  475.     {
  476.         /* Probe() has failed. */
  477.         var_Destroy( p_aout, "audio-device" );
  478.         return;
  479.     }
  480.     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
  481.     var_SetBool( p_aout, "intf-change", true );
  482. }
  483. /*****************************************************************************
  484.  * Play: play a sound buffer
  485.  *****************************************************************************
  486.  * This doesn't actually play the buffer. This just stores the buffer so it
  487.  * can be played by the callback thread.
  488.  *****************************************************************************/
  489. static void Play( aout_instance_t *_p_aout )
  490. {
  491.     if( !_p_aout->output.p_sys->b_playing )
  492.     {
  493.         _p_aout->output.p_sys->b_playing = 1;
  494.         /* get the playing date of the first aout buffer */
  495.         _p_aout->output.p_sys->start_date =
  496.             aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
  497.         msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
  498.         /* wake up the audio output thread */
  499.         SetEvent( _p_aout->output.p_sys->event );
  500.     } else {
  501.         SetEvent( _p_aout->output.p_sys->new_buffer_event );
  502.     }
  503. }
  504. /*****************************************************************************
  505.  * Close: close the audio device
  506.  *****************************************************************************/
  507. static void Close( vlc_object_t *p_this )
  508. {
  509.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  510.     aout_sys_t *p_sys = p_aout->output.p_sys;
  511.     /* Before calling waveOutClose we must reset the device */
  512.     vlc_object_kill( p_aout );
  513.     /* wake up the audio thread, to recognize that p_aout died */
  514.     SetEvent( p_sys->event );
  515.     SetEvent( p_sys->new_buffer_event );
  516.     vlc_thread_join( p_sys->p_notif );
  517.     vlc_object_release( p_sys->p_notif );
  518.     /*
  519.       kill the real output then - when the feed thread
  520.       is surely terminated!
  521.       old code could be too early in case that "feeding"
  522.       was running on termination
  523.       at this point now its sure, that there will be no new
  524.       data send to the driver, and we can cancel the last
  525.       running playbuffers
  526.     */
  527.     MMRESULT result = waveOutReset( p_sys->h_waveout );
  528.     if(result != MMSYSERR_NOERROR)
  529.     {
  530.        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
  531.        /*
  532.         now we must wait, that all buffers are played
  533.         because cancel doesn't work in this case...
  534.        */
  535.        if(result == MMSYSERR_NOTSUPPORTED)
  536.        {
  537.            /*
  538.              clear currently played (done) buffers,
  539.              if returnvalue > 0 (means some buffer still playing)
  540.              wait for the driver event callback that one buffer
  541.              is finished with playing, and check again
  542.              the timeout of 5000ms is just, an emergency exit
  543.              of this loop, to avoid deadlock in case of other
  544.              (currently not known bugs, problems, errors cases?)
  545.            */
  546.            while(
  547.                  (WaveOutClearDoneBuffers( p_sys ) > 0)
  548.                  &&
  549.                  (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
  550.                 )
  551.            {
  552.                  msg_Dbg( p_aout, "Wait for waveout device...");
  553.            }
  554.        }
  555.     } else {
  556.         WaveOutClearDoneBuffers( p_sys );
  557.     }
  558.     /* now we can Close the device */
  559.     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
  560.     {
  561.         msg_Err( p_aout, "waveOutClose failed" );
  562.     }
  563.     /*
  564.       because so long, the waveout device is playing, the callback
  565.       could occur and need the events
  566.     */
  567.     CloseHandle( p_sys->event );
  568.     CloseHandle( p_sys->new_buffer_event);
  569.     free( p_sys->p_silence_buffer );
  570.     free( p_sys );
  571. }
  572. /*****************************************************************************
  573.  * OpenWaveOut: open the waveout sound device
  574.  ****************************************************************************/
  575. static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
  576.                         int i_channels, int i_nb_channels, int i_rate,
  577.                         bool b_probe )
  578. {
  579.     MMRESULT result;
  580.     unsigned int i;
  581.     /* Set sound format */
  582. #define waveformat p_aout->output.p_sys->waveformat
  583.     waveformat.dwChannelMask = 0;
  584.     for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
  585.     {
  586.         if( i_channels & pi_channels_src[i] )
  587.             waveformat.dwChannelMask |= pi_channels_in[i];
  588.     }
  589.     switch( i_format )
  590.     {
  591.     case VLC_FOURCC('s','p','d','i'):
  592.         i_nb_channels = 2;
  593.         /* To prevent channel re-ordering */
  594.         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
  595.         waveformat.Format.wBitsPerSample = 16;
  596.         waveformat.Samples.wValidBitsPerSample =
  597.             waveformat.Format.wBitsPerSample;
  598.         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
  599.         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
  600.         break;
  601.     case VLC_FOURCC('f','l','3','2'):
  602.         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
  603.         waveformat.Samples.wValidBitsPerSample =
  604.             waveformat.Format.wBitsPerSample;
  605.         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
  606.         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  607.         break;
  608.     case VLC_FOURCC('s','1','6','l'):
  609.         waveformat.Format.wBitsPerSample = 16;
  610.         waveformat.Samples.wValidBitsPerSample =
  611.             waveformat.Format.wBitsPerSample;
  612.         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
  613.         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
  614.         break;
  615.     }
  616.     waveformat.Format.nChannels = i_nb_channels;
  617.     waveformat.Format.nSamplesPerSec = i_rate;
  618.     waveformat.Format.nBlockAlign =
  619.         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
  620.     waveformat.Format.nAvgBytesPerSec =
  621.         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
  622.     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
  623.     if( i_nb_channels <= 2 )
  624.     {
  625.         waveformat.Format.cbSize = 0;
  626.     }
  627.     else
  628.     {
  629.         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  630.         waveformat.Format.cbSize =
  631.             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  632.     }
  633.     if(!b_probe) {
  634.         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
  635.         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
  636.                  waveformat.Format.cbSize);
  637.         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
  638.                  waveformat.Format.wFormatTag);
  639.         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
  640.                  waveformat.Format.nChannels);
  641.         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
  642.                  (int)waveformat.Format.nSamplesPerSec);
  643.         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
  644.                  (int)waveformat.Format.nAvgBytesPerSec);
  645.         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
  646.                  waveformat.Format.nBlockAlign);
  647.         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
  648.                  waveformat.Format.wBitsPerSample);
  649.         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
  650.                  waveformat.Samples.wValidBitsPerSample);
  651.         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
  652.                  waveformat.Samples.wSamplesPerBlock);
  653.         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu",
  654.                  waveformat.dwChannelMask);
  655.     }
  656.     /* Open the device */
  657.     result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
  658.                           (WAVEFORMATEX *)&waveformat,
  659.                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
  660.                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
  661.     if( result == WAVERR_BADFORMAT )
  662.     {
  663.         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
  664.         return VLC_EGENERIC;
  665.     }
  666.     if( result == MMSYSERR_ALLOCATED )
  667.     {
  668.         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
  669.         return VLC_EGENERIC;
  670.     }
  671.     if( result != MMSYSERR_NOERROR )
  672.     {
  673.         msg_Warn( p_aout, "waveOutOpen failed" );
  674.         return VLC_EGENERIC;
  675.     }
  676.     p_aout->output.p_sys->b_chan_reorder =
  677.         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
  678.                                   waveformat.dwChannelMask, i_nb_channels,
  679.                                   p_aout->output.p_sys->pi_chan_table );
  680.     if( p_aout->output.p_sys->b_chan_reorder )
  681.     {
  682.         msg_Dbg( p_aout, "channel reordering needed" );
  683.     }
  684.     return VLC_SUCCESS;
  685. #undef waveformat
  686. }
  687. /*****************************************************************************
  688.  * OpenWaveOutPCM: open a PCM waveout sound device
  689.  ****************************************************************************/
  690. static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
  691.                            int i_channels, int i_nb_channels, int i_rate,
  692.                            bool b_probe )
  693. {
  694.     bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
  695.     if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
  696.                                    i_channels, i_nb_channels, i_rate, b_probe )
  697.         != VLC_SUCCESS )
  698.     {
  699.         if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
  700.                           i_channels, i_nb_channels, i_rate, b_probe )
  701.              != VLC_SUCCESS )
  702.         {
  703.             return VLC_EGENERIC;
  704.         }
  705.         else
  706.         {
  707.             *i_format = VLC_FOURCC('s','1','6','l');
  708.             return VLC_SUCCESS;
  709.         }
  710.     }
  711.     else
  712.     {
  713.         *i_format = VLC_FOURCC('f','l','3','2');
  714.         return VLC_SUCCESS;
  715.     }
  716. }
  717. /*****************************************************************************
  718.  * PlayWaveOut: play a buffer through the WaveOut device
  719.  *****************************************************************************/
  720. static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
  721.                         WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
  722.                         bool b_spdif)
  723. {
  724.     MMRESULT result;
  725.     /* Prepare the buffer */
  726.     if( p_buffer != NULL )
  727.     {
  728.         p_waveheader->lpData = p_buffer->p_buffer;
  729.         /*
  730.           copy the buffer to the silence buffer :) so in case we don't
  731.           get the next buffer fast enough (I will repeat this one a time
  732.           for AC3 / DTS and SPDIF this will sound better instead of
  733.           a hickup)
  734.         */
  735.         if(b_spdif)
  736.         {
  737.            vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
  738.                        p_buffer->p_buffer,
  739.                        p_aout->output.p_sys->i_buffer_size );
  740.            p_aout->output.p_sys->i_repeat_counter = 2;
  741.         }
  742.     } else {
  743.         /* Use silence buffer instead */
  744.         if(p_aout->output.p_sys->i_repeat_counter)
  745.         {
  746.            p_aout->output.p_sys->i_repeat_counter--;
  747.            if(!p_aout->output.p_sys->i_repeat_counter)
  748.            {
  749.                vlc_memset( p_aout->output.p_sys->p_silence_buffer,
  750.                            0x00, p_aout->output.p_sys->i_buffer_size );
  751.            }
  752.         }
  753.         p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
  754.     }
  755.     p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
  756.     p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
  757.     p_waveheader->dwFlags = 0;
  758.     result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
  759.     if( result != MMSYSERR_NOERROR )
  760.     {
  761.         msg_Err( p_aout, "waveOutPrepareHeader failed" );
  762.         return VLC_EGENERIC;
  763.     }
  764.     /* Send the buffer to the waveOut queue */
  765.     result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
  766.     if( result != MMSYSERR_NOERROR )
  767.     {
  768.         msg_Err( p_aout, "waveOutWrite failed" );
  769.         return VLC_EGENERIC;
  770.     }
  771.     return VLC_SUCCESS;
  772. }
  773. /*****************************************************************************
  774.  * WaveOutCallback: what to do once WaveOut has played its sound samples
  775.  *****************************************************************************/
  776. static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
  777.                                       DWORD _p_aout,
  778.                                       DWORD dwParam1, DWORD dwParam2 )
  779. {
  780.     (void)h_waveout;    (void)dwParam1;    (void)dwParam2;
  781.     aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
  782.     int i, i_queued_frames = 0;
  783.     if( uMsg != WOM_DONE ) return;
  784.     if( !vlc_object_alive (p_aout) ) return;
  785.     /* Find out the current latency */
  786.     for( i = 0; i < FRAMES_NUM; i++ )
  787.     {
  788.         /* Check if frame buf is available */
  789.         if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
  790.         {
  791.             i_queued_frames++;
  792.         }
  793.     }
  794.     /* Don't wake up the thread too much */
  795.     if( i_queued_frames <= FRAMES_NUM/2 )
  796.         SetEvent( p_aout->output.p_sys->event );
  797. }
  798. /****************************************************************************
  799.  * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
  800.  ****************************************************************************
  801.  * return value is the number of still playing buffers in the queue
  802.  ****************************************************************************/
  803. static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
  804. {
  805.     WAVEHDR *p_waveheader = p_sys->waveheader;
  806.     int i_queued_frames = 0;
  807.     for( int i = 0; i < FRAMES_NUM; i++ )
  808.     {
  809.         if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
  810.             p_waveheader[i].dwUser )
  811.         {
  812.             aout_buffer_t *p_buffer =
  813.                     (aout_buffer_t *)(p_waveheader[i].dwUser);
  814.             /* Unprepare and free the buffers which has just been played */
  815.             waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
  816.                                     sizeof(WAVEHDR) );
  817.             if( p_waveheader[i].dwUser != 1 )
  818.                 aout_BufferFree( p_buffer );
  819.             p_waveheader[i].dwUser = 0;
  820.         }
  821.         /* Check if frame buf is available */
  822.         if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
  823.         {
  824.             i_queued_frames++;
  825.         }
  826.     }
  827.     return i_queued_frames;
  828. }
  829. /*****************************************************************************
  830.  * WaveOutThread: this thread will capture play notification events.
  831.  *****************************************************************************
  832.  * We use this thread to feed new audio samples to the sound card because
  833.  * we are not authorized to use waveOutWrite() directly in the waveout
  834.  * callback.
  835.  *****************************************************************************/
  836. static void* WaveOutThread( vlc_object_t *p_this )
  837. {
  838.     notification_thread_t *p_notif = (notification_thread_t*)p_this;
  839.     aout_instance_t *p_aout = p_notif->p_aout;
  840.     aout_sys_t *p_sys = p_aout->output.p_sys;
  841.     aout_buffer_t *p_buffer = NULL;
  842.     WAVEHDR *p_waveheader = p_sys->waveheader;
  843.     int i, i_queued_frames;
  844.     bool b_sleek;
  845.     mtime_t next_date;
  846.     uint32_t i_buffer_length = 64;
  847.     int canc = vlc_savecancel ();
  848.     /* We don't want any resampling when using S/PDIF */
  849.     b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
  850.     // wait for first call to "play()"
  851.     while( !p_sys->start_date && vlc_object_alive (p_aout) )
  852.            WaitForSingleObject( p_sys->event, INFINITE );
  853.     if( !vlc_object_alive (p_aout) )
  854.         return NULL;
  855.     msg_Dbg( p_aout, "will start to play in %"PRId64" us",
  856.              (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
  857.     // than wait a short time... before grabbing first frames
  858.     mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
  859. #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "
  860.                            "got next_date=%d ms, "
  861.                            "%d frames to play, "
  862.                            "starving? %d, %s",(int)(next_date/(mtime_t)1000), 
  863.                            i_queued_frames, 
  864.                            p_aout->output.b_starving, msg);
  865.     next_date = mdate();
  866.     while( vlc_object_alive (p_aout) )
  867.     {
  868.         /* Cleanup and find out the current latency */
  869.         i_queued_frames = WaveOutClearDoneBuffers( p_sys );
  870.         if( !vlc_object_alive (p_aout) ) return NULL;
  871.         /* Try to fill in as many frame buffers as possible */
  872.         for( i = 0; i < FRAMES_NUM; i++ )
  873.         {
  874.             /* Check if frame buf is available */
  875.             if( p_waveheader[i].dwFlags & WHDR_DONE )
  876.             {
  877.                 // next_date = mdate() + 1000000 * i_queued_frames /
  878.                 //  p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
  879.                 // the realtime has got our back-site:) to come in sync
  880.                 if(next_date < mdate())
  881.                    next_date = mdate();
  882.                 /* Take into account the latency */
  883.                 p_buffer = aout_OutputNextBuffer( p_aout,
  884.                     next_date,
  885.                     b_sleek );
  886.                 if(!p_buffer)
  887.                 {
  888. #if 0
  889.                     msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "
  890.                                       "got next_date=%d ms, "
  891.                                       "%d frames to play, "
  892.                                       "starving? %d",(int)(next_date/(mtime_t)1000),
  893.                                                      i_queued_frames,
  894.                                                      p_aout->output.b_starving);
  895. #endif
  896.                     if(p_aout->output.b_starving)
  897.                     {
  898.                         // means we are too early to request a new buffer?
  899.                         waveout_warn("waiting...")
  900.                         next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
  901.                         mwait( next_date - AOUT_PTS_TOLERANCE/4 );
  902.                         next_date = mdate();
  903.                         p_buffer = aout_OutputNextBuffer( p_aout,
  904.                                      next_date,
  905.                                      b_sleek
  906.                                    );
  907.                     }
  908.                 }
  909.                 if( !p_buffer && i_queued_frames )
  910.                 {
  911.                     /* We aren't late so no need to play a blank sample */
  912.                     break;
  913.                 }
  914.                 if( p_buffer )
  915.                 {
  916.                     mtime_t buffer_length = (p_buffer->end_date
  917.                                              - p_buffer->start_date);
  918.                     next_date = next_date + buffer_length;
  919.                     i_buffer_length = buffer_length/1000;
  920.                 }
  921.                 /* Do the channel reordering */
  922.                 if( p_buffer && p_sys->b_chan_reorder )
  923.                 {
  924.                     aout_ChannelReorder( p_buffer->p_buffer,
  925.                         p_buffer->i_nb_bytes,
  926.                         p_sys->waveformat.Format.nChannels,
  927.                         p_sys->pi_chan_table,
  928.                         p_sys->waveformat.Format.wBitsPerSample );
  929.                 }
  930.                 PlayWaveOut( p_aout, p_sys->h_waveout,
  931.                              &p_waveheader[i], p_buffer, b_sleek );
  932.                 i_queued_frames++;
  933.             }
  934.         }
  935.         if( !vlc_object_alive (p_aout) ) return NULL;
  936.         /*
  937.           deal with the case that the loop didn't fillup the buffer to the
  938.           max - instead of waiting that half the buffer is played before
  939.           fillup the waveout buffers, wait only for the next sample buffer
  940.           to arrive at the play method...
  941.           this will also avoid, that the last buffer is play until the
  942.           end, and then trying to get more data, so it will also
  943.           work - if the next buffer will arrive some ms before the
  944.           last buffer is finished.
  945.         */
  946.         if(i_queued_frames < FRAMES_NUM)
  947.            WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
  948.         else
  949.            WaitForSingleObject( p_sys->event, INFINITE );
  950.     }
  951. #undef waveout_warn
  952.     vlc_restorecancel (canc);
  953.     return NULL;
  954. }
  955. static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
  956. {
  957.     *pi_soft = AOUT_VOLUME_MAX / 2;
  958.     return 0;
  959. }
  960. static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
  961. {
  962.     DWORD i_waveout_vol;
  963. #ifdef UNDER_CE
  964.     waveOutGetVolume( 0, &i_waveout_vol );
  965. #else
  966.     waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
  967. #endif
  968.     i_waveout_vol &= 0xFFFF;
  969.     *pi_volume = p_aout->output.i_volume =
  970.         (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
  971.     return 0;
  972. }
  973. static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
  974. {
  975.     unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
  976.     i_waveout_vol |= (i_waveout_vol << 16);
  977. #ifdef UNDER_CE
  978.     waveOutSetVolume( 0, i_waveout_vol );
  979. #else
  980.     waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
  981. #endif
  982.     p_aout->output.i_volume = i_volume;
  983.     return 0;
  984. }
  985. /*
  986.   reload the configuration drop down list, of the Audio Devices
  987. */
  988. static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
  989.                                  vlc_value_t newval, vlc_value_t oldval, void *data )
  990. {
  991.     int i;
  992.     module_config_t *p_item = config_FindConfig( p_this, psz_name );
  993.     if( !p_item ) return VLC_SUCCESS;
  994.     /* Clear-up the current list */
  995.     if( p_item->i_list )
  996.     {
  997.         /* Keep the first entry */
  998.         for( i = 1; i < p_item->i_list; i++ )
  999.         {
  1000.             free((char *)(p_item->ppsz_list[i]) );
  1001.             free((char *)(p_item->ppsz_list_text[i]) );
  1002.         }
  1003.         /* TODO: Remove when no more needed */
  1004.         p_item->ppsz_list[i] = NULL;
  1005.         p_item->ppsz_list_text[i] = NULL;
  1006.     }
  1007.     p_item->i_list = 1;
  1008.     int wave_devices = waveOutGetNumDevs();
  1009.     p_item->ppsz_list =
  1010.         (char **)realloc( p_item->ppsz_list,
  1011.                           (wave_devices+2) * sizeof(char *) );
  1012.     p_item->ppsz_list_text =
  1013.         (char **)realloc( p_item->ppsz_list_text,
  1014.                           (wave_devices+2) * sizeof(char *) );
  1015.     WAVEOUTCAPS caps;
  1016.     char sz_dev_name[MAXPNAMELEN+32];
  1017.     int j=1;
  1018.     for(int i=0; i<wave_devices; i++)
  1019.     {
  1020.         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
  1021.            == MMSYSERR_NOERROR)
  1022.         {
  1023.           sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
  1024.                                                caps.wMid,
  1025.                                                caps.wPid
  1026.                                               );
  1027.           p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
  1028.           p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
  1029.           p_item->i_list++;
  1030.           j++;
  1031.         }
  1032.     }
  1033.     p_item->ppsz_list[j] = NULL;
  1034.     p_item->ppsz_list_text[j] = NULL;
  1035.     /* Signal change to the interface */
  1036.     p_item->b_dirty = true;
  1037.     return VLC_SUCCESS;
  1038. }
  1039. /*
  1040.   convert devicename to device ID for output
  1041.   if device not found return WAVE_MAPPER, so let
  1042.   windows decide which preferred audio device
  1043.   should be used.
  1044. */
  1045. static uint32_t findDeviceID(char *psz_device_name)
  1046. {
  1047.     if(!psz_device_name)
  1048.        return WAVE_MAPPER;
  1049.     uint32_t wave_devices = waveOutGetNumDevs();
  1050.     WAVEOUTCAPS caps;
  1051.     char sz_dev_name[MAXPNAMELEN+32];
  1052.     for(uint32_t i=0; i<wave_devices; i++)
  1053.     {
  1054.         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
  1055.            == MMSYSERR_NOERROR)
  1056.         {
  1057.             sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
  1058.                                                caps.wMid,
  1059.                                                caps.wPid
  1060.                                               );
  1061.             char *psz_temp = FromLocaleDup(sz_dev_name);
  1062.             if( !stricmp(psz_temp, psz_device_name) )
  1063.             {
  1064.                 LocaleFree( psz_temp );
  1065.                 return i;
  1066.             }
  1067.             LocaleFree( psz_temp );
  1068.         }
  1069.     }
  1070.     return WAVE_MAPPER;
  1071. }