Changeset 79223aaeafe7ef625f08551700a6ae4d2a26e8b0

Show
Ignore:
Timestamp:
03/02/08 18:22:11 (6 months ago)
Author:
André Weber <WeberAndre@gmx.de>
git-committer:
André Weber <WeberAndre@gmx.de> 1204478531 +0100
git-parent:

[ced125da0699eb348462270926a6802288800433]

git-author:
André Weber <WeberAndre@gmx.de> 1204478531 +0100
Message:

Bugfix for #492: Audio output on Windows useing SPDIF for AC3 / DTS
But its still very time critical, because paout gets sometimes empty
so that aout_OutputNextBuffer(..) doesn't deliver new audiobuffers,
sometimes it happens - that these buffers arrive very late for output.
Reasons: -changed CPU load, (extra running application, also fast forward
seeking and and jumping may lead to this situation.)

Enhancement #897: added an option to let the user choose is prefered audio device. (needs restart of VLC to get applied)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/audio_output/waveout.c

    rced125d r79223aa  
    3232#include <vlc/vlc.h> 
    3333#include <vlc_aout.h> 
     34#include <vlc_charset.h> 
    3435 
    3536#include <windows.h> 
     
    121122/* local functions */ 
    122123static void Probe        ( aout_instance_t * ); 
    123 static int OpenWaveOut   ( aout_instance_t *, int, int, int, int, vlc_bool_t ); 
    124 static int OpenWaveOutPCM( aout_instance_t *, int*, int, int, int, vlc_bool_t ); 
     124static int OpenWaveOut   ( aout_instance_t *, uint32_t, 
     125                           int, int, int, int, vlc_bool_t ); 
     126static int OpenWaveOutPCM( aout_instance_t *, uint32_t, 
     127                           int*, int, int, int, vlc_bool_t ); 
    125128static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *, 
    126                            aout_buffer_t * ); 
     129                           aout_buffer_t *, vlc_bool_t ); 
    127130 
    128131static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD ); 
     
    132135static int VolumeGet( aout_instance_t *, audio_volume_t * ); 
    133136static int VolumeSet( aout_instance_t *, audio_volume_t ); 
     137 
     138static int WaveOutClearDoneBuffers(aout_sys_t *p_sys); 
     139 
     140static int ReloadWaveoutDevices( vlc_object_t *, char const *, 
     141                                vlc_value_t, vlc_value_t, void * ); 
     142static uint32_t findDeviceID(char *); 
     143 
     144static const char psz_device_name_fmt[] = "%s ($%x,$%x)"; 
     145 
     146static const char *ppsz_adev[] = { "wavemapper", }; 
     147static const char *ppsz_adev_text[] = { N_("Microsoft Soundmapper") }; 
     148 
     149 
    134150 
    135151/***************************************************************************** 
     
    140156    "The option allows you to enable or disable the high-quality float32 " \ 
    141157    "audio output mode (which is not well supported by some soundcards)." ) 
     158#define DEVICE_TEXT N_("Select Audio Device") 
     159#define DEVICE_LONG N_("Select special Audio device, or let windows "\ 
     160                       "decide (default), change needs VLC restart "\ 
     161                       "to apply.") 
     162#define DEFAULT_AUDIO_DEVICE N_("Default Audio Device") 
    142163 
    143164vlc_module_begin(); 
     
    148169    set_subcategory( SUBCAT_AUDIO_AOUT ); 
    149170    add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE ); 
     171 
     172    add_string( "waveout-dev", "wavemapper", NULL, 
     173                 DEVICE_TEXT, DEVICE_LONG, VLC_FALSE ); 
     174       change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices ); 
     175       change_need_restart(); 
     176       change_action_add( ReloadWaveoutDevices, N_("Refresh list") ); 
     177 
     178 
    150179    set_callbacks( Open, Close ); 
    151180vlc_module_end(); 
     
    159188struct aout_sys_t 
    160189{ 
     190    uint32_t i_wave_device_id;               /* ID of selected output device */ 
     191 
    161192    HWAVEOUT h_waveout;                        /* handle to waveout instance */ 
    162193 
     
    167198    notification_thread_t *p_notif;                      /* WaveOutThread id */ 
    168199    HANDLE event; 
     200    HANDLE new_buffer_event; 
     201 
     202    // rental from alsa.c to synchronize startup of audiothread 
     203    int b_playing;                                         /* playing status */ 
     204    mtime_t start_date; 
     205 
     206    int i_repeat_counter; 
    169207 
    170208    int i_buffer_size; 
     
    215253    p_aout->b_die = VLC_FALSE; 
    216254 
     255 
     256    /* 
     257     initialize/update Device selection List 
     258    */ 
     259    ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL); 
     260 
     261 
     262    /* 
     263      check for configured audio device! 
     264    */ 
     265    char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev"); 
     266 
     267    p_aout->output.p_sys->i_wave_device_id = 
     268         findDeviceID( psz_waveout_dev ); 
     269 
     270    if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER) 
     271    { 
     272       if(psz_waveout_dev && 
     273          stricmp(psz_waveout_dev,"wavemapper")) 
     274       { 
     275           msg_Warn( p_aout, "configured audio device '%s' not available, "\ 
     276                         "use default instead", psz_waveout_dev ); 
     277       } 
     278    } 
     279    if(psz_waveout_dev) free( psz_waveout_dev ); 
     280 
     281 
     282    WAVEOUTCAPS waveoutcaps; 
     283    if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id, 
     284                          &waveoutcaps, 
     285                          sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) 
     286    { 
     287      /* log debug some infos about driver, to know who to blame 
     288         if it doesn't work */ 
     289        msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname); 
     290        msg_Dbg( p_aout, "Driver Version: %d.%d", 
     291                          (waveoutcaps.vDriverVersion>>8)&255, 
     292                          waveoutcaps.vDriverVersion & 255); 
     293        msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid ); 
     294        msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid ); 
     295    } 
     296 
     297 
     298 
    217299    if( var_Type( p_aout, "audio-device" ) == 0 ) 
    218300    { 
     
    223305    { 
    224306        /* Probe() has failed. */ 
     307        var_Destroy( p_aout, "waveout-device"); 
    225308        free( p_aout->output.p_sys ); 
    226309        return VLC_EGENERIC; 
    227310    } 
    228311 
    229     var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); 
    230312 
    231313    /* Open the device */ 
     
    234316        p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); 
    235317 
    236         if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'), 
     318        if( OpenWaveOut( p_aout, 
     319                         p_aout->output.p_sys->i_wave_device_id, 
     320                         VLC_FOURCC('s','p','d','i'), 
    237321                         p_aout->output.output.i_physical_channels, 
    238322                         aout_FormatNbChannels( &p_aout->output.output ), 
     
    281365        } 
    282366 
    283         if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format, 
     367        if( OpenWaveOutPCM( p_aout, 
     368                            p_aout->output.p_sys->i_wave_device_id, 
     369                            &p_aout->output.output.i_format, 
    284370                            p_aout->output.output.i_physical_channels, 
    285371                            aout_FormatNbChannels( &p_aout->output.output ), 
     
    328414        return 1; 
    329415    } 
     416    p_aout->output.p_sys->i_repeat_counter = 0; 
     417 
    330418 
    331419    /* Zero the buffer. WinCE doesn't have calloc(). */ 
     
    338426    p_aout->output.p_sys->p_notif->p_aout = p_aout; 
    339427    p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL ); 
     428    p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL ); 
     429 
     430    /* define startpoint of playback on first call to play() 
     431      like alsa does (instead of playing a blank sample) */ 
     432    p_aout->output.p_sys->b_playing = 0; 
     433    p_aout->output.p_sys->start_date = 0; 
     434 
    340435 
    341436    /* Then launch the notification thread */ 
    342437    if( vlc_thread_create( p_aout->output.p_sys->p_notif, 
    343438                           "waveOut Notification Thread", WaveOutThread, 
    344                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) ) 
     439                           VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) ) 
    345440    { 
    346441        msg_Err( p_aout, "cannot create WaveOutThread" ); 
     
    354449        p_aout->output.p_sys->waveheader[i].dwUser = 0; 
    355450    } 
    356     PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout, 
    357                  &p_aout->output.p_sys->waveheader[0], NULL ); 
    358451 
    359452    return 0; 
     
    379472    if( p_aout->output.output.i_physical_channels == i_physical_channels ) 
    380473    { 
    381         if( OpenWaveOutPCM( p_aout, &i_format, 
     474        if( OpenWaveOutPCM( p_aout, 
     475                            p_aout->output.p_sys->i_wave_device_id, 
     476                            &i_format, 
    382477                            i_physical_channels, 6, 
    383478                            p_aout->output.output.i_rate, VLC_TRUE ) 
     
    385480        { 
    386481            val.i_int = AOUT_VAR_5_1; 
    387             text.psz_string = N_("5.1"); 
     482            text.psz_string = (char *)N_("5.1"); 
    388483            var_Change( p_aout, "audio-device", 
    389484                        VLC_VAR_ADDCHOICE, &val, &text ); 
     
    398493        == i_physical_channels ) 
    399494    { 
    400         if( OpenWaveOutPCM( p_aout, &i_format, 
     495        if( OpenWaveOutPCM( p_aout, 
     496                            p_aout->output.p_sys->i_wave_device_id, 
     497                            &i_format, 
    401498                            i_physical_channels, 4, 
    402499                            p_aout->output.output.i_rate, VLC_TRUE ) 
     
    404501        { 
    405502            val.i_int = AOUT_VAR_2F2R; 
    406             text.psz_string = N_("2 Front 2 Rear"); 
     503            text.psz_string = (char *)N_("2 Front 2 Rear"); 
    407504            var_Change( p_aout, "audio-device", 
    408505                        VLC_VAR_ADDCHOICE, &val, &text ); 
     
    413510    /* Test for stereo support */ 
    414511    i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; 
    415     if( OpenWaveOutPCM( p_aout, &i_format, 
     512    if( OpenWaveOutPCM( p_aout, 
     513                        p_aout->output.p_sys->i_wave_device_id, 
     514                        &i_format, 
    416515                        i_physical_channels, 2, 
    417516                        p_aout->output.output.i_rate, VLC_TRUE ) 
     
    419518    { 
    420519        val.i_int = AOUT_VAR_STEREO; 
    421         text.psz_string = N_("Stereo"); 
     520        text.psz_string = (char *)N_("Stereo"); 
    422521        var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); 
    423522        msg_Dbg( p_aout, "device supports 2 channels" ); 
     
    426525    /* Test for mono support */ 
    427526    i_physical_channels = AOUT_CHAN_CENTER; 
    428     if( OpenWaveOutPCM( p_aout, &i_format, 
     527    if( OpenWaveOutPCM( p_aout, 
     528                        p_aout->output.p_sys->i_wave_device_id, 
     529                        &i_format, 
    429530                        i_physical_channels, 1, 
    430531                        p_aout->output.output.i_rate, VLC_TRUE ) 
     
    432533    { 
    433534        val.i_int = AOUT_VAR_MONO; 
    434         text.psz_string = N_("Mono"); 
     535        text.psz_string = (char *)N_("Mono"); 
    435536        var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); 
    436537        msg_Dbg( p_aout, "device supports 1 channel" ); 
     
    440541    if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) 
    441542    { 
    442         if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'), 
     543        if( OpenWaveOut( p_aout, 
     544                         p_aout->output.p_sys->i_wave_device_id, 
     545                         VLC_FOURCC('s','p','d','i'), 
    443546                         p_aout->output.output.i_physical_channels, 
    444547                         aout_FormatNbChannels( &p_aout->output.output ), 
     
    448551            msg_Dbg( p_aout, "device supports A/52 over S/PDIF" ); 
    449552            val.i_int = AOUT_VAR_SPDIF; 
    450             text.psz_string = N_("A/52 over S/PDIF"); 
     553            text.psz_string = (char *)N_("A/52 over S/PDIF"); 
    451554            var_Change( p_aout, "audio-device", 
    452555                        VLC_VAR_ADDCHOICE, &val, &text ); 
     
    478581static void Play( aout_instance_t *_p_aout ) 
    479582{ 
     583    if( !_p_aout->output.p_sys->b_playing ) 
     584    { 
     585        _p_aout->output.p_sys->b_playing = 1; 
     586 
     587        /* get the playing date of the first aout buffer */ 
     588        _p_aout->output.p_sys->start_date = 
     589            aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo ); 
     590 
     591        msg_Dbg( _p_aout, "Wakeup sleeping output thread."); 
     592 
     593        /* wake up the audio output thread */ 
     594        SetEvent( _p_aout->output.p_sys->event ); 
     595    } else { 
     596        SetEvent( _p_aout->output.p_sys->new_buffer_event ); 
     597    } 
    480598} 
    481599 
     
    491609    vlc_object_kill( p_aout ); 
    492610 
    493     waveOutReset( p_sys->h_waveout ); 
    494  
    495     /* wake up the audio thread */ 
     611    /* wake up the audio thread, to recognize that p_aout died */ 
    496612    SetEvent( p_sys->event ); 
     613    SetEvent( p_sys->new_buffer_event ); 
     614 
    497615    vlc_thread_join( p_sys->p_notif ); 
    498616    vlc_object_release( p_sys->p_notif ); 
     617 
     618    /* 
     619      kill the real output then - when the feed thread 
     620      is surely terminated! 
     621      old code could be too early in case that "feeding" 
     622      was running on termination 
     623 
     624      at this point now its sure, that there will be no new 
     625      data send to the driver, and we can cancel the last 
     626      running playbuffers 
     627    */ 
     628    MMRESULT result = waveOutReset( p_sys->h_waveout ); 
     629    if(result != MMSYSERR_NOERROR) 
     630    { 
     631       msg_Err( p_aout, "waveOutReset failed 0x%x", result ); 
     632       /* 
     633        now we must wait, that all buffers are played 
     634        because cancel doesn't work in this case... 
     635       */ 
     636       if(result == MMSYSERR_NOTSUPPORTED) 
     637       { 
     638           /* 
     639             clear currently played (done) buffers, 
     640             if returnvalue > 0 (means some buffer still playing) 
     641             wait for the driver event callback that one buffer 
     642             is finished with playing, and check again 
     643             the timeout of 5000ms is just, an emergency exit 
     644             of this loop, to avoid deadlock in case of other 
     645             (currently not known bugs, problems, errors cases?) 
     646           */ 
     647           while( 
     648                 (WaveOutClearDoneBuffers( p_sys ) > 0) 
     649                 && 
     650                 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0) 
     651                ) 
     652           { 
     653                 msg_Dbg( p_aout, "Wait for waveout device..."); 
     654           } 
     655       } 
     656    } else { 
     657        WaveOutClearDoneBuffers( p_sys ); 
     658    } 
     659 
     660    /* now we can Close the device */ 
     661    if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR ) 
     662    { 
     663        msg_Err( p_aout, "waveOutClose failed" ); 
     664    } 
     665 
     666    /* 
     667      because so long, the waveout device is playing, the callback 
     668      could occur and need the events 
     669    */ 
    499670    CloseHandle( p_sys->event ); 
    500  
    501     /* Close the device */ 
    502     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR ) 
    503     { 
    504         msg_Err( p_aout, "waveOutClose failed" ); 
    505     } 
     671    CloseHandle( p_sys->new_buffer_event); 
    506672 
    507673    free( p_sys->p_silence_buffer ); 
     
    512678 * OpenWaveOut: open the waveout sound device 
    513679 ****************************************************************************/ 
    514 static int OpenWaveOut( aout_instance_t *p_aout, int i_format, 
     680static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format, 
    515681                        int i_channels, int i_nb_channels, int i_rate, 
    516682                        vlc_bool_t b_probe ) 
     
    579745    } 
    580746 
     747    if(!b_probe) { 
     748        msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id); 
     749        msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d", 
     750                 waveformat.Format.cbSize); 
     751        msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u", 
     752                 waveformat.Format.wFormatTag); 
     753        msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u", 
     754                 waveformat.Format.nChannels); 
     755        msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d", 
     756                 (int)waveformat.Format.nSamplesPerSec); 
     757        msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u", 
     758                 (int)waveformat.Format.nAvgBytesPerSec); 
     759        msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d", 
     760                 waveformat.Format.nBlockAlign); 
     761        msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d", 
     762                 waveformat.Format.wBitsPerSample); 
     763        msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d", 
     764                 waveformat.Samples.wValidBitsPerSample); 
     765        msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d", 
     766                 waveformat.Samples.wSamplesPerBlock); 
     767        msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu", 
     768                 waveformat.dwChannelMask); 
     769    } 
     770 
    581771    /* Open the device */ 
    582     result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER
     772    result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id
    583773                          (WAVEFORMATEX *)&waveformat, 
    584774                          (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout, 
     
    619809 * OpenWaveOutPCM: open a PCM waveout sound device 
    620810 ****************************************************************************/ 
    621 static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format, 
     811static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format, 
    622812                           int i_channels, int i_nb_channels, int i_rate, 
    623813                           vlc_bool_t b_probe ) 
    624814{ 
    625     vlc_value_t val; 
    626  
    627     var_Get( p_aout, "waveout-float32", &val ); 
    628  
    629     if( !val.b_bool || OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'), 
     815    vlc_bool_t b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32"); 
     816 
     817    if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'), 
    630818                                   i_channels, i_nb_channels, i_rate, b_probe ) 
    631819        != VLC_SUCCESS ) 
    632820    { 
    633         if ( OpenWaveOut( p_aout, VLC_FOURCC('s','1','6','l'), 
     821        if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'), 
    634822                          i_channels, i_nb_channels, i_rate, b_probe ) 
    635823             != VLC_SUCCESS ) 
     
    654842 *****************************************************************************/ 
    655843static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout, 
    656                         WAVEHDR *p_waveheader, aout_buffer_t *p_buffer ) 
     844                        WAVEHDR *p_waveheader, aout_buffer_t *p_buffer, 
     845                        vlc_bool_t b_spdif) 
    657846{ 
    658847    MMRESULT result; 
     
    660849    /* Prepare the buffer */ 
    661850    if( p_buffer != NULL ) 
     851    { 
    662852        p_waveheader->lpData = p_buffer->p_buffer; 
    663     else 
     853        /* 
     854          copy the buffer to the silence buffer :) so in case we don't 
     855          get the next buffer fast enough (I will repeat this one a time 
     856          for AC3 / DTS and SPDIF this will sound better instead of 
     857          a hickup) 
     858        */ 
     859        if(b_spdif) 
     860        { 
     861           p_aout->p_libvlc->pf_memcpy( p_aout->output.p_sys->p_silence_buffer, 
     862                                     p_buffer->p_buffer, 
     863                                     p_aout->output.p_sys->i_buffer_size ); 
     864           p_aout->output.p_sys->i_repeat_counter = 2; 
     865        } 
     866    } else { 
    664867        /* Use silence buffer instead */ 
     868        if(p_aout->output.p_sys->i_repeat_counter) 
     869        { 
     870           p_aout->output.p_sys->i_repeat_counter--; 
     871           if(!p_aout->output.p_sys->i_repeat_counter) 
     872           { 
     873               p_aout->p_libvlc->pf_memset( p_aout->output.p_sys->p_silence_buffer, 
     874                                            0x00, 
     875                                            p_aout->output.p_sys->i_buffer_size 
     876                                          ); 
     877           } 
     878        } 
    665879        p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer; 
     880    } 
    666881 
    667882    p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1; 
     
    712927 
    713928    /* Don't wake up the thread too much */ 
    714     if( i_queued_frames < FRAMES_NUM / 2 ) 
     929    if( i_queued_frames <= FRAMES_NUM/2 ) 
    715930        SetEvent( p_aout->output.p_sys->event ); 
     931} 
     932 
     933 
     934/**************************************************************************** 
     935 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer 
     936 **************************************************************************** 
     937 * return value is the number of still playing buffers in the queue 
     938 ****************************************************************************/ 
     939static int WaveOutClearDoneBuffers(aout_sys_t *p_sys) 
     940{ 
     941    WAVEHDR *p_waveheader = p_sys->waveheader; 
     942    int i_queued_frames = 0; 
     943 
     944    for( int i = 0; i < FRAMES_NUM; i++ ) 
     945    { 
     946        if( (p_waveheader[i].dwFlags & WHDR_DONE) && 
     947            p_waveheader[i].dwUser ) 
     948        { 
     949            aout_buffer_t *p_buffer = 
     950                    (aout_buffer_t *)(p_waveheader[i].dwUser); 
     951            /* Unprepare and free the buffers which has just been played */ 
     952            waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i], 
     953                                    sizeof(WAVEHDR) ); 
     954 
     955            if( p_waveheader[i].dwUser != 1 ) 
     956                aout_BufferFree( p_buffer ); 
     957 
     958            p_waveheader[i].dwUser = 0; 
     959        } 
     960 
     961        /* Check if frame buf is available */ 
     962        if( !(p_waveheader[i].dwFlags & WHDR_DONE) ) 
     963        { 
     964            i_queued_frames++; 
     965        } 
     966    } 
     967    return i_queued_frames; 
    716968} 
    717969 
     
    731983    int i, i_queued_frames; 
    732984    vlc_bool_t b_sleek; 
     985    mtime_t next_date; 
     986    uint32_t i_buffer_length = 64; 
    733987 
    734988    /* We don't want any resampling when using S/PDIF */ 
    735989    b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i'); 
    736990 
    737     while( 1 ) 
    738     { 
    739         WaitForSingleObject( p_sys->event, INFINITE ); 
    740  
     991    // wait for first call to "play()" 
     992    while( !p_sys->start_date && !p_aout->b_die ) 
     993           WaitForSingleObject( p_sys->event, INFINITE ); 
     994    if( p_aout->b_die ) 
     995        return; 
     996 
     997    msg_Dbg( p_aout, "will start to play in "I64Fd" us", 
     998             (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate()); 
     999 
     1000    // than wait a short time... before grabbing first frames 
     1001    mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 ); 
     1002 
     1003#define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\ 
     1004                           "got next_date=%d ms, "\ 
     1005                           "%d frames to play, "\ 
     1006                           "starving? %d, %s",(int)(next_date/(mtime_t)1000), \ 
     1007                           i_queued_frames, \ 
     1008                           p_aout->output.b_starving, msg); 
     1009    next_date = mdate(); 
     1010 
     1011    while( !p_aout->b_die ) 
     1012    { 
    7411013        /* Cleanup and find out the current latency */ 
    742         i_queued_frames = 0; 
    743         for( i = 0; i < FRAMES_NUM; i++ ) 
    744         { 
    745             if( (p_waveheader[i].dwFlags & WHDR_DONE) && 
    746                 p_waveheader[i].dwUser ) 
    747             { 
    748                 aout_buffer_t *p_buffer = 
    749                         (aout_buffer_t *)(p_waveheader[i].dwUser); 
    750                 /* Unprepare and free the buffers which has just been played */ 
    751                 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i], 
    752                                         sizeof(WAVEHDR) ); 
    753  
    754                 if( p_waveheader[i].dwUser != 1 ) 
    755                     aout_BufferFree( p_buffer ); 
    756  
    757                 p_waveheader[i].dwUser = 0; 
    758             } 
    759  
    760             /* Check if frame buf is available */ 
    761             if( !(p_waveheader[i].dwFlags & WHDR_DONE) ) 
    762             { 
    763                 i_queued_frames++; 
    764             } 
    765         } 
     1014        i_queued_frames = WaveOutClearDoneBuffers( p_sys ); 
    7661015 
    7671016        if( p_aout->b_die ) return; 
     
    7731022            if( p_waveheader[i].dwFlags & WHDR_DONE ) 
    7741023            { 
     1024                // next_date = mdate() + 1000000 * i_queued_frames / 
     1025                //  p_aout->output.output.i_rate * p_aout->output.i_nb_samples; 
     1026 
     1027                // the realtime has got our back-site:) to come in sync 
     1028                if(next_date < mdate()) 
     1029                   next_date = mdate(); 
     1030 
     1031 
    7751032                /* Take into account the latency */ 
    7761033                p_buffer = aout_OutputNextBuffer( p_aout, 
    777                     mdate() + 1000000 * i_queued_frames / 
    778                     p_aout->output.output.i_rate * p_aout->output.i_nb_samples, 
     1034                    next_date, 
    7791035                    b_sleek ); 
     1036 
     1037                if(!p_buffer) 
     1038                { 
     1039#if 0 
     1040                    msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\ 
     1041                                      "got next_date=%d ms, "\ 
     1042                                      "%d frames to play, "\ 
     1043                                      "starving? %d",(int)(next_date/(mtime_t)1000), 
     1044                                                     i_queued_frames, 
     1045                                                     p_aout->output.b_starving); 
     1046#endif 
     1047                    if(p_aout->output.b_starving) 
     1048                    { 
     1049                        // means we are too early to request a new buffer? 
     1050                        waveout_warn("waiting...") 
     1051                        next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo ); 
     1052                        mwait( next_date - AOUT_PTS_TOLERANCE/4 ); 
     1053                        next_date = mdate(); 
     1054                        p_buffer = aout_OutputNextBuffer( p_aout, 
     1055                                     next_date, 
     1056                                     b_sleek 
     1057                                   ); 
     1058                    } 
     1059                } 
    7801060 
    7811061                if( !p_buffer && i_queued_frames ) 
     
    7831063                    /* We aren't late so no need to play a blank sample */ 
    7841064                    break; 
     1065                } 
     1066 
     1067                if( p_buffer ) 
     1068                { 
     1069                    mtime_t buffer_length = (p_buffer->end_date 
     1070                                             - p_buffer->start_date); 
     1071                    next_date = next_date + buffer_length; 
     1072                    i_buffer_length = buffer_length/1000; 
    7851073                } 
    7861074 
     
    7961084 
    7971085                PlayWaveOut( p_aout, p_sys->h_waveout, 
    798                              &p_waveheader[i], p_buffer ); 
     1086                             &p_waveheader[i], p_buffer, b_sleek ); 
    7991087 
    8001088                i_queued_frames++; 
    8011089            } 
    8021090        } 
    803     } 
     1091 
     1092        if( p_aout->b_die ) return; 
     1093 
     1094        /* 
     1095          deal with the case that the loop didn't fillup the buffer to the 
     1096          max - instead of waiting that half the buffer is played before 
     1097          fillup the waveout buffers, wait only for the next sample buffer 
     1098          to arrive at the play method... 
     1099 
     1100          this will also avoid, that the last buffer is play until the 
     1101          end, and then trying to get more data, so it will also 
     1102          work - if the next buffer will arrive some ms before the 
     1103          last buffer is finished. 
     1104        */ 
     1105        if(i_queued_frames < FRAMES_NUM) 
     1106           WaitForSingleObject( p_sys->new_buffer_event, INFINITE ); 
     1107        else 
     1108           WaitForSingleObject( p_sys->event, INFINITE ); 
     1109 
     1110    } 
     1111 
     1112#undef waveout_warn 
    8041113} 
    8051114 
     
    8401149    return 0; 
    8411150} 
     1151 
     1152 
     1153/* 
     1154  reload the configuration drop down list, of the Audio Devices 
     1155*/ 
     1156static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name, 
     1157                                 vlc_value_t newval, vlc_value_t oldval, void *data ) 
     1158{ 
     1159    int i; 
     1160 
     1161    module_config_t *p_item = config_FindConfig( p_this, psz_name ); 
     1162    if( !p_item ) return VLC_SUCCESS; 
     1163 
     1164    /* Clear-up the current list */ 
     1165    if( p_item->i_list ) 
     1166    { 
     1167        /* Keep the first entry */ 
     1168        for( i = 1; i < p_item->i_list; i++ ) 
     1169        { 
     1170            free((char *)(p_item->ppsz_list[i]) ); 
     1171            free((char *)(p_item->ppsz_list_text[i]) ); 
     1172        } 
     1173        /* TODO: Remove when no more needed */ 
     1174        p_item->ppsz_list[i] = NULL; 
     1175        p_item->ppsz_list_text[i] = NULL; 
     1176    } 
     1177    p_item->i_list = 1; 
     1178 
     1179    int wave_devices = waveOutGetNumDevs(); 
     1180 
     1181    p_item->ppsz_list = 
     1182        (char **)realloc( p_item->ppsz_list, 
     1183                          (wave_devices+2) * sizeof(char *) ); 
     1184    p_item->ppsz_list_text = 
     1185        (char **)realloc( p_item->ppsz_list_text, 
     1186                          (wave_devices+2) * sizeof(char *) ); 
     1187 
     1188    WAVEOUTCAPS caps; 
     1189    char sz_dev_name[MAXPNAMELEN+32]; 
     1190    int j=1; 
     1191    for(int i=0; i<wave_devices; i++) 
     1192    { 
     1193        if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS)) 
     1194           == MMSYSERR_NOERROR) 
     1195        { 
     1196          sprintf(sz_dev_name,psz_device_name_fmt,caps.szPname, 
     1197                                               caps.wMid, 
     1198                                               caps.wPid 
     1199                                              ); 
     1200          p_item->ppsz_list[j] = strdup( sz_dev_name ); 
     1201          p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name ); 
     1202          p_item->i_list++; 
     1203          j++; 
     1204        } 
     1205 
     1206    } 
     1207    p_item->ppsz_list[j] = NULL; 
     1208    p_item->ppsz_list_text[j] = NULL; 
     1209 
     1210    /* Signal change to the interface */ 
     1211    p_item->b_dirty = VLC_TRUE; 
     1212 
     1213    return VLC_SUCCESS; 
     1214} 
     1215 
     1216/* 
     1217  convert devicename to device ID for output 
     1218  if device not found return WAVE_MAPPER, so let 
     1219  windows decide which prefered audio device 
     1220  should be used. 
     1221*/ 
     1222static uint32_t findDeviceID(char *psz_device_name) 
     1223{ 
     1224    if(!psz_device_name) 
     1225       return WAVE_MAPPER; 
     1226 
     1227    uint32_t wave_devices = waveOutGetNumDevs(); 
     1228    WAVEOUTCAPS caps; 
     1229    char sz_dev_name[MAXPNAMELEN+32]; 
     1230    for(uint32_t i=0; i<wave_devices; i++) 
     1231    { 
     1232        if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS)) 
     1233           == MMSYSERR_NOERROR) 
     1234        { 
     1235            sprintf(sz_dev_name,psz_device_name_fmt,caps.szPname, 
     1236                                               caps.wMid, 
     1237                                               caps.wPid 
     1238                                              ); 
     1239            if(!stricmp(sz_dev_name,psz_device_name)) 
     1240               return i; 
     1241        } 
     1242    } 
     1243 
     1244    return WAVE_MAPPER; 
     1245}