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
* );
54 /*****************************************************************************
55 * notification_thread_t: waveOut event thread
56 *****************************************************************************/
60 struct lkwavehdr
* p_next
;
64 static int OpenWaveOut ( audio_output_t
*, uint32_t,
65 int, int, int, int, bool );
66 static int OpenWaveOutPCM( audio_output_t
*, uint32_t,
67 vlc_fourcc_t
*, int, int, int, bool );
68 static int PlayWaveOut ( audio_output_t
*, HWAVEOUT
, struct lkwavehdr
*,
71 static void CALLBACK
WaveOutCallback ( HWAVEOUT
, UINT
, DWORD_PTR
, DWORD_PTR
, DWORD_PTR
);
73 static void WaveOutClean( aout_sys_t
* p_sys
);
75 static void WaveOutClearBuffer( HWAVEOUT
, WAVEHDR
*);
77 static int ReloadWaveoutDevices( vlc_object_t
*, const char *,
79 static uint32_t findDeviceID(char *);
80 static int WaveOutTimeGet(audio_output_t
* , mtime_t
*);
81 static void WaveOutFlush( audio_output_t
*, bool);
82 static void WaveOutPause( audio_output_t
*, bool, mtime_t
);
83 static int WaveoutVolumeSet(audio_output_t
* p_aout
, float volume
);
84 static int WaveoutMuteSet(audio_output_t
* p_aout
, bool mute
);
86 static void WaveoutPollVolume( void * );
88 static const wchar_t device_name_fmt
[] = L
"%ls ($%x,$%x)";
90 /*****************************************************************************
91 * aout_sys_t: waveOut audio output method descriptor
92 *****************************************************************************
93 * This structure is part of the audio output thread descriptor.
94 * It describes the waveOut specific properties of an audio device.
95 *****************************************************************************/
99 HWAVEOUT h_waveout
; /* handle to waveout instance */
101 WAVEFORMATEXTENSIBLE waveformat
; /* audio format */
105 int i_repeat_counter
;
111 uint8_t *p_silence_buffer
; /* buffer we use to play silence */
117 bool b_soft
; /* Use software gain */
118 uint8_t chans_to_reorder
; /* do we need channel reordering */
120 uint8_t chan_table
[AOUT_CHAN_MAX
];
123 mtime_t i_played_length
;
125 struct lkwavehdr
* p_free_list
;
129 vlc_timer_t volume_poll_timer
;
132 /*****************************************************************************
134 *****************************************************************************/
135 #define DEVICE_TEXT N_("Select Audio Device")
136 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
137 "decide (default), change needs VLC restart "\
140 #define AUDIO_CHAN_TEXT N_("Audio output channels")
141 #define AUDIO_CHAN_LONGTEXT N_("Channels available for audio output. " \
142 "If the input has more channels than the output, it will be down-mixed. " \
143 "This parameter is ignored when digital pass-through is active.")
145 #define VOLUME_TEXT N_("Audio volume")
148 set_shortname( "WaveOut" )
149 set_description( N_("WaveOut audio output") )
150 set_capability( "audio output", 50 )
151 set_category( CAT_AUDIO
)
152 set_subcategory( SUBCAT_AUDIO_AOUT
)
153 add_string( "waveout-audio-device", "wavemapper",
154 DEVICE_TEXT
, DEVICE_LONG
, false )
155 change_string_cb( ReloadWaveoutDevices
)
156 add_float( "waveout-volume", 1.0f
, VOLUME_TEXT
, NULL
, true )
157 change_float_range(0.0f
, 2.0f
)
158 add_bool( "waveout-float32", true, FLOAT_TEXT
, FLOAT_LONGTEXT
, true )
159 add_integer ("waveout-audio-channels", 9, AUDIO_CHAN_TEXT
,
160 AUDIO_CHAN_LONGTEXT
, false)
161 change_integer_range(1,9)
162 set_callbacks( Open
, Close
)
165 /*****************************************************************************
166 * Opens the audio device
167 *****************************************************************************
168 * This function opens and setups Win32 waveOut
169 *****************************************************************************/
170 static int Start( audio_output_t
*p_aout
, audio_sample_format_t
*restrict fmt
)
172 if( aout_FormatNbChannels( fmt
) == 0 )
175 p_aout
->time_get
= WaveOutTimeGet
;
177 p_aout
->pause
= WaveOutPause
;
178 p_aout
->flush
= WaveOutFlush
;
180 /* Default behaviour is to use software gain */
181 p_aout
->sys
->b_soft
= true;
183 char *dev
= var_GetNonEmptyString( p_aout
, "waveout-audio-device");
184 uint32_t devid
= findDeviceID( dev
);
186 if(devid
== WAVE_MAPPER
&& dev
!= NULL
&& stricmp(dev
,"wavemapper"))
187 msg_Warn( p_aout
, "configured audio device '%s' not available, "
188 "using default instead", dev
);
191 WAVEOUTCAPS waveoutcaps
;
192 if(waveOutGetDevCaps( devid
, &waveoutcaps
,
193 sizeof(WAVEOUTCAPS
)) == MMSYSERR_NOERROR
)
195 /* log debug some infos about driver, to know who to blame
196 if it doesn't work */
197 msg_Dbg( p_aout
, "Drivername: %ls", waveoutcaps
.szPname
);
198 msg_Dbg( p_aout
, "Driver Version: %d.%d",
199 (waveoutcaps
.vDriverVersion
>>8)&255,
200 waveoutcaps
.vDriverVersion
& 255);
201 msg_Dbg( p_aout
, "Manufacturer identifier: 0x%x", waveoutcaps
.wMid
);
202 msg_Dbg( p_aout
, "Product identifier: 0x%x", waveoutcaps
.wPid
);
207 /* Open the device */
208 if( AOUT_FMT_SPDIF(fmt
) && var_InheritBool (p_aout
, "spdif") )
211 if( OpenWaveOut( p_aout
, devid
, VLC_CODEC_SPDIFL
,
212 fmt
->i_physical_channels
,
213 aout_FormatNbChannels( fmt
), fmt
->i_rate
, false )
216 fmt
->i_format
= VLC_CODEC_SPDIFL
;
218 /* Calculate the frame size in bytes */
219 fmt
->i_bytes_per_frame
= AOUT_SPDIF_SIZE
;
220 fmt
->i_frame_length
= A52_FRAME_NB
;
221 p_aout
->sys
->i_buffer_size
= fmt
->i_bytes_per_frame
;
222 p_aout
->sys
->b_spdif
= true;
227 "cannot open waveout audio device for spdif fallback to PCM" );
230 if( fmt
->i_format
!= VLC_CODEC_SPDIFL
)
233 check for configured audio device!
235 fmt
->i_format
= var_InheritBool( p_aout
, "waveout-float32" )?
236 VLC_CODEC_FL32
: VLC_CODEC_S16N
;
238 int max_chan
= var_InheritInteger( p_aout
, "waveout-audio-channels");
239 int i_channels
= aout_FormatNbChannels(fmt
);
240 i_channels
= ( i_channels
< max_chan
)? i_channels
: max_chan
;
246 fmt
->i_physical_channels
= AOUT_CHANS_8_1
;
249 fmt
->i_physical_channels
= AOUT_CHANS_7_1
;
252 fmt
->i_physical_channels
= AOUT_CHANS_7_0
;
255 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
256 | AOUT_CHAN_CENTER
| AOUT_CHAN_REARLEFT
257 | AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE
;
260 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
261 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
265 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
266 | AOUT_CHAN_REARLEFT
| AOUT_CHAN_REARRIGHT
;
269 fmt
->i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
273 fmt
->i_physical_channels
= AOUT_CHANS_STEREO
;
277 fmt
->i_physical_channels
= AOUT_CHAN_CENTER
;
279 msg_Dbg( p_aout
, "Trying %d channels", i_channels
);
281 while( ( OpenWaveOutPCM( p_aout
, devid
, &fmt
->i_format
,
282 fmt
->i_physical_channels
, i_channels
,
283 fmt
->i_rate
, false ) != VLC_SUCCESS
) &&
288 msg_Err(p_aout
, "Waveout couldn't find appropriate channel mapping");
292 /* Calculate the frame size in bytes */
293 aout_FormatPrepare( fmt
);
294 p_aout
->sys
->i_buffer_size
= FRAME_SIZE
* fmt
->i_bytes_per_frame
;
296 if( waveoutcaps
.dwSupport
& WAVECAPS_VOLUME
)
298 aout_GainRequest( p_aout
, 1.0f
);
299 p_aout
->sys
->b_soft
= false;
302 WaveoutMuteSet( p_aout
, p_aout
->sys
->b_mute
);
304 p_aout
->sys
->b_spdif
= false;
307 p_aout
->sys
->i_rate
= fmt
->i_rate
;
309 waveOutReset( p_aout
->sys
->h_waveout
);
311 /* Allocate silence buffer */
312 p_aout
->sys
->p_silence_buffer
=
313 malloc( p_aout
->sys
->i_buffer_size
);
314 if( p_aout
->sys
->p_silence_buffer
== NULL
)
316 msg_Err( p_aout
, "Couldn't alloc silence buffer... aborting");
319 p_aout
->sys
->i_repeat_counter
= 0;
322 /* Zero the buffer. WinCE doesn't have calloc(). */
323 memset( p_aout
->sys
->p_silence_buffer
, 0,
324 p_aout
->sys
->i_buffer_size
);
326 /* Now we need to setup our waveOut play notification structure */
327 p_aout
->sys
->i_frames
= 0;
328 p_aout
->sys
->i_played_length
= 0;
329 p_aout
->sys
->p_free_list
= NULL
;
334 /*****************************************************************************
335 * Play: play a sound buffer
336 *****************************************************************************
337 * This doesn't actually play the buffer. This just stores the buffer so it
338 * can be played by the callback thread.
339 *****************************************************************************/
340 static void Play( audio_output_t
*p_aout
, block_t
*block
)
342 struct lkwavehdr
* p_waveheader
=
343 (struct lkwavehdr
*) malloc(sizeof(struct lkwavehdr
));
346 msg_Err(p_aout
, "Couldn't alloc WAVEHDR");
348 block_Release( block
);
352 p_waveheader
->p_next
= NULL
;
354 if( block
&& p_aout
->sys
->chans_to_reorder
)
356 aout_ChannelReorder( block
->p_buffer
, block
->i_buffer
,
357 p_aout
->sys
->waveformat
.Format
.nChannels
,
358 p_aout
->sys
->chan_table
, p_aout
->sys
->format
);
360 while( PlayWaveOut( p_aout
, p_aout
->sys
->h_waveout
, p_waveheader
, block
,
361 p_aout
->sys
->b_spdif
) != VLC_SUCCESS
)
364 msg_Warn( p_aout
, "Couln't write frame... sleeping");
365 msleep( block
->i_length
);
368 WaveOutClean( p_aout
->sys
);
369 WaveoutPollVolume( p_aout
);
371 vlc_mutex_lock( &p_aout
->sys
->lock
);
372 p_aout
->sys
->i_frames
++;
373 p_aout
->sys
->i_played_length
+= block
->i_length
;
374 vlc_mutex_unlock( &p_aout
->sys
->lock
);
377 /*****************************************************************************
378 * Close: close the audio device
379 *****************************************************************************/
380 static void Stop( audio_output_t
*p_aout
)
382 aout_sys_t
*p_sys
= p_aout
->sys
;
384 /* Before calling waveOutClose we must reset the device */
385 MMRESULT result
= waveOutReset( p_sys
->h_waveout
);
386 if(result
!= MMSYSERR_NOERROR
)
388 msg_Err( p_aout
, "waveOutReset failed 0x%x", result
);
390 now we must wait, that all buffers are played
391 because cancel doesn't work in this case...
393 if(result
== MMSYSERR_NOTSUPPORTED
)
396 clear currently played (done) buffers,
397 if returnvalue > 0 (means some buffer still playing)
398 wait for the driver event callback that one buffer
399 is finished with playing, and check again
400 the timeout of 5000ms is just, an emergency exit
401 of this loop, to avoid deadlock in case of other
402 (currently not known bugs, problems, errors cases?)
404 WaveOutFlush( p_aout
, true );
408 /* wait for the frames to be queued in cleaning list */
409 WaveOutFlush( p_aout
, true );
410 WaveOutClean( p_aout
->sys
);
412 /* now we can Close the device */
413 if( waveOutClose( p_sys
->h_waveout
) != MMSYSERR_NOERROR
)
415 msg_Err( p_aout
, "waveOutClose failed" );
418 free( p_sys
->p_silence_buffer
);
419 p_aout
->sys
->i_played_length
= 0;
420 p_sys
->b_soft
= true;
423 /*****************************************************************************
424 * OpenWaveOut: open the waveout sound device
425 ****************************************************************************/
426 static int OpenWaveOut( audio_output_t
*p_aout
, uint32_t i_device_id
, int i_format
,
427 int i_channels
, int i_nb_channels
, int i_rate
,
432 /* Set sound format */
434 #define waveformat p_aout->sys->waveformat
436 waveformat
.dwChannelMask
= 0;
437 for( unsigned i
= 0; pi_vlc_chan_order_wg4
[i
]; i
++ )
438 if( i_channels
& pi_vlc_chan_order_wg4
[i
] )
439 waveformat
.dwChannelMask
|= pi_channels_in
[i
];
443 case VLC_CODEC_SPDIFL
:
445 /* To prevent channel re-ordering */
446 waveformat
.dwChannelMask
= SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
;
447 waveformat
.Format
.wBitsPerSample
= 16;
448 waveformat
.Samples
.wValidBitsPerSample
=
449 waveformat
.Format
.wBitsPerSample
;
450 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_DOLBY_AC3_SPDIF
;
451 waveformat
.SubFormat
= __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF
;
455 waveformat
.Format
.wBitsPerSample
= sizeof(float) * 8;
456 waveformat
.Samples
.wValidBitsPerSample
=
457 waveformat
.Format
.wBitsPerSample
;
458 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_IEEE_FLOAT
;
459 waveformat
.SubFormat
= __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
463 waveformat
.Format
.wBitsPerSample
= 16;
464 waveformat
.Samples
.wValidBitsPerSample
=
465 waveformat
.Format
.wBitsPerSample
;
466 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
467 waveformat
.SubFormat
= __KSDATAFORMAT_SUBTYPE_PCM
;
471 waveformat
.Format
.nChannels
= i_nb_channels
;
472 waveformat
.Format
.nSamplesPerSec
= i_rate
;
473 waveformat
.Format
.nBlockAlign
=
474 waveformat
.Format
.wBitsPerSample
/ 8 * i_nb_channels
;
475 waveformat
.Format
.nAvgBytesPerSec
=
476 waveformat
.Format
.nSamplesPerSec
* waveformat
.Format
.nBlockAlign
;
478 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
479 if( i_nb_channels
<= 2 )
481 waveformat
.Format
.cbSize
= 0;
485 waveformat
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
486 waveformat
.Format
.cbSize
=
487 sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
491 msg_Dbg( p_aout
, "OpenWaveDevice-ID: %u", i_device_id
);
492 msg_Dbg( p_aout
,"waveformat.Format.cbSize = %d",
493 waveformat
.Format
.cbSize
);
494 msg_Dbg( p_aout
,"waveformat.Format.wFormatTag = %u",
495 waveformat
.Format
.wFormatTag
);
496 msg_Dbg( p_aout
,"waveformat.Format.nChannels = %u",
497 waveformat
.Format
.nChannels
);
498 msg_Dbg( p_aout
,"waveformat.Format.nSamplesPerSec = %d",
499 (int)waveformat
.Format
.nSamplesPerSec
);
500 msg_Dbg( p_aout
,"waveformat.Format.nAvgBytesPerSec = %u",
501 (int)waveformat
.Format
.nAvgBytesPerSec
);
502 msg_Dbg( p_aout
,"waveformat.Format.nBlockAlign = %d",
503 waveformat
.Format
.nBlockAlign
);
504 msg_Dbg( p_aout
,"waveformat.Format.wBitsPerSample = %d",
505 waveformat
.Format
.wBitsPerSample
);
506 msg_Dbg( p_aout
,"waveformat.Samples.wValidBitsPerSample = %d",
507 waveformat
.Samples
.wValidBitsPerSample
);
508 msg_Dbg( p_aout
,"waveformat.Samples.wSamplesPerBlock = %d",
509 waveformat
.Samples
.wSamplesPerBlock
);
510 msg_Dbg( p_aout
,"waveformat.dwChannelMask = %u",
511 waveformat
.dwChannelMask
);
514 /* Open the device */
515 result
= waveOutOpen( &p_aout
->sys
->h_waveout
, i_device_id
,
516 (WAVEFORMATEX
*)&waveformat
,
517 (DWORD_PTR
)WaveOutCallback
, (DWORD_PTR
)p_aout
,
518 CALLBACK_FUNCTION
| (b_probe
?WAVE_FORMAT_QUERY
:0) );
519 if( result
== WAVERR_BADFORMAT
)
521 msg_Warn( p_aout
, "waveOutOpen failed WAVERR_BADFORMAT" );
524 if( result
== MMSYSERR_ALLOCATED
)
526 msg_Warn( p_aout
, "waveOutOpen failed WAVERR_ALLOCATED" );
529 if( result
!= MMSYSERR_NOERROR
)
531 msg_Warn( p_aout
, "waveOutOpen failed" );
535 p_aout
->sys
->chans_to_reorder
=
536 aout_CheckChannelReorder( pi_channels_in
, pi_channels_out
,
537 waveformat
.dwChannelMask
,
538 p_aout
->sys
->chan_table
);
539 if( p_aout
->sys
->chans_to_reorder
)
540 msg_Dbg( p_aout
, "channel reordering needed" );
541 p_aout
->sys
->format
= i_format
;
549 /*****************************************************************************
550 * OpenWaveOutPCM: open a PCM waveout sound device
551 ****************************************************************************/
552 static int OpenWaveOutPCM( audio_output_t
*p_aout
, uint32_t i_device_id
,
553 vlc_fourcc_t
*i_format
,
554 int i_channels
, int i_nb_channels
, int i_rate
,
557 bool b_use_float32
= var_CreateGetBool( p_aout
, "waveout-float32");
559 if( !b_use_float32
|| OpenWaveOut( p_aout
, i_device_id
, VLC_CODEC_FL32
,
560 i_channels
, i_nb_channels
, i_rate
, b_probe
)
563 if ( OpenWaveOut( p_aout
, i_device_id
, VLC_CODEC_S16N
,
564 i_channels
, i_nb_channels
, i_rate
, b_probe
)
571 *i_format
= VLC_CODEC_S16N
;
577 *i_format
= VLC_CODEC_FL32
;
582 /*****************************************************************************
583 * PlayWaveOut: play a buffer through the WaveOut device
584 *****************************************************************************/
585 static int PlayWaveOut( audio_output_t
*p_aout
, HWAVEOUT h_waveout
,
586 struct lkwavehdr
*p_waveheader
, block_t
*p_buffer
, bool b_spdif
)
590 /* Prepare the buffer */
591 if( p_buffer
!= NULL
)
593 p_waveheader
->hdr
.lpData
= (LPSTR
)p_buffer
->p_buffer
;
594 p_waveheader
->hdr
.dwBufferLength
= p_buffer
->i_buffer
;
596 copy the buffer to the silence buffer :) so in case we don't
597 get the next buffer fast enough (I will repeat this one a time
598 for AC3 / DTS and SPDIF this will sound better instead of
603 memcpy( p_aout
->sys
->p_silence_buffer
,
605 p_aout
->sys
->i_buffer_size
);
606 p_aout
->sys
->i_repeat_counter
= 2;
609 /* Use silence buffer instead */
610 if(p_aout
->sys
->i_repeat_counter
)
612 p_aout
->sys
->i_repeat_counter
--;
613 if(!p_aout
->sys
->i_repeat_counter
)
615 memset( p_aout
->sys
->p_silence_buffer
,
616 0x00, p_aout
->sys
->i_buffer_size
);
619 p_waveheader
->hdr
.lpData
= (LPSTR
)p_aout
->sys
->p_silence_buffer
;
620 p_waveheader
->hdr
.dwBufferLength
= p_aout
->sys
->i_buffer_size
;
623 p_waveheader
->hdr
.dwUser
= p_buffer
? (DWORD_PTR
)p_buffer
: (DWORD_PTR
)1;
624 p_waveheader
->hdr
.dwFlags
= 0;
626 result
= waveOutPrepareHeader( h_waveout
, &p_waveheader
->hdr
, sizeof(WAVEHDR
) );
627 if( result
!= MMSYSERR_NOERROR
)
629 msg_Err( p_aout
, "waveOutPrepareHeader failed" );
633 /* Send the buffer to the waveOut queue */
634 result
= waveOutWrite( h_waveout
, &p_waveheader
->hdr
, sizeof(WAVEHDR
) );
635 if( result
!= MMSYSERR_NOERROR
)
637 msg_Err( p_aout
, "waveOutWrite failed" );
644 /*****************************************************************************
645 * WaveOutCallback: what to do once WaveOut has played its sound samples
646 *****************************************************************************/
647 static void CALLBACK
WaveOutCallback( HWAVEOUT h_waveout
, UINT uMsg
,
649 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
653 audio_output_t
*p_aout
= (audio_output_t
*)_p_aout
;
654 struct lkwavehdr
* p_waveheader
= (struct lkwavehdr
*) dwParam1
;
656 if( uMsg
!= WOM_DONE
) return;
658 vlc_mutex_lock( &p_aout
->sys
->lock
);
659 p_waveheader
->p_next
= p_aout
->sys
->p_free_list
;
660 p_aout
->sys
->p_free_list
= p_waveheader
;
661 p_aout
->sys
->i_frames
--;
662 vlc_cond_broadcast( &p_aout
->sys
->cond
);
663 vlc_mutex_unlock( &p_aout
->sys
->lock
);
666 static void WaveOutClean( aout_sys_t
* p_sys
)
668 struct lkwavehdr
*p_whdr
, *p_list
;
670 vlc_mutex_lock(&p_sys
->lock
);
671 p_list
= p_sys
->p_free_list
;
672 p_sys
->p_free_list
= NULL
;
673 vlc_mutex_unlock(&p_sys
->lock
);
678 p_list
= p_list
->p_next
;
679 WaveOutClearBuffer( p_sys
->h_waveout
, &p_whdr
->hdr
);
684 static void WaveOutClearBuffer( HWAVEOUT h_waveout
, WAVEHDR
*p_waveheader
)
686 block_t
*p_buffer
= (block_t
*)(p_waveheader
->dwUser
);
687 /* Unprepare and free the buffers which has just been played */
688 waveOutUnprepareHeader( h_waveout
, p_waveheader
, sizeof(WAVEHDR
) );
690 if( p_waveheader
->dwUser
!= 1 )
691 block_Release( p_buffer
);
695 reload the configuration drop down list, of the Audio Devices
697 static int ReloadWaveoutDevices( vlc_object_t
*p_this
, char const *psz_name
,
698 char ***values
, char ***descs
)
700 int n
= 0, nb_devices
= waveOutGetNumDevs();
702 VLC_UNUSED( p_this
); VLC_UNUSED( psz_name
);
704 *values
= xmalloc( (nb_devices
+ 1) * sizeof(char *) );
705 *descs
= xmalloc( (nb_devices
+ 1) * sizeof(char *) );
707 (*values
)[n
] = strdup( "wavemapper" );
708 (*descs
)[n
] = strdup( _("Microsoft Soundmapper") );
711 for(int i
= 0; i
< nb_devices
; i
++)
714 wchar_t dev_name
[MAXPNAMELEN
+32];
716 if(waveOutGetDevCaps(i
, &caps
, sizeof(WAVEOUTCAPS
))
720 _snwprintf(dev_name
, MAXPNAMELEN
+ 32, device_name_fmt
,
721 caps
.szPname
, caps
.wMid
, caps
.wPid
);
722 (*values
)[n
] = FromWide( dev_name
);
723 (*descs
)[n
] = strdup( (*values
)[n
] );
731 convert devicename to device ID for output
732 if device not found return WAVE_MAPPER, so let
733 windows decide which preferred audio device
736 static uint32_t findDeviceID(char *psz_device_name
)
738 if( !psz_device_name
)
741 uint32_t wave_devices
= waveOutGetNumDevs();
743 for( uint32_t i
= 0; i
< wave_devices
; i
++ )
746 wchar_t dev_name
[MAXPNAMELEN
+32];
748 if( waveOutGetDevCaps( i
, &caps
, sizeof(WAVEOUTCAPS
) )
749 != MMSYSERR_NOERROR
)
752 _snwprintf( dev_name
, MAXPNAMELEN
+ 32, device_name_fmt
,
753 caps
.szPname
, caps
.wMid
, caps
.wPid
);
754 char *u8
= FromWide(dev_name
);
755 if( !stricmp(u8
, psz_device_name
) )
766 static int DeviceSelect (audio_output_t
*aout
, const char *id
)
768 var_SetString(aout
, "waveout-audio-device", (id
!= NULL
) ? id
: "");
769 aout_DeviceReport (aout
, id
);
770 aout_RestartRequest (aout
, AOUT_RESTART_OUTPUT
);
774 static int Open(vlc_object_t
*obj
)
776 audio_output_t
*aout
= (audio_output_t
*)obj
;
777 aout_sys_t
*sys
= malloc(sizeof (*sys
));
779 if (unlikely(sys
== NULL
))
784 aout
->volume_set
= WaveoutVolumeSet
;
785 aout
->mute_set
= WaveoutMuteSet
;
786 aout
->device_select
= DeviceSelect
;
788 sys
->f_volume
= var_InheritFloat(aout
, "waveout-volume");
789 sys
->b_mute
= var_InheritBool(aout
, "mute");
791 aout_MuteReport(aout
, sys
->b_mute
);
792 aout_VolumeReport(aout
, sys
->f_volume
);
794 if( vlc_timer_create( &sys
->volume_poll_timer
,
795 WaveoutPollVolume
, aout
) )
797 msg_Err( aout
, "Couldn't create volume polling timer" );
802 vlc_mutex_init( &sys
->lock
);
803 vlc_cond_init( &sys
->cond
);
805 /* WaveOut does not support hot-plug events so list devices at startup */
807 int count
= ReloadWaveoutDevices(VLC_OBJECT(aout
), NULL
, &ids
, &names
);
810 for (int i
= 0; i
< count
; i
++)
812 aout_HotplugReport(aout
, ids
[i
], names
[i
]);
820 char *dev
= var_CreateGetNonEmptyString(aout
, "waveout-audio-device");
821 aout_DeviceReport(aout
, dev
);
827 static void Close(vlc_object_t
*obj
)
829 audio_output_t
*aout
= (audio_output_t
*)obj
;
830 aout_sys_t
*sys
= aout
->sys
;
832 var_Destroy(aout
, "waveout-audio-device");
834 vlc_timer_destroy( sys
->volume_poll_timer
);
835 vlc_cond_destroy( &sys
->cond
);
836 vlc_mutex_destroy( &sys
->lock
);
841 static int WaveOutTimeGet(audio_output_t
* p_aout
, mtime_t
*delay
)
844 mmtime
.wType
= TIME_SAMPLES
;
846 if( !p_aout
->sys
->i_frames
)
849 if( waveOutGetPosition( p_aout
->sys
->h_waveout
, &mmtime
, sizeof(MMTIME
) )
850 != MMSYSERR_NOERROR
)
852 msg_Err( p_aout
, "waveOutGetPosition failed");
856 mtime_t i_pos
= (mtime_t
) mmtime
.u
.sample
* CLOCK_FREQ
/ p_aout
->sys
->i_rate
;
857 *delay
= p_aout
->sys
->i_played_length
- i_pos
;
861 static void WaveOutFlush( audio_output_t
*p_aout
, bool wait
)
866 res
= waveOutReset( p_aout
->sys
->h_waveout
);
867 p_aout
->sys
->i_played_length
= 0;
868 if( res
!= MMSYSERR_NOERROR
)
869 msg_Err( p_aout
, "waveOutReset failed");
873 vlc_mutex_lock( &p_aout
->sys
->lock
);
874 while( p_aout
->sys
->i_frames
)
876 vlc_cond_wait( &p_aout
->sys
->cond
, &p_aout
->sys
-> lock
);
878 vlc_mutex_unlock( &p_aout
->sys
->lock
);
882 static void WaveOutPause( audio_output_t
* p_aout
, bool pause
, mtime_t date
)
888 vlc_timer_schedule( p_aout
->sys
->volume_poll_timer
, false, 1, 200000 );
889 res
= waveOutPause( p_aout
->sys
->h_waveout
);
890 if( res
!= MMSYSERR_NOERROR
)
892 msg_Err( p_aout
, "waveOutPause failed (0x%x)", res
);
898 vlc_timer_schedule( p_aout
->sys
->volume_poll_timer
, false, 0, 0 );
899 res
= waveOutRestart( p_aout
->sys
->h_waveout
);
900 if( res
!= MMSYSERR_NOERROR
)
902 msg_Err( p_aout
, "waveOutRestart failed (0x%x)", res
);
908 static int WaveoutVolumeSet( audio_output_t
*p_aout
, float volume
)
910 aout_sys_t
*sys
= p_aout
->sys
;
914 float gain
= volume
* volume
* volume
;
915 if ( !sys
->b_mute
&& aout_GainRequest( p_aout
, gain
) )
920 const HWAVEOUT hwo
= sys
->h_waveout
;
922 uint32_t vol
= lroundf( volume
* 0x7fff.fp0
);
932 MMRESULT r
= waveOutSetVolume( hwo
, vol
| ( vol
<< 16 ) );
933 if( r
!= MMSYSERR_NOERROR
)
935 msg_Err( p_aout
, "waveOutSetVolume failed (%u)", r
);
941 vlc_mutex_lock(&p_aout
->sys
->lock
);
942 sys
->f_volume
= volume
;
944 if( var_InheritBool( p_aout
, "volume-save" ) )
945 config_PutFloat( p_aout
, "waveout-volume", volume
);
947 aout_VolumeReport( p_aout
, volume
);
948 vlc_mutex_unlock(&p_aout
->sys
->lock
);
953 static int WaveoutMuteSet( audio_output_t
* p_aout
, bool mute
)
955 aout_sys_t
*sys
= p_aout
->sys
;
959 float gain
= sys
->f_volume
* sys
->f_volume
* sys
->f_volume
;
960 if ( aout_GainRequest( p_aout
, mute
? 0.f
: gain
) )
966 const HWAVEOUT hwo
= sys
->h_waveout
;
967 uint32_t vol
= mute
? 0 : lroundf( sys
->f_volume
* 0x7fff.fp0
);
972 MMRESULT r
= waveOutSetVolume( hwo
, vol
| ( vol
<< 16 ) );
973 if( r
!= MMSYSERR_NOERROR
)
975 msg_Err( p_aout
, "waveOutSetVolume failed (%u)", r
);
980 vlc_mutex_lock(&p_aout
->sys
->lock
);
982 aout_MuteReport( p_aout
, mute
);
983 vlc_mutex_unlock(&p_aout
->sys
->lock
);
988 static void WaveoutPollVolume( void * aout
)
990 audio_output_t
* p_aout
= (audio_output_t
*) aout
;
993 MMRESULT r
= waveOutGetVolume( p_aout
->sys
->h_waveout
, (LPDWORD
) &vol
);
995 if( r
!= MMSYSERR_NOERROR
)
997 msg_Err( p_aout
, "waveOutGetVolume failed (%u)", r
);
1001 float volume
= (float) ( vol
& UINT32_C( 0xffff ) );
1002 volume
/= 0x7fff.fp0
;
1004 vlc_mutex_lock(&p_aout
->sys
->lock
);
1005 if( !p_aout
->sys
->b_mute
&& volume
!= p_aout
->sys
->f_volume
)
1007 p_aout
->sys
->f_volume
= volume
;
1009 if( var_InheritBool( p_aout
, "volume-save" ) )
1010 config_PutFloat( p_aout
, "waveout-volume", volume
);
1012 aout_VolumeReport( p_aout
, volume
);
1014 vlc_mutex_unlock(&p_aout
->sys
->lock
);