1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2009 VLC authors and VideoLAN
7 * Authors: Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
41 #include <vlc_charset.h> /* FromWide() */
43 #include "audio_output/windows_audio_common.h"
45 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
47 /*****************************************************************************
49 *****************************************************************************/
50 static int Open ( vlc_object_t
* );
51 static void Close ( vlc_object_t
* );
52 static void Play ( audio_output_t
*, block_t
*, vlc_tick_t
);
54 /*****************************************************************************
55 * notification_thread_t: waveOut event thread
56 *****************************************************************************/
58 typedef struct aout_sys_t aout_sys_t
;
63 struct lkwavehdr
* p_next
;
67 static int OpenWaveOut ( audio_output_t
*, uint32_t,
68 int, int, int, int, bool );
69 static int OpenWaveOutPCM( audio_output_t
*, uint32_t,
70 vlc_fourcc_t
*, int, int, int, bool );
71 static int PlayWaveOut ( audio_output_t
*, HWAVEOUT
, struct lkwavehdr
*,
74 static void CALLBACK
WaveOutCallback ( HWAVEOUT
, UINT
, DWORD_PTR
, DWORD_PTR
, DWORD_PTR
);
76 static void WaveOutClean( aout_sys_t
* p_sys
);
78 static void WaveOutClearBuffer( HWAVEOUT
, WAVEHDR
*);
80 static int ReloadWaveoutDevices( const char *, char ***, char *** );
81 static uint32_t findDeviceID(char *);
82 static int WaveOutTimeGet(audio_output_t
* , vlc_tick_t
*);
83 static void WaveOutFlush( audio_output_t
*, bool);
84 static void WaveOutPause( audio_output_t
*, bool, vlc_tick_t
);
85 static int WaveoutVolumeSet(audio_output_t
* p_aout
, float volume
);
86 static int WaveoutMuteSet(audio_output_t
* p_aout
, bool mute
);
88 static void WaveoutPollVolume( void * );
90 static const wchar_t device_name_fmt
[] = L
"%ls ($%x,$%x)";
92 /*****************************************************************************
93 * aout_sys_t: waveOut audio output method descriptor
94 *****************************************************************************
95 * This structure is part of the audio output thread descriptor.
96 * It describes the waveOut specific properties of an audio device.
97 *****************************************************************************/
101 HWAVEOUT h_waveout
; /* handle to waveout instance */
103 WAVEFORMATEXTENSIBLE waveformat
; /* audio format */
107 int i_repeat_counter
;
113 uint8_t *p_silence_buffer
; /* buffer we use to play silence */
119 bool b_soft
; /* Use software gain */
120 uint8_t chans_to_reorder
; /* do we need channel reordering */
122 uint8_t chan_table
[AOUT_CHAN_MAX
];
125 vlc_tick_t i_played_length
;
127 struct lkwavehdr
* p_free_list
;
131 vlc_timer_t volume_poll_timer
;
134 /*****************************************************************************
136 *****************************************************************************/
137 #define DEVICE_TEXT N_("Select Audio Device")
138 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
139 "decide (default), change needs VLC restart "\
142 #define AUDIO_CHAN_TEXT N_("Audio output channels")
143 #define AUDIO_CHAN_LONGTEXT N_("Channels available for audio output. " \
144 "If the input has more channels than the output, it will be down-mixed. " \
145 "This parameter is ignored when digital pass-through is active.")
147 #define VOLUME_TEXT N_("Audio volume")
150 set_shortname( "WaveOut" )
151 set_description( N_("WaveOut audio output") )
152 set_capability( "audio output", 50 )
153 set_category( CAT_AUDIO
)
154 set_subcategory( SUBCAT_AUDIO_AOUT
)
155 add_string( "waveout-audio-device", "wavemapper",
156 DEVICE_TEXT
, DEVICE_LONG
, false )
157 change_string_cb( ReloadWaveoutDevices
)
158 add_float( "waveout-volume", 1.0f
, VOLUME_TEXT
, NULL
, true )
159 change_float_range(0.0f
, 2.0f
)
160 add_bool( "waveout-float32", true, FLOAT_TEXT
, FLOAT_LONGTEXT
, true )
161 add_integer ("waveout-audio-channels", 9, AUDIO_CHAN_TEXT
,
162 AUDIO_CHAN_LONGTEXT
, false)
163 change_integer_range(1,9)
164 set_callbacks( Open
, Close
)
167 /*****************************************************************************
168 * Opens the audio device
169 *****************************************************************************
170 * This function opens and setups Win32 waveOut
171 *****************************************************************************/
172 static int Start( audio_output_t
*p_aout
, audio_sample_format_t
*restrict fmt
)
174 if( aout_FormatNbChannels( fmt
) == 0 )
177 p_aout
->time_get
= WaveOutTimeGet
;
179 p_aout
->pause
= WaveOutPause
;
180 p_aout
->flush
= WaveOutFlush
;
182 aout_sys_t
*sys
= p_aout
->sys
;
184 /* Default behaviour is to use software gain */
187 char *dev
= var_GetNonEmptyString( p_aout
, "waveout-audio-device");
188 uint32_t devid
= findDeviceID( dev
);
190 if(devid
== WAVE_MAPPER
&& dev
!= NULL
&& stricmp(dev
,"wavemapper"))
191 msg_Warn( p_aout
, "configured audio device '%s' not available, "
192 "using default instead", dev
);
195 WAVEOUTCAPS waveoutcaps
;
196 if(waveOutGetDevCaps( devid
, &waveoutcaps
,
197 sizeof(WAVEOUTCAPS
)) == MMSYSERR_NOERROR
)
199 /* log debug some infos about driver, to know who to blame
200 if it doesn't work */
201 msg_Dbg( p_aout
, "Drivername: %ls", waveoutcaps
.szPname
);
202 msg_Dbg( p_aout
, "Driver Version: %d.%d",
203 (waveoutcaps
.vDriverVersion
>>8)&255,
204 waveoutcaps
.vDriverVersion
& 255);
205 msg_Dbg( p_aout
, "Manufacturer identifier: 0x%x", waveoutcaps
.wMid
);
206 msg_Dbg( p_aout
, "Product identifier: 0x%x", waveoutcaps
.wPid
);
211 /* Open the device */
212 if( AOUT_FMT_SPDIF(fmt
) && var_InheritBool (p_aout
, "spdif") )
215 if( OpenWaveOut( p_aout
, devid
, VLC_CODEC_SPDIFL
,
216 fmt
->i_physical_channels
,
217 aout_FormatNbChannels( fmt
), fmt
->i_rate
, false )
220 fmt
->i_format
= VLC_CODEC_SPDIFL
;
222 /* Calculate the frame size in bytes */
223 fmt
->i_bytes_per_frame
= AOUT_SPDIF_SIZE
;
224 fmt
->i_frame_length
= A52_FRAME_NB
;
225 sys
->i_buffer_size
= fmt
->i_bytes_per_frame
;
231 "cannot open waveout audio device for spdif fallback to PCM" );
234 if( fmt
->i_format
!= VLC_CODEC_SPDIFL
)
237 check for configured audio device!
239 fmt
->i_format
= var_InheritBool( p_aout
, "waveout-float32" )?
240 VLC_CODEC_FL32
: VLC_CODEC_S16N
;
242 int max_chan
= var_InheritInteger( p_aout
, "waveout-audio-channels");
243 int i_channels
= aout_FormatNbChannels(fmt
);
244 i_channels
= ( i_channels
< max_chan
)? i_channels
: max_chan
;
250 fmt
->i_physical_channels
= AOUT_CHANS_8_1
;
253 fmt
->i_physical_channels
= AOUT_CHANS_7_1
;
256 fmt
->i_physical_channels
= AOUT_CHANS_7_0
;
259 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
260 | AOUT_CHAN_CENTER
| AOUT_CHAN_REARLEFT
261 | AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE
;
264 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
265 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
269 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
270 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
;
273 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
277 fmt
->i_physical_channels
= AOUT_CHANS_STEREO
;
281 fmt
->i_physical_channels
= AOUT_CHAN_CENTER
;
283 msg_Dbg( p_aout
, "Trying %d channels", i_channels
);
285 while( ( OpenWaveOutPCM( p_aout
, devid
, &fmt
->i_format
,
286 fmt
->i_physical_channels
, i_channels
,
287 fmt
->i_rate
, false ) != VLC_SUCCESS
) &&
292 msg_Err(p_aout
, "Waveout couldn't find appropriate channel mapping");
296 /* Calculate the frame size in bytes */
297 aout_FormatPrepare( fmt
);
298 sys
->i_buffer_size
= FRAME_SIZE
* fmt
->i_bytes_per_frame
;
300 if( waveoutcaps
.dwSupport
& WAVECAPS_VOLUME
)
302 aout_GainRequest( p_aout
, 1.0f
);
306 WaveoutMuteSet( p_aout
, sys
->b_mute
);
308 sys
->b_spdif
= false;
311 sys
->i_rate
= fmt
->i_rate
;
313 waveOutReset( sys
->h_waveout
);
315 /* Allocate silence buffer */
316 sys
->p_silence_buffer
=
317 malloc( sys
->i_buffer_size
);
318 if( sys
->p_silence_buffer
== NULL
)
320 msg_Err( p_aout
, "Couldn't alloc silence buffer... aborting");
323 sys
->i_repeat_counter
= 0;
326 /* Zero the buffer. WinCE doesn't have calloc(). */
327 memset( sys
->p_silence_buffer
, 0,
328 sys
->i_buffer_size
);
330 /* Now we need to setup our waveOut play notification structure */
332 sys
->i_played_length
= 0;
333 sys
->p_free_list
= NULL
;
335 fmt
->channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
340 /*****************************************************************************
341 * Play: play a sound buffer
342 *****************************************************************************
343 * This doesn't actually play the buffer. This just stores the buffer so it
344 * can be played by the callback thread.
345 *****************************************************************************/
346 static void Play( audio_output_t
*p_aout
, block_t
*block
, vlc_tick_t date
)
348 aout_sys_t
*sys
= p_aout
->sys
;
350 struct lkwavehdr
* p_waveheader
=
351 (struct lkwavehdr
*) malloc(sizeof(struct lkwavehdr
));
354 msg_Err(p_aout
, "Couldn't alloc WAVEHDR");
356 block_Release( block
);
360 p_waveheader
->p_next
= NULL
;
362 if( block
&& sys
->chans_to_reorder
)
364 aout_ChannelReorder( block
->p_buffer
, block
->i_buffer
,
365 sys
->waveformat
.Format
.nChannels
,
366 sys
->chan_table
, sys
->format
);
368 while( PlayWaveOut( p_aout
, sys
->h_waveout
, p_waveheader
, block
,
369 sys
->b_spdif
) != VLC_SUCCESS
)
372 msg_Warn( p_aout
, "Couln't write frame... sleeping");
373 vlc_tick_sleep( block
->i_length
);
377 WaveoutPollVolume( p_aout
);
379 vlc_mutex_lock( &sys
->lock
);
381 sys
->i_played_length
+= block
->i_length
;
382 vlc_mutex_unlock( &sys
->lock
);
386 /*****************************************************************************
387 * Close: close the audio device
388 *****************************************************************************/
389 static void Stop( audio_output_t
*p_aout
)
391 aout_sys_t
*p_sys
= p_aout
->sys
;
393 /* Before calling waveOutClose we must reset the device */
394 MMRESULT result
= waveOutReset( p_sys
->h_waveout
);
395 if(result
!= MMSYSERR_NOERROR
)
397 msg_Err( p_aout
, "waveOutReset failed 0x%x", result
);
399 now we must wait, that all buffers are played
400 because cancel doesn't work in this case...
402 if(result
== MMSYSERR_NOTSUPPORTED
)
405 clear currently played (done) buffers,
406 if returnvalue > 0 (means some buffer still playing)
407 wait for the driver event callback that one buffer
408 is finished with playing, and check again
409 the timeout of 5000ms is just, an emergency exit
410 of this loop, to avoid deadlock in case of other
411 (currently not known bugs, problems, errors cases?)
413 WaveOutFlush( p_aout
, true );
417 /* wait for the frames to be queued in cleaning list */
418 WaveOutFlush( p_aout
, true );
419 WaveOutClean( p_sys
);
421 /* now we can Close the device */
422 if( waveOutClose( p_sys
->h_waveout
) != MMSYSERR_NOERROR
)
424 msg_Err( p_aout
, "waveOutClose failed" );
427 free( p_sys
->p_silence_buffer
);
428 p_sys
->i_played_length
= 0;
429 p_sys
->b_soft
= true;
432 /*****************************************************************************
433 * OpenWaveOut: open the waveout sound device
434 ****************************************************************************/
435 static int OpenWaveOut( audio_output_t
*p_aout
, uint32_t i_device_id
, int i_format
,
436 int i_channels
, int i_nb_channels
, int i_rate
,
440 aout_sys_t
*sys
= p_aout
->sys
;
442 /* Set sound format */
444 #define waveformat sys->waveformat
446 waveformat
.dwChannelMask
= 0;
447 for( unsigned i
= 0; pi_vlc_chan_order_wg4
[i
]; i
++ )
448 if( i_channels
& pi_vlc_chan_order_wg4
[i
] )
449 waveformat
.dwChannelMask
|= pi_channels_in
[i
];
453 case VLC_CODEC_SPDIFL
:
455 /* To prevent channel re-ordering */
456 waveformat
.dwChannelMask
= SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
;
457 waveformat
.Format
.wBitsPerSample
= 16;
458 waveformat
.Samples
.wValidBitsPerSample
=
459 waveformat
.Format
.wBitsPerSample
;
460 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_DOLBY_AC3_SPDIF
;
461 waveformat
.SubFormat
= __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF
;
465 waveformat
.Format
.wBitsPerSample
= sizeof(float) * 8;
466 waveformat
.Samples
.wValidBitsPerSample
=
467 waveformat
.Format
.wBitsPerSample
;
468 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_IEEE_FLOAT
;
469 waveformat
.SubFormat
= __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
473 waveformat
.Format
.wBitsPerSample
= 16;
474 waveformat
.Samples
.wValidBitsPerSample
=
475 waveformat
.Format
.wBitsPerSample
;
476 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
477 waveformat
.SubFormat
= __KSDATAFORMAT_SUBTYPE_PCM
;
481 waveformat
.Format
.nChannels
= i_nb_channels
;
482 waveformat
.Format
.nSamplesPerSec
= i_rate
;
483 waveformat
.Format
.nBlockAlign
=
484 waveformat
.Format
.wBitsPerSample
/ 8 * i_nb_channels
;
485 waveformat
.Format
.nAvgBytesPerSec
=
486 waveformat
.Format
.nSamplesPerSec
* waveformat
.Format
.nBlockAlign
;
488 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
489 if( i_nb_channels
<= 2 )
491 waveformat
.Format
.cbSize
= 0;
495 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
496 waveformat
.Format
.cbSize
=
497 sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
501 msg_Dbg( p_aout
, "OpenWaveDevice-ID: %u", i_device_id
);
502 msg_Dbg( p_aout
,"waveformat.Format.cbSize = %d",
503 waveformat
.Format
.cbSize
);
504 msg_Dbg( p_aout
,"waveformat.Format.wFormatTag = %u",
505 waveformat
.Format
.wFormatTag
);
506 msg_Dbg( p_aout
,"waveformat.Format.nChannels = %u",
507 waveformat
.Format
.nChannels
);
508 msg_Dbg( p_aout
,"waveformat.Format.nSamplesPerSec = %d",
509 (int)waveformat
.Format
.nSamplesPerSec
);
510 msg_Dbg( p_aout
,"waveformat.Format.nAvgBytesPerSec = %u",
511 (int)waveformat
.Format
.nAvgBytesPerSec
);
512 msg_Dbg( p_aout
,"waveformat.Format.nBlockAlign = %d",
513 waveformat
.Format
.nBlockAlign
);
514 msg_Dbg( p_aout
,"waveformat.Format.wBitsPerSample = %d",
515 waveformat
.Format
.wBitsPerSample
);
516 msg_Dbg( p_aout
,"waveformat.Samples.wValidBitsPerSample = %d",
517 waveformat
.Samples
.wValidBitsPerSample
);
518 msg_Dbg( p_aout
,"waveformat.Samples.wSamplesPerBlock = %d",
519 waveformat
.Samples
.wSamplesPerBlock
);
520 msg_Dbg( p_aout
,"waveformat.dwChannelMask = %u",
521 waveformat
.dwChannelMask
);
524 /* Open the device */
525 result
= waveOutOpen( &sys
->h_waveout
, i_device_id
,
526 (WAVEFORMATEX
*)&waveformat
,
527 (DWORD_PTR
)WaveOutCallback
, (DWORD_PTR
)p_aout
,
528 CALLBACK_FUNCTION
| (b_probe
?WAVE_FORMAT_QUERY
:0) );
529 if( result
== WAVERR_BADFORMAT
)
531 msg_Warn( p_aout
, "waveOutOpen failed WAVERR_BADFORMAT" );
534 if( result
== MMSYSERR_ALLOCATED
)
536 msg_Warn( p_aout
, "waveOutOpen failed WAVERR_ALLOCATED" );
539 if( result
!= MMSYSERR_NOERROR
)
541 msg_Warn( p_aout
, "waveOutOpen failed" );
545 sys
->chans_to_reorder
=
546 aout_CheckChannelReorder( pi_channels_in
, pi_channels_out
,
547 waveformat
.dwChannelMask
,
549 if( sys
->chans_to_reorder
)
550 msg_Dbg( p_aout
, "channel reordering needed" );
551 sys
->format
= i_format
;
559 /*****************************************************************************
560 * OpenWaveOutPCM: open a PCM waveout sound device
561 ****************************************************************************/
562 static int OpenWaveOutPCM( audio_output_t
*p_aout
, uint32_t i_device_id
,
563 vlc_fourcc_t
*i_format
,
564 int i_channels
, int i_nb_channels
, int i_rate
,
567 bool b_use_float32
= var_CreateGetBool( p_aout
, "waveout-float32");
569 if( !b_use_float32
|| OpenWaveOut( p_aout
, i_device_id
, VLC_CODEC_FL32
,
570 i_channels
, i_nb_channels
, i_rate
, b_probe
)
573 if ( OpenWaveOut( p_aout
, i_device_id
, VLC_CODEC_S16N
,
574 i_channels
, i_nb_channels
, i_rate
, b_probe
)
581 *i_format
= VLC_CODEC_S16N
;
587 *i_format
= VLC_CODEC_FL32
;
592 /*****************************************************************************
593 * PlayWaveOut: play a buffer through the WaveOut device
594 *****************************************************************************/
595 static int PlayWaveOut( audio_output_t
*p_aout
, HWAVEOUT h_waveout
,
596 struct lkwavehdr
*p_waveheader
, block_t
*p_buffer
, bool b_spdif
)
599 aout_sys_t
*sys
= p_aout
->sys
;
601 /* Prepare the buffer */
602 if( p_buffer
!= NULL
)
604 p_waveheader
->hdr
.lpData
= (LPSTR
)p_buffer
->p_buffer
;
605 p_waveheader
->hdr
.dwBufferLength
= p_buffer
->i_buffer
;
607 copy the buffer to the silence buffer :) so in case we don't
608 get the next buffer fast enough (I will repeat this one a time
609 for AC3 / DTS and SPDIF this will sound better instead of
614 memcpy( sys
->p_silence_buffer
,
616 sys
->i_buffer_size
);
617 sys
->i_repeat_counter
= 2;
620 /* Use silence buffer instead */
621 if(sys
->i_repeat_counter
)
623 sys
->i_repeat_counter
--;
624 if(!sys
->i_repeat_counter
)
626 memset( sys
->p_silence_buffer
,
627 0x00, sys
->i_buffer_size
);
630 p_waveheader
->hdr
.lpData
= (LPSTR
)sys
->p_silence_buffer
;
631 p_waveheader
->hdr
.dwBufferLength
= sys
->i_buffer_size
;
634 p_waveheader
->hdr
.dwUser
= p_buffer
? (DWORD_PTR
)p_buffer
: (DWORD_PTR
)1;
635 p_waveheader
->hdr
.dwFlags
= 0;
637 result
= waveOutPrepareHeader( h_waveout
, &p_waveheader
->hdr
, sizeof(WAVEHDR
) );
638 if( result
!= MMSYSERR_NOERROR
)
640 msg_Err( p_aout
, "waveOutPrepareHeader failed" );
644 /* Send the buffer to the waveOut queue */
645 result
= waveOutWrite( h_waveout
, &p_waveheader
->hdr
, sizeof(WAVEHDR
) );
646 if( result
!= MMSYSERR_NOERROR
)
648 msg_Err( p_aout
, "waveOutWrite failed" );
655 /*****************************************************************************
656 * WaveOutCallback: what to do once WaveOut has played its sound samples
657 *****************************************************************************/
658 static void CALLBACK
WaveOutCallback( HWAVEOUT h_waveout
, UINT uMsg
,
660 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
664 aout_sys_t
*sys
= ((audio_output_t
*)_p_aout
)->sys
;
665 struct lkwavehdr
* p_waveheader
= (struct lkwavehdr
*) dwParam1
;
667 if( uMsg
!= WOM_DONE
) return;
669 vlc_mutex_lock( &sys
->lock
);
670 p_waveheader
->p_next
= sys
->p_free_list
;
671 sys
->p_free_list
= p_waveheader
;
673 vlc_cond_broadcast( &sys
->cond
);
674 vlc_mutex_unlock( &sys
->lock
);
677 static void WaveOutClean( aout_sys_t
* p_sys
)
679 struct lkwavehdr
*p_whdr
, *p_list
;
681 vlc_mutex_lock(&p_sys
->lock
);
682 p_list
= p_sys
->p_free_list
;
683 p_sys
->p_free_list
= NULL
;
684 vlc_mutex_unlock(&p_sys
->lock
);
689 p_list
= p_list
->p_next
;
690 WaveOutClearBuffer( p_sys
->h_waveout
, &p_whdr
->hdr
);
695 static void WaveOutClearBuffer( HWAVEOUT h_waveout
, WAVEHDR
*p_waveheader
)
697 block_t
*p_buffer
= (block_t
*)(p_waveheader
->dwUser
);
698 /* Unprepare and free the buffers which has just been played */
699 waveOutUnprepareHeader( h_waveout
, p_waveheader
, sizeof(WAVEHDR
) );
701 if( p_waveheader
->dwUser
!= 1 )
702 block_Release( p_buffer
);
706 reload the configuration drop down list, of the Audio Devices
708 static int ReloadWaveoutDevices( char const *psz_name
,
709 char ***values
, char ***descs
)
711 int n
= 0, nb_devices
= waveOutGetNumDevs();
713 VLC_UNUSED( psz_name
);
715 *values
= xmalloc( (nb_devices
+ 1) * sizeof(char *) );
716 *descs
= xmalloc( (nb_devices
+ 1) * sizeof(char *) );
718 (*values
)[n
] = strdup( "wavemapper" );
719 (*descs
)[n
] = strdup( _("Microsoft Soundmapper") );
722 for(int i
= 0; i
< nb_devices
; i
++)
725 wchar_t dev_name
[MAXPNAMELEN
+32];
727 if(waveOutGetDevCaps(i
, &caps
, sizeof(WAVEOUTCAPS
))
731 _snwprintf(dev_name
, MAXPNAMELEN
+ 32, device_name_fmt
,
732 caps
.szPname
, caps
.wMid
, caps
.wPid
);
733 (*values
)[n
] = FromWide( dev_name
);
734 (*descs
)[n
] = strdup( (*values
)[n
] );
742 convert devicename to device ID for output
743 if device not found return WAVE_MAPPER, so let
744 windows decide which preferred audio device
747 static uint32_t findDeviceID(char *psz_device_name
)
749 if( !psz_device_name
)
752 uint32_t wave_devices
= waveOutGetNumDevs();
754 for( uint32_t i
= 0; i
< wave_devices
; i
++ )
757 wchar_t dev_name
[MAXPNAMELEN
+32];
759 if( waveOutGetDevCaps( i
, &caps
, sizeof(WAVEOUTCAPS
) )
760 != MMSYSERR_NOERROR
)
763 _snwprintf( dev_name
, MAXPNAMELEN
+ 32, device_name_fmt
,
764 caps
.szPname
, caps
.wMid
, caps
.wPid
);
765 char *u8
= FromWide(dev_name
);
766 if( !stricmp(u8
, psz_device_name
) )
777 static int DeviceSelect (audio_output_t
*aout
, const char *id
)
779 var_SetString(aout
, "waveout-audio-device", (id
!= NULL
) ? id
: "");
780 aout_DeviceReport (aout
, id
);
781 aout_RestartRequest (aout
, AOUT_RESTART_OUTPUT
);
785 static int Open(vlc_object_t
*obj
)
787 audio_output_t
*aout
= (audio_output_t
*)obj
;
788 aout_sys_t
*sys
= malloc(sizeof (*sys
));
790 if (unlikely(sys
== NULL
))
795 aout
->volume_set
= WaveoutVolumeSet
;
796 aout
->mute_set
= WaveoutMuteSet
;
797 aout
->device_select
= DeviceSelect
;
799 sys
->f_volume
= var_InheritFloat(aout
, "waveout-volume");
800 sys
->b_mute
= var_InheritBool(aout
, "mute");
802 aout_MuteReport(aout
, sys
->b_mute
);
803 aout_VolumeReport(aout
, sys
->f_volume
);
805 if( vlc_timer_create( &sys
->volume_poll_timer
,
806 WaveoutPollVolume
, aout
) )
808 msg_Err( aout
, "Couldn't create volume polling timer" );
813 vlc_mutex_init( &sys
->lock
);
814 vlc_cond_init( &sys
->cond
);
816 /* WaveOut does not support hot-plug events so list devices at startup */
818 int count
= ReloadWaveoutDevices(NULL
, &ids
, &names
);
821 for (int i
= 0; i
< count
; i
++)
823 aout_HotplugReport(aout
, ids
[i
], names
[i
]);
831 char *dev
= var_CreateGetNonEmptyString(aout
, "waveout-audio-device");
832 aout_DeviceReport(aout
, dev
);
838 static void Close(vlc_object_t
*obj
)
840 audio_output_t
*aout
= (audio_output_t
*)obj
;
841 aout_sys_t
*sys
= aout
->sys
;
843 var_Destroy(aout
, "waveout-audio-device");
845 vlc_timer_destroy( sys
->volume_poll_timer
);
846 vlc_cond_destroy( &sys
->cond
);
847 vlc_mutex_destroy( &sys
->lock
);
852 static int WaveOutTimeGet(audio_output_t
* p_aout
, vlc_tick_t
*delay
)
855 mmtime
.wType
= TIME_SAMPLES
;
856 aout_sys_t
*sys
= p_aout
->sys
;
861 if( waveOutGetPosition( sys
->h_waveout
, &mmtime
, sizeof(MMTIME
) )
862 != MMSYSERR_NOERROR
)
864 msg_Err( p_aout
, "waveOutGetPosition failed");
868 vlc_tick_t i_pos
= (vlc_tick_t
) mmtime
.u
.sample
* CLOCK_FREQ
/ sys
->i_rate
;
869 *delay
= sys
->i_played_length
- i_pos
;
873 static void WaveOutFlush( audio_output_t
*p_aout
, bool wait
)
876 aout_sys_t
*sys
= p_aout
->sys
;
880 res
= waveOutReset( sys
->h_waveout
);
881 sys
->i_played_length
= 0;
882 if( res
!= MMSYSERR_NOERROR
)
883 msg_Err( p_aout
, "waveOutReset failed");
887 vlc_mutex_lock( &sys
->lock
);
888 while( sys
->i_frames
)
890 vlc_cond_wait( &sys
->cond
, &sys
->lock
);
892 vlc_mutex_unlock( &sys
->lock
);
896 static void WaveOutPause( audio_output_t
* p_aout
, bool pause
, vlc_tick_t date
)
900 aout_sys_t
*sys
= p_aout
->sys
;
904 vlc_timer_schedule_asap( sys
->volume_poll_timer
, VLC_TICK_FROM_MS(200) );
905 res
= waveOutPause( sys
->h_waveout
);
906 if( res
!= MMSYSERR_NOERROR
)
908 msg_Err( p_aout
, "waveOutPause failed (0x%x)", res
);
914 vlc_timer_disarm( sys
->volume_poll_timer
);
915 res
= waveOutRestart( sys
->h_waveout
);
916 if( res
!= MMSYSERR_NOERROR
)
918 msg_Err( p_aout
, "waveOutRestart failed (0x%x)", res
);
924 static int WaveoutVolumeSet( audio_output_t
*p_aout
, float volume
)
926 aout_sys_t
*sys
= p_aout
->sys
;
930 float gain
= volume
* volume
* volume
;
931 if ( !sys
->b_mute
&& aout_GainRequest( p_aout
, gain
) )
936 const HWAVEOUT hwo
= sys
->h_waveout
;
938 uint32_t vol
= lroundf( volume
* 0x7fff.fp0
);
948 MMRESULT r
= waveOutSetVolume( hwo
, vol
| ( vol
<< 16 ) );
949 if( r
!= MMSYSERR_NOERROR
)
951 msg_Err( p_aout
, "waveOutSetVolume failed (%u)", r
);
957 vlc_mutex_lock(&sys
->lock
);
958 sys
->f_volume
= volume
;
960 if( var_InheritBool( p_aout
, "volume-save" ) )
961 config_PutFloat( "waveout-volume", volume
);
963 aout_VolumeReport( p_aout
, volume
);
964 vlc_mutex_unlock(&sys
->lock
);
969 static int WaveoutMuteSet( audio_output_t
* p_aout
, bool mute
)
971 aout_sys_t
*sys
= p_aout
->sys
;
975 float gain
= sys
->f_volume
* sys
->f_volume
* sys
->f_volume
;
976 if ( aout_GainRequest( p_aout
, mute
? 0.f
: gain
) )
982 const HWAVEOUT hwo
= sys
->h_waveout
;
983 uint32_t vol
= mute
? 0 : lroundf( sys
->f_volume
* 0x7fff.fp0
);
988 MMRESULT r
= waveOutSetVolume( hwo
, vol
| ( vol
<< 16 ) );
989 if( r
!= MMSYSERR_NOERROR
)
991 msg_Err( p_aout
, "waveOutSetVolume failed (%u)", r
);
996 vlc_mutex_lock(&sys
->lock
);
998 aout_MuteReport( p_aout
, mute
);
999 vlc_mutex_unlock(&sys
->lock
);
1004 static void WaveoutPollVolume( void * _aout
)
1006 audio_output_t
* aout
= (audio_output_t
*) _aout
;
1007 aout_sys_t
*sys
= aout
->sys
;
1010 MMRESULT r
= waveOutGetVolume( sys
->h_waveout
, (LPDWORD
) &vol
);
1012 if( r
!= MMSYSERR_NOERROR
)
1014 msg_Err( aout
, "waveOutGetVolume failed (%u)", r
);
1018 float volume
= (float) ( vol
& UINT32_C( 0xffff ) );
1019 volume
/= 0x7fff.fp0
;
1021 vlc_mutex_lock(&sys
->lock
);
1022 if( !sys
->b_mute
&& volume
!= sys
->f_volume
)
1024 sys
->f_volume
= volume
;
1026 if( var_InheritBool( aout
, "volume-save" ) )
1027 config_PutFloat( "waveout-volume", volume
);
1029 aout_VolumeReport( aout
, volume
);
1031 vlc_mutex_unlock(&sys
->lock
);