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() */
42 #include <vlc_atomic.h>
44 #include "windows_audio_common.h"
46 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open ( vlc_object_t * );
52 static void Close ( vlc_object_t * );
53 static void Play ( audio_output_t *, block_t * );
55 /*****************************************************************************
56 * notification_thread_t: waveOut event thread
57 *****************************************************************************/
61 struct lkwavehdr * p_next;
65 static void Probe ( audio_output_t *, const audio_sample_format_t * );
66 static int OpenWaveOut ( audio_output_t *, uint32_t,
67 int, int, int, int, bool );
68 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
69 vlc_fourcc_t*, int, int, int, bool );
70 static int PlayWaveOut ( audio_output_t *, HWAVEOUT, struct lkwavehdr *,
73 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
75 static void WaveOutClean( aout_sys_t * p_sys );
77 static void WaveOutClearBuffer( HWAVEOUT, WAVEHDR *);
79 static int ReloadWaveoutDevices( vlc_object_t *, const char *,
81 static uint32_t findDeviceID(char *);
82 static int WaveOutTimeGet(audio_output_t * , mtime_t *);
83 static void WaveOutFlush( audio_output_t *, bool);
84 static void WaveOutPause( audio_output_t *, bool, mtime_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 uint32_t i_wave_device_id; /* ID of selected output device */
103 HWAVEOUT h_waveout; /* handle to waveout instance */
105 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
109 int i_repeat_counter;
115 uint8_t *p_silence_buffer; /* buffer we use to play silence */
121 bool b_soft; /* Use software gain */
122 uint8_t chans_to_reorder; /* do we need channel reordering */
124 uint8_t chan_table[AOUT_CHAN_MAX];
127 mtime_t i_played_length;
129 struct lkwavehdr * p_free_list;
133 vlc_timer_t volume_poll_timer;
136 /*****************************************************************************
138 *****************************************************************************/
139 #define DEVICE_TEXT N_("Select Audio Device")
140 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
141 "decide (default), change needs VLC restart "\
143 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
145 #define VOLUME_TEXT N_("Audio volume")
148 set_shortname( "WaveOut" )
149 set_description( N_("Win32 waveOut extension output") )
150 set_capability( "audio output", 50 )
151 set_category( CAT_AUDIO )
152 set_subcategory( SUBCAT_AUDIO_AOUT )
154 add_string( "waveout-audio-device", "wavemapper",
155 DEVICE_TEXT, DEVICE_LONG, false )
156 change_string_cb( ReloadWaveoutDevices )
158 add_float( "waveout-volume", 1.0f, VOLUME_TEXT, NULL, true )
159 change_float_range(0.0f, 2.0f)
161 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
163 set_callbacks( Open, Close )
166 /*****************************************************************************
167 * Opens the audio device
168 *****************************************************************************
169 * This function opens and setups Win32 waveOut
170 *****************************************************************************/
171 static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
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;
184 check for configured audio device!
186 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
188 p_aout->sys->i_wave_device_id =
189 findDeviceID( psz_waveout_dev );
191 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
193 if(psz_waveout_dev &&
194 stricmp(psz_waveout_dev,"wavemapper"))
196 msg_Warn( p_aout, "configured audio device '%s' not available, "\
197 "use default instead", psz_waveout_dev );
200 free( psz_waveout_dev );
203 WAVEOUTCAPS waveoutcaps;
204 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
206 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
208 /* log debug some infos about driver, to know who to blame
209 if it doesn't work */
210 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
211 msg_Dbg( p_aout, "Driver Version: %d.%d",
212 (waveoutcaps.vDriverVersion>>8)&255,
213 waveoutcaps.vDriverVersion & 255);
214 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
215 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
220 if( var_Type( p_aout, "audio-device" ) == 0 )
222 Probe( p_aout, fmt );
225 if( var_Get( p_aout, "audio-device", &val ) < 0 )
227 /* Probe() has failed. */
228 var_Destroy( p_aout, "waveout-audio-device");
233 /* Open the device */
234 if( val.i_int == AOUT_VAR_SPDIF )
236 fmt->i_format = VLC_CODEC_SPDIFL;
238 if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
239 VLC_CODEC_SPDIFL, fmt->i_physical_channels,
240 aout_FormatNbChannels( fmt ), fmt->i_rate, false )
243 msg_Err( p_aout, "cannot open waveout audio device" );
247 /* Calculate the frame size in bytes */
248 fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
249 fmt->i_frame_length = A52_FRAME_NB;
250 p_aout->sys->i_buffer_size = fmt->i_bytes_per_frame;
251 p_aout->sys->b_spdif = true;
258 fmt->i_physical_channels
259 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
260 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
264 fmt->i_physical_channels
265 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
266 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
269 fmt->i_physical_channels = AOUT_CHAN_CENTER;
272 fmt->i_physical_channels = AOUT_CHANS_STEREO;
275 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
276 &fmt->i_format, fmt->i_physical_channels,
277 aout_FormatNbChannels( fmt ), fmt->i_rate, false )
280 msg_Err( p_aout, "cannot open waveout audio device" );
284 /* Calculate the frame size in bytes */
285 aout_FormatPrepare( fmt );
286 p_aout->sys->i_buffer_size = FRAME_SIZE * fmt->i_bytes_per_frame;
288 if( waveoutcaps.dwSupport & WAVECAPS_VOLUME )
290 aout_GainRequest( p_aout, 1.0f );
291 p_aout->sys->b_soft = false;
294 WaveoutMuteSet( p_aout, p_aout->sys->b_mute );
296 p_aout->sys->b_spdif = false;
299 p_aout->sys->i_rate = fmt->i_rate;
301 waveOutReset( p_aout->sys->h_waveout );
303 /* Allocate silence buffer */
304 p_aout->sys->p_silence_buffer =
305 malloc( p_aout->sys->i_buffer_size );
306 if( p_aout->sys->p_silence_buffer == NULL )
308 msg_Err( p_aout, "Couldn't alloc silence buffer... aborting");
311 p_aout->sys->i_repeat_counter = 0;
314 /* Zero the buffer. WinCE doesn't have calloc(). */
315 memset( p_aout->sys->p_silence_buffer, 0,
316 p_aout->sys->i_buffer_size );
318 /* Now we need to setup our waveOut play notification structure */
319 p_aout->sys->i_frames = 0;
320 p_aout->sys->i_played_length = 0;
321 p_aout->sys->p_free_list = NULL;
326 /*****************************************************************************
327 * Probe: probe the audio device for available formats and channels
328 *****************************************************************************/
329 static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
331 vlc_value_t val, text;
332 vlc_fourcc_t i_format;
333 unsigned int i_physical_channels;
335 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
336 text.psz_string = _("Audio Device");
337 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
339 /* Test for 5.1 support */
340 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
341 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
342 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
343 if( fmt->i_physical_channels == i_physical_channels )
345 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
346 &i_format, i_physical_channels, 6,
350 val.i_int = AOUT_VAR_5_1;
351 text.psz_string = (char *)_("5.1");
352 var_Change( p_aout, "audio-device",
353 VLC_VAR_ADDCHOICE, &val, &text );
354 msg_Dbg( p_aout, "device supports 5.1 channels" );
358 /* Test for 2 Front 2 Rear support */
359 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
360 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
361 if( ( fmt->i_physical_channels & i_physical_channels )
362 == i_physical_channels )
364 if( OpenWaveOutPCM( p_aout,p_aout->sys->i_wave_device_id,
365 &i_format, i_physical_channels, 4,
369 val.i_int = AOUT_VAR_2F2R;
370 text.psz_string = (char *)_("2 Front 2 Rear");
371 var_Change( p_aout, "audio-device",
372 VLC_VAR_ADDCHOICE, &val, &text );
373 msg_Dbg( p_aout, "device supports 4 channels" );
377 /* Test for stereo support */
378 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
379 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
380 &i_format,i_physical_channels, 2,
384 val.i_int = AOUT_VAR_STEREO;
385 text.psz_string = (char *)_("Stereo");
386 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
387 msg_Dbg( p_aout, "device supports 2 channels" );
390 /* Test for mono support */
391 i_physical_channels = AOUT_CHAN_CENTER;
392 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
393 &i_format, i_physical_channels, 1, fmt->i_rate, true )
396 val.i_int = AOUT_VAR_MONO;
397 text.psz_string = (char *)_("Mono");
398 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
399 msg_Dbg( p_aout, "device supports 1 channel" );
402 /* Test for SPDIF support */
403 if ( AOUT_FMT_SPDIF( fmt ) )
405 if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
406 VLC_CODEC_SPDIFL, fmt->i_physical_channels,
407 aout_FormatNbChannels( fmt ), fmt->i_rate, true )
410 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
411 val.i_int = AOUT_VAR_SPDIF;
412 text.psz_string = (char *)_("A/52 over S/PDIF");
413 var_Change( p_aout, "audio-device",
414 VLC_VAR_ADDCHOICE, &val, &text );
415 if( var_InheritBool( p_aout, "spdif" ) )
416 var_Set( p_aout, "audio-device", val );
420 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
423 /* Probe() has failed. */
424 var_Destroy( p_aout, "audio-device" );
428 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
431 /*****************************************************************************
432 * Play: play a sound buffer
433 *****************************************************************************
434 * This doesn't actually play the buffer. This just stores the buffer so it
435 * can be played by the callback thread.
436 *****************************************************************************/
437 static void Play( audio_output_t *p_aout, block_t *block )
439 struct lkwavehdr * p_waveheader =
440 (struct lkwavehdr *) malloc(sizeof(struct lkwavehdr));
443 msg_Err(p_aout, "Couldn't alloc WAVEHDR");
445 block_Release( block );
449 p_waveheader->p_next = NULL;
451 if( block && p_aout->sys->chans_to_reorder )
453 aout_ChannelReorder( block->p_buffer, block->i_buffer,
454 p_aout->sys->waveformat.Format.nChannels,
455 p_aout->sys->chan_table, p_aout->sys->format );
457 while( PlayWaveOut( p_aout, p_aout->sys->h_waveout, p_waveheader, block,
458 p_aout->sys->b_spdif ) != VLC_SUCCESS )
461 msg_Warn( p_aout, "Couln't write frame... sleeping");
462 msleep( block->i_length );
465 WaveOutClean( p_aout->sys );
466 WaveoutPollVolume( p_aout );
468 vlc_mutex_lock( &p_aout->sys->lock );
469 p_aout->sys->i_frames++;
470 p_aout->sys->i_played_length += block->i_length;
471 vlc_mutex_unlock( &p_aout->sys->lock );
474 /*****************************************************************************
475 * Close: close the audio device
476 *****************************************************************************/
477 static void Stop( audio_output_t *p_aout )
479 aout_sys_t *p_sys = p_aout->sys;
481 /* Before calling waveOutClose we must reset the device */
482 MMRESULT result = waveOutReset( p_sys->h_waveout );
483 if(result != MMSYSERR_NOERROR)
485 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
487 now we must wait, that all buffers are played
488 because cancel doesn't work in this case...
490 if(result == MMSYSERR_NOTSUPPORTED)
493 clear currently played (done) buffers,
494 if returnvalue > 0 (means some buffer still playing)
495 wait for the driver event callback that one buffer
496 is finished with playing, and check again
497 the timeout of 5000ms is just, an emergency exit
498 of this loop, to avoid deadlock in case of other
499 (currently not known bugs, problems, errors cases?)
501 WaveOutFlush( p_aout, true );
505 /* wait for the frames to be queued in cleaning list */
506 WaveOutFlush( p_aout, true );
507 WaveOutClean( p_aout->sys );
509 /* now we can Close the device */
510 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
512 msg_Err( p_aout, "waveOutClose failed" );
515 free( p_sys->p_silence_buffer );
516 p_aout->sys->i_played_length = 0;
517 p_sys->b_soft = true;
520 /*****************************************************************************
521 * OpenWaveOut: open the waveout sound device
522 ****************************************************************************/
523 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
524 int i_channels, int i_nb_channels, int i_rate,
529 /* Set sound format */
531 #define waveformat p_aout->sys->waveformat
533 waveformat.dwChannelMask = 0;
534 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
535 if( i_channels & pi_vlc_chan_order_wg4[i] )
536 waveformat.dwChannelMask |= pi_channels_in[i];
540 case VLC_CODEC_SPDIFL:
542 /* To prevent channel re-ordering */
543 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
544 waveformat.Format.wBitsPerSample = 16;
545 waveformat.Samples.wValidBitsPerSample =
546 waveformat.Format.wBitsPerSample;
547 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
548 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
552 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
553 waveformat.Samples.wValidBitsPerSample =
554 waveformat.Format.wBitsPerSample;
555 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
556 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
560 waveformat.Format.wBitsPerSample = 16;
561 waveformat.Samples.wValidBitsPerSample =
562 waveformat.Format.wBitsPerSample;
563 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
564 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
568 waveformat.Format.nChannels = i_nb_channels;
569 waveformat.Format.nSamplesPerSec = i_rate;
570 waveformat.Format.nBlockAlign =
571 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
572 waveformat.Format.nAvgBytesPerSec =
573 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
575 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
576 if( i_nb_channels <= 2 )
578 waveformat.Format.cbSize = 0;
582 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
583 waveformat.Format.cbSize =
584 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
588 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
589 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
590 waveformat.Format.cbSize);
591 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
592 waveformat.Format.wFormatTag);
593 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
594 waveformat.Format.nChannels);
595 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
596 (int)waveformat.Format.nSamplesPerSec);
597 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
598 (int)waveformat.Format.nAvgBytesPerSec);
599 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
600 waveformat.Format.nBlockAlign);
601 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
602 waveformat.Format.wBitsPerSample);
603 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
604 waveformat.Samples.wValidBitsPerSample);
605 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
606 waveformat.Samples.wSamplesPerBlock);
607 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
608 waveformat.dwChannelMask);
611 /* Open the device */
612 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
613 (WAVEFORMATEX *)&waveformat,
614 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
615 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
616 if( result == WAVERR_BADFORMAT )
618 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
621 if( result == MMSYSERR_ALLOCATED )
623 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
626 if( result != MMSYSERR_NOERROR )
628 msg_Warn( p_aout, "waveOutOpen failed" );
632 p_aout->sys->chans_to_reorder =
633 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
634 waveformat.dwChannelMask,
635 p_aout->sys->chan_table );
636 if( p_aout->sys->chans_to_reorder )
637 msg_Dbg( p_aout, "channel reordering needed" );
638 p_aout->sys->format = i_format;
646 /*****************************************************************************
647 * OpenWaveOutPCM: open a PCM waveout sound device
648 ****************************************************************************/
649 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
650 vlc_fourcc_t *i_format,
651 int i_channels, int i_nb_channels, int i_rate,
654 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
656 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
657 i_channels, i_nb_channels, i_rate, b_probe )
660 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16N,
661 i_channels, i_nb_channels, i_rate, b_probe )
668 *i_format = VLC_CODEC_S16N;
674 *i_format = VLC_CODEC_FL32;
679 /*****************************************************************************
680 * PlayWaveOut: play a buffer through the WaveOut device
681 *****************************************************************************/
682 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
683 struct lkwavehdr *p_waveheader, block_t *p_buffer, bool b_spdif)
687 /* Prepare the buffer */
688 if( p_buffer != NULL )
690 p_waveheader->hdr.lpData = (LPSTR)p_buffer->p_buffer;
691 p_waveheader->hdr.dwBufferLength = p_buffer->i_buffer;
693 copy the buffer to the silence buffer :) so in case we don't
694 get the next buffer fast enough (I will repeat this one a time
695 for AC3 / DTS and SPDIF this will sound better instead of
700 memcpy( p_aout->sys->p_silence_buffer,
702 p_aout->sys->i_buffer_size );
703 p_aout->sys->i_repeat_counter = 2;
706 /* Use silence buffer instead */
707 if(p_aout->sys->i_repeat_counter)
709 p_aout->sys->i_repeat_counter--;
710 if(!p_aout->sys->i_repeat_counter)
712 memset( p_aout->sys->p_silence_buffer,
713 0x00, p_aout->sys->i_buffer_size );
716 p_waveheader->hdr.lpData = (LPSTR)p_aout->sys->p_silence_buffer;
717 p_waveheader->hdr.dwBufferLength = p_aout->sys->i_buffer_size;
720 p_waveheader->hdr.dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
721 p_waveheader->hdr.dwFlags = 0;
723 result = waveOutPrepareHeader( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
724 if( result != MMSYSERR_NOERROR )
726 msg_Err( p_aout, "waveOutPrepareHeader failed" );
730 /* Send the buffer to the waveOut queue */
731 result = waveOutWrite( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
732 if( result != MMSYSERR_NOERROR )
734 msg_Err( p_aout, "waveOutWrite failed" );
741 /*****************************************************************************
742 * WaveOutCallback: what to do once WaveOut has played its sound samples
743 *****************************************************************************/
744 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
746 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
750 audio_output_t *p_aout = (audio_output_t *)_p_aout;
751 struct lkwavehdr * p_waveheader = (struct lkwavehdr *) dwParam1;
753 if( uMsg != WOM_DONE ) return;
755 vlc_mutex_lock( &p_aout->sys->lock );
756 p_waveheader->p_next = p_aout->sys->p_free_list;
757 p_aout->sys->p_free_list = p_waveheader;
758 p_aout->sys->i_frames--;
759 vlc_cond_broadcast( &p_aout->sys->cond );
760 vlc_mutex_unlock( &p_aout->sys->lock );
763 static void WaveOutClean( aout_sys_t * p_sys )
765 struct lkwavehdr *p_whdr, *p_list;
767 vlc_mutex_lock(&p_sys->lock);
768 p_list = p_sys->p_free_list;
769 p_sys->p_free_list = NULL;
770 vlc_mutex_unlock(&p_sys->lock);
775 p_list = p_list->p_next;
776 WaveOutClearBuffer( p_sys->h_waveout, &p_whdr->hdr );
781 static void WaveOutClearBuffer( HWAVEOUT h_waveout, WAVEHDR *p_waveheader )
783 block_t *p_buffer = (block_t *)(p_waveheader->dwUser);
784 /* Unprepare and free the buffers which has just been played */
785 waveOutUnprepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
787 if( p_waveheader->dwUser != 1 )
788 block_Release( p_buffer );
792 reload the configuration drop down list, of the Audio Devices
794 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
795 char ***values, char ***descs )
797 int n = 0, nb_devices = waveOutGetNumDevs();
799 VLC_UNUSED( p_this); VLC_UNUSED( psz_name );
801 *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
802 *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
804 (*values)[n] = strdup( "wavemapper" );
805 (*descs)[n] = strdup( _("Microsoft Soundmapper") );
808 for(int i = 0; i < nb_devices; i++)
811 wchar_t dev_name[MAXPNAMELEN+32];
813 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
817 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
818 caps.szPname, caps.wMid, caps.wPid);
819 (*values)[n] = FromWide( dev_name );
820 (*descs)[n] = strdup( (*values)[n] );
828 convert devicename to device ID for output
829 if device not found return WAVE_MAPPER, so let
830 windows decide which preferred audio device
833 static uint32_t findDeviceID(char *psz_device_name)
835 if( !psz_device_name )
838 uint32_t wave_devices = waveOutGetNumDevs();
840 for( uint32_t i = 0; i < wave_devices; i++ )
843 wchar_t dev_name[MAXPNAMELEN+32];
845 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
846 != MMSYSERR_NOERROR )
849 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
850 caps.szPname, caps.wMid, caps.wPid );
851 char *u8 = FromWide(dev_name);
852 if( !stricmp(u8, psz_device_name) )
863 static int Open(vlc_object_t *obj)
865 audio_output_t *aout = (audio_output_t *)obj;
866 aout_sys_t *sys = malloc(sizeof (*sys));
868 if (unlikely(sys == NULL))
873 aout->volume_set = WaveoutVolumeSet;
874 aout->mute_set = WaveoutMuteSet;
876 sys->f_volume = var_InheritFloat(aout, "waveout-volume");
877 sys->b_mute = var_InheritBool(aout, "mute");
879 aout_MuteReport(aout, sys->b_mute);
880 aout_VolumeReport(aout, sys->f_volume );
882 if( vlc_timer_create( &sys->volume_poll_timer,
883 WaveoutPollVolume, aout ) )
885 msg_Err( aout, "Couldn't create volume polling timer" );
890 vlc_mutex_init( &sys->lock );
891 vlc_cond_init( &sys->cond );
896 static void Close(vlc_object_t *obj)
898 audio_output_t *aout = (audio_output_t *)obj;
899 aout_sys_t *sys = aout->sys;
901 vlc_timer_destroy( sys->volume_poll_timer );
903 vlc_cond_destroy( &sys->cond );
904 vlc_mutex_destroy( &sys->lock );
909 static int WaveOutTimeGet(audio_output_t * p_aout, mtime_t *delay)
912 mmtime.wType = TIME_SAMPLES;
914 if( !p_aout->sys->i_frames )
917 if( waveOutGetPosition( p_aout->sys->h_waveout, &mmtime, sizeof(MMTIME) )
918 != MMSYSERR_NOERROR )
920 msg_Err( p_aout, "waveOutGetPosition failed");
924 mtime_t i_pos = (mtime_t) mmtime.u.sample * CLOCK_FREQ / p_aout->sys->i_rate;
925 *delay = p_aout->sys->i_played_length - i_pos;
929 static void WaveOutFlush( audio_output_t *p_aout, bool wait)
934 res = waveOutReset( p_aout->sys->h_waveout );
935 p_aout->sys->i_played_length = 0;
936 if( res != MMSYSERR_NOERROR )
937 msg_Err( p_aout, "waveOutReset failed");
941 vlc_mutex_lock( &p_aout->sys->lock );
942 while( p_aout->sys->i_frames )
944 vlc_cond_wait( &p_aout->sys->cond, &p_aout->sys-> lock );
946 vlc_mutex_unlock( &p_aout->sys->lock );
950 static void WaveOutPause( audio_output_t * p_aout, bool pause, mtime_t date)
956 vlc_timer_schedule( p_aout->sys->volume_poll_timer, false, 1, 200000 );
957 res = waveOutPause( p_aout->sys->h_waveout );
958 if( res != MMSYSERR_NOERROR )
960 msg_Err( p_aout, "waveOutPause failed (0x%x)", res);
966 vlc_timer_schedule( p_aout->sys->volume_poll_timer, false, 0, 0 );
967 res = waveOutRestart( p_aout->sys->h_waveout );
968 if( res != MMSYSERR_NOERROR )
970 msg_Err( p_aout, "waveOutRestart failed (0x%x)", res);
976 static int WaveoutVolumeSet( audio_output_t *p_aout, float volume )
978 aout_sys_t *sys = p_aout->sys;
982 float gain = volume * volume * volume;
983 if ( !sys->b_mute && aout_GainRequest( p_aout, gain ) )
988 const HWAVEOUT hwo = sys->h_waveout;
990 uint32_t vol = lroundf( volume * 0x7fff.fp0 );
1000 MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
1001 if( r != MMSYSERR_NOERROR )
1003 msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
1009 vlc_mutex_lock(&p_aout->sys->lock);
1010 sys->f_volume = volume;
1012 if( var_InheritBool( p_aout, "volume-save" ) )
1013 config_PutFloat( p_aout, "waveout-volume", volume );
1015 aout_VolumeReport( p_aout, volume );
1016 vlc_mutex_unlock(&p_aout->sys->lock);
1021 static int WaveoutMuteSet( audio_output_t * p_aout, bool mute )
1023 aout_sys_t *sys = p_aout->sys;
1027 float gain = sys->f_volume * sys->f_volume * sys->f_volume;
1028 if ( aout_GainRequest( p_aout, mute ? 0.f : gain ) )
1034 const HWAVEOUT hwo = sys->h_waveout;
1035 uint32_t vol = mute ? 0 : lroundf( sys->f_volume * 0x7fff.fp0 );
1040 MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
1041 if( r != MMSYSERR_NOERROR )
1043 msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
1048 vlc_mutex_lock(&p_aout->sys->lock);
1050 aout_MuteReport( p_aout, mute );
1051 vlc_mutex_unlock(&p_aout->sys->lock);
1056 static void WaveoutPollVolume( void * aout )
1058 audio_output_t * p_aout = (audio_output_t *) aout;
1061 MMRESULT r = waveOutGetVolume( p_aout->sys->h_waveout, (LPDWORD) &vol );
1063 if( r != MMSYSERR_NOERROR )
1065 msg_Err( p_aout, "waveOutGetVolume failed (%u)", r );
1069 float volume = (float) ( vol & UINT32_C( 0xffff ) );
1070 volume /= 0x7fff.fp0;
1072 vlc_mutex_lock(&p_aout->sys->lock);
1073 if( !p_aout->sys->b_mute && volume != p_aout->sys->f_volume )
1075 p_aout->sys->f_volume = volume;
1077 if( var_InheritBool( p_aout, "volume-save" ) )
1078 config_PutFloat( p_aout, "waveout-volume", volume );
1080 aout_VolumeReport( p_aout, volume );
1082 vlc_mutex_unlock(&p_aout->sys->lock);