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);
86 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
88 /*****************************************************************************
89 * aout_sys_t: waveOut audio output method descriptor
90 *****************************************************************************
91 * This structure is part of the audio output thread descriptor.
92 * It describes the waveOut specific properties of an audio device.
93 *****************************************************************************/
97 uint32_t i_wave_device_id; /* ID of selected output device */
99 HWAVEOUT h_waveout; /* handle to waveout instance */
101 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
105 int i_repeat_counter;
112 uint8_t *p_silence_buffer; /* buffer we use to play silence */
117 uint8_t chans_to_reorder; /* do we need channel reordering */
118 uint8_t chan_table[AOUT_CHAN_MAX];
121 mtime_t i_played_length;
123 struct lkwavehdr * p_free_list;
131 /*****************************************************************************
133 *****************************************************************************/
134 #define DEVICE_TEXT N_("Select Audio Device")
135 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
136 "decide (default), change needs VLC restart "\
138 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
141 set_shortname( "WaveOut" )
142 set_description( N_("Win32 waveOut extension output") )
143 set_capability( "audio output", 50 )
144 set_category( CAT_AUDIO )
145 set_subcategory( SUBCAT_AUDIO_AOUT )
147 add_string( "waveout-audio-device", "wavemapper",
148 DEVICE_TEXT, DEVICE_LONG, false )
149 change_string_cb( ReloadWaveoutDevices )
152 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
154 set_callbacks( Open, Close )
157 /*****************************************************************************
158 * Opens the audio device
159 *****************************************************************************
160 * This function opens and setups Win32 waveOut
161 *****************************************************************************/
162 static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
166 p_aout->time_get = WaveOutTimeGet;
168 p_aout->pause = WaveOutPause;
169 p_aout->flush = WaveOutFlush;
172 check for configured audio device!
174 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
176 p_aout->sys->i_wave_device_id =
177 findDeviceID( psz_waveout_dev );
179 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
181 if(psz_waveout_dev &&
182 stricmp(psz_waveout_dev,"wavemapper"))
184 msg_Warn( p_aout, "configured audio device '%s' not available, "\
185 "use default instead", psz_waveout_dev );
188 free( psz_waveout_dev );
191 WAVEOUTCAPS waveoutcaps;
192 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
194 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
196 /* log debug some infos about driver, to know who to blame
197 if it doesn't work */
198 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
199 msg_Dbg( p_aout, "Driver Version: %d.%d",
200 (waveoutcaps.vDriverVersion>>8)&255,
201 waveoutcaps.vDriverVersion & 255);
202 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
203 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
208 if( var_Type( p_aout, "audio-device" ) == 0 )
210 Probe( p_aout, fmt );
213 if( var_Get( p_aout, "audio-device", &val ) < 0 )
215 /* Probe() has failed. */
216 var_Destroy( p_aout, "waveout-audio-device");
221 /* Open the device */
222 if( val.i_int == AOUT_VAR_SPDIF )
224 fmt->i_format = VLC_CODEC_SPDIFL;
226 if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
227 VLC_CODEC_SPDIFL, fmt->i_physical_channels,
228 aout_FormatNbChannels( fmt ), fmt->i_rate, false )
231 msg_Err( p_aout, "cannot open waveout audio device" );
235 /* Calculate the frame size in bytes */
236 fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
237 fmt->i_frame_length = A52_FRAME_NB;
238 p_aout->sys->i_buffer_size = fmt->i_bytes_per_frame;
239 p_aout->sys->b_spdif = true;
246 fmt->i_physical_channels
247 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
248 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
252 fmt->i_physical_channels
253 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
254 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
257 fmt->i_physical_channels = AOUT_CHAN_CENTER;
260 fmt->i_physical_channels = AOUT_CHANS_STEREO;
263 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
264 &fmt->i_format, fmt->i_physical_channels,
265 aout_FormatNbChannels( fmt ), fmt->i_rate, false )
268 msg_Err( p_aout, "cannot open waveout audio device" );
272 /* Calculate the frame size in bytes */
273 aout_FormatPrepare( fmt );
274 p_aout->sys->i_buffer_size = FRAME_SIZE * fmt->i_bytes_per_frame;
276 aout_SoftVolumeStart( p_aout );
278 p_aout->sys->b_spdif = false;
281 p_aout->sys->i_rate = fmt->i_rate;
283 waveOutReset( p_aout->sys->h_waveout );
285 /* Allocate silence buffer */
286 p_aout->sys->p_silence_buffer =
287 malloc( p_aout->sys->i_buffer_size );
288 if( p_aout->sys->p_silence_buffer == NULL )
290 msg_Err( p_aout, "Couldn't alloc silence buffer... aborting");
293 p_aout->sys->i_repeat_counter = 0;
296 /* Zero the buffer. WinCE doesn't have calloc(). */
297 memset( p_aout->sys->p_silence_buffer, 0,
298 p_aout->sys->i_buffer_size );
300 /* Now we need to setup our waveOut play notification structure */
301 p_aout->sys->i_frames = 0;
302 p_aout->sys->i_played_length = 0;
303 p_aout->sys->p_free_list = NULL;
308 /*****************************************************************************
309 * Probe: probe the audio device for available formats and channels
310 *****************************************************************************/
311 static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
313 vlc_value_t val, text;
314 vlc_fourcc_t i_format;
315 unsigned int i_physical_channels;
317 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
318 text.psz_string = _("Audio Device");
319 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
321 /* Test for 5.1 support */
322 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
323 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
324 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
325 if( fmt->i_physical_channels == i_physical_channels )
327 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
328 &i_format, i_physical_channels, 6,
332 val.i_int = AOUT_VAR_5_1;
333 text.psz_string = (char *)_("5.1");
334 var_Change( p_aout, "audio-device",
335 VLC_VAR_ADDCHOICE, &val, &text );
336 msg_Dbg( p_aout, "device supports 5.1 channels" );
340 /* Test for 2 Front 2 Rear support */
341 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
342 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
343 if( ( fmt->i_physical_channels & i_physical_channels )
344 == i_physical_channels )
346 if( OpenWaveOutPCM( p_aout,p_aout->sys->i_wave_device_id,
347 &i_format, i_physical_channels, 4,
351 val.i_int = AOUT_VAR_2F2R;
352 text.psz_string = (char *)_("2 Front 2 Rear");
353 var_Change( p_aout, "audio-device",
354 VLC_VAR_ADDCHOICE, &val, &text );
355 msg_Dbg( p_aout, "device supports 4 channels" );
359 /* Test for stereo support */
360 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
361 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
362 &i_format,i_physical_channels, 2,
366 val.i_int = AOUT_VAR_STEREO;
367 text.psz_string = (char *)_("Stereo");
368 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
369 msg_Dbg( p_aout, "device supports 2 channels" );
372 /* Test for mono support */
373 i_physical_channels = AOUT_CHAN_CENTER;
374 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
375 &i_format, i_physical_channels, 1, fmt->i_rate, true )
378 val.i_int = AOUT_VAR_MONO;
379 text.psz_string = (char *)_("Mono");
380 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
381 msg_Dbg( p_aout, "device supports 1 channel" );
384 /* Test for SPDIF support */
385 if ( AOUT_FMT_SPDIF( fmt ) )
387 if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
388 VLC_CODEC_SPDIFL, fmt->i_physical_channels,
389 aout_FormatNbChannels( fmt ), fmt->i_rate, true )
392 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
393 val.i_int = AOUT_VAR_SPDIF;
394 text.psz_string = (char *)_("A/52 over S/PDIF");
395 var_Change( p_aout, "audio-device",
396 VLC_VAR_ADDCHOICE, &val, &text );
397 if( var_InheritBool( p_aout, "spdif" ) )
398 var_Set( p_aout, "audio-device", val );
402 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
405 /* Probe() has failed. */
406 var_Destroy( p_aout, "audio-device" );
410 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
413 /*****************************************************************************
414 * Play: play a sound buffer
415 *****************************************************************************
416 * This doesn't actually play the buffer. This just stores the buffer so it
417 * can be played by the callback thread.
418 *****************************************************************************/
419 static void Play( audio_output_t *p_aout, block_t *block )
421 struct lkwavehdr * p_waveheader =
422 (struct lkwavehdr *) malloc(sizeof(struct lkwavehdr));
425 msg_Err(p_aout, "Couldn't alloc WAVEHDR");
427 block_Release( block );
431 p_waveheader->p_next = NULL;
433 if( block && p_aout->sys->chans_to_reorder )
435 aout_ChannelReorder( block->p_buffer, block->i_buffer,
436 p_aout->sys->waveformat.Format.nChannels,
437 p_aout->sys->chan_table, p_aout->sys->format );
439 while( PlayWaveOut( p_aout, p_aout->sys->h_waveout, p_waveheader, block,
440 p_aout->sys->b_spdif ) != VLC_SUCCESS )
443 msg_Warn( p_aout, "Couln't write frame... sleeping");
444 msleep( block->i_length );
447 WaveOutClean( p_aout->sys );
449 vlc_mutex_lock( &p_aout->sys->lock );
450 p_aout->sys->i_frames++;
451 p_aout->sys->i_played_length += block->i_length;
452 vlc_mutex_unlock( &p_aout->sys->lock );
455 /*****************************************************************************
456 * Close: close the audio device
457 *****************************************************************************/
458 static void Stop( audio_output_t *p_aout )
460 aout_sys_t *p_sys = p_aout->sys;
462 /* Before calling waveOutClose we must reset the device */
463 MMRESULT result = waveOutReset( p_sys->h_waveout );
464 if(result != MMSYSERR_NOERROR)
466 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
468 now we must wait, that all buffers are played
469 because cancel doesn't work in this case...
471 if(result == MMSYSERR_NOTSUPPORTED)
474 clear currently played (done) buffers,
475 if returnvalue > 0 (means some buffer still playing)
476 wait for the driver event callback that one buffer
477 is finished with playing, and check again
478 the timeout of 5000ms is just, an emergency exit
479 of this loop, to avoid deadlock in case of other
480 (currently not known bugs, problems, errors cases?)
482 WaveOutFlush( p_aout, true );
486 /* wait for the frames to be queued in cleaning list */
487 WaveOutFlush( p_aout, true );
488 WaveOutClean( p_aout->sys );
490 /* now we can Close the device */
491 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
493 msg_Err( p_aout, "waveOutClose failed" );
496 free( p_sys->p_silence_buffer );
497 p_aout->sys->i_played_length = 0;
500 /*****************************************************************************
501 * OpenWaveOut: open the waveout sound device
502 ****************************************************************************/
503 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
504 int i_channels, int i_nb_channels, int i_rate,
509 /* Set sound format */
511 #define waveformat p_aout->sys->waveformat
513 waveformat.dwChannelMask = 0;
514 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
515 if( i_channels & pi_vlc_chan_order_wg4[i] )
516 waveformat.dwChannelMask |= pi_channels_in[i];
520 case VLC_CODEC_SPDIFL:
522 /* To prevent channel re-ordering */
523 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
524 waveformat.Format.wBitsPerSample = 16;
525 waveformat.Samples.wValidBitsPerSample =
526 waveformat.Format.wBitsPerSample;
527 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
528 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
532 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
533 waveformat.Samples.wValidBitsPerSample =
534 waveformat.Format.wBitsPerSample;
535 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
536 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
540 waveformat.Format.wBitsPerSample = 16;
541 waveformat.Samples.wValidBitsPerSample =
542 waveformat.Format.wBitsPerSample;
543 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
544 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
548 waveformat.Format.nChannels = i_nb_channels;
549 waveformat.Format.nSamplesPerSec = i_rate;
550 waveformat.Format.nBlockAlign =
551 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
552 waveformat.Format.nAvgBytesPerSec =
553 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
555 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
556 if( i_nb_channels <= 2 )
558 waveformat.Format.cbSize = 0;
562 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
563 waveformat.Format.cbSize =
564 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
568 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
569 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
570 waveformat.Format.cbSize);
571 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
572 waveformat.Format.wFormatTag);
573 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
574 waveformat.Format.nChannels);
575 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
576 (int)waveformat.Format.nSamplesPerSec);
577 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
578 (int)waveformat.Format.nAvgBytesPerSec);
579 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
580 waveformat.Format.nBlockAlign);
581 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
582 waveformat.Format.wBitsPerSample);
583 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
584 waveformat.Samples.wValidBitsPerSample);
585 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
586 waveformat.Samples.wSamplesPerBlock);
587 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
588 waveformat.dwChannelMask);
591 /* Open the device */
592 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
593 (WAVEFORMATEX *)&waveformat,
594 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
595 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
596 if( result == WAVERR_BADFORMAT )
598 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
601 if( result == MMSYSERR_ALLOCATED )
603 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
606 if( result != MMSYSERR_NOERROR )
608 msg_Warn( p_aout, "waveOutOpen failed" );
612 p_aout->sys->chans_to_reorder =
613 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
614 waveformat.dwChannelMask,
615 p_aout->sys->chan_table );
616 if( p_aout->sys->chans_to_reorder )
617 msg_Dbg( p_aout, "channel reordering needed" );
618 p_aout->sys->format = i_format;
626 /*****************************************************************************
627 * OpenWaveOutPCM: open a PCM waveout sound device
628 ****************************************************************************/
629 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
630 vlc_fourcc_t *i_format,
631 int i_channels, int i_nb_channels, int i_rate,
634 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
636 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
637 i_channels, i_nb_channels, i_rate, b_probe )
640 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16N,
641 i_channels, i_nb_channels, i_rate, b_probe )
648 *i_format = VLC_CODEC_S16N;
654 *i_format = VLC_CODEC_FL32;
659 /*****************************************************************************
660 * PlayWaveOut: play a buffer through the WaveOut device
661 *****************************************************************************/
662 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
663 struct lkwavehdr *p_waveheader, block_t *p_buffer, bool b_spdif)
667 /* Prepare the buffer */
668 if( p_buffer != NULL )
670 p_waveheader->hdr.lpData = (LPSTR)p_buffer->p_buffer;
671 p_waveheader->hdr.dwBufferLength = p_buffer->i_buffer;
673 copy the buffer to the silence buffer :) so in case we don't
674 get the next buffer fast enough (I will repeat this one a time
675 for AC3 / DTS and SPDIF this will sound better instead of
680 memcpy( p_aout->sys->p_silence_buffer,
682 p_aout->sys->i_buffer_size );
683 p_aout->sys->i_repeat_counter = 2;
686 /* Use silence buffer instead */
687 if(p_aout->sys->i_repeat_counter)
689 p_aout->sys->i_repeat_counter--;
690 if(!p_aout->sys->i_repeat_counter)
692 memset( p_aout->sys->p_silence_buffer,
693 0x00, p_aout->sys->i_buffer_size );
696 p_waveheader->hdr.lpData = (LPSTR)p_aout->sys->p_silence_buffer;
697 p_waveheader->hdr.dwBufferLength = p_aout->sys->i_buffer_size;
700 p_waveheader->hdr.dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
701 p_waveheader->hdr.dwFlags = 0;
703 result = waveOutPrepareHeader( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
704 if( result != MMSYSERR_NOERROR )
706 msg_Err( p_aout, "waveOutPrepareHeader failed" );
710 /* Send the buffer to the waveOut queue */
711 result = waveOutWrite( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
712 if( result != MMSYSERR_NOERROR )
714 msg_Err( p_aout, "waveOutWrite failed" );
721 /*****************************************************************************
722 * WaveOutCallback: what to do once WaveOut has played its sound samples
723 *****************************************************************************/
724 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
726 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
730 audio_output_t *p_aout = (audio_output_t *)_p_aout;
731 struct lkwavehdr * p_waveheader = (struct lkwavehdr *) dwParam1;
733 if( uMsg != WOM_DONE ) return;
735 vlc_mutex_lock( &p_aout->sys->lock );
736 p_waveheader->p_next = p_aout->sys->p_free_list;
737 p_aout->sys->p_free_list = p_waveheader;
738 p_aout->sys->i_frames--;
739 vlc_cond_broadcast( &p_aout->sys->cond );
740 vlc_mutex_unlock( &p_aout->sys->lock );
743 static void WaveOutClean( aout_sys_t * p_sys )
745 struct lkwavehdr *p_whdr, *p_list;
747 vlc_mutex_lock(&p_sys->lock);
748 p_list = p_sys->p_free_list;
749 p_sys->p_free_list = NULL;
750 vlc_mutex_unlock(&p_sys->lock);
755 p_list = p_list->p_next;
756 WaveOutClearBuffer( p_sys->h_waveout, &p_whdr->hdr );
761 static void WaveOutClearBuffer( HWAVEOUT h_waveout, WAVEHDR *p_waveheader )
763 block_t *p_buffer = (block_t *)(p_waveheader->dwUser);
764 /* Unprepare and free the buffers which has just been played */
765 waveOutUnprepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
767 if( p_waveheader->dwUser != 1 )
768 block_Release( p_buffer );
772 reload the configuration drop down list, of the Audio Devices
774 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
775 char ***values, char ***descs )
777 int n = 0, nb_devices = waveOutGetNumDevs();
779 VLC_UNUSED( p_this); VLC_UNUSED( psz_name );
781 *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
782 *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
784 (*values)[n] = strdup( "wavemapper" );
785 (*descs)[n] = strdup( _("Microsoft Soundmapper") );
788 for(int i = 0; i < nb_devices; i++)
791 wchar_t dev_name[MAXPNAMELEN+32];
793 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
797 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
798 caps.szPname, caps.wMid, caps.wPid);
799 (*values)[n] = FromWide( dev_name );
800 (*descs)[n] = strdup( (*values)[n] );
808 convert devicename to device ID for output
809 if device not found return WAVE_MAPPER, so let
810 windows decide which preferred audio device
813 static uint32_t findDeviceID(char *psz_device_name)
815 if( !psz_device_name )
818 uint32_t wave_devices = waveOutGetNumDevs();
820 for( uint32_t i = 0; i < wave_devices; i++ )
823 wchar_t dev_name[MAXPNAMELEN+32];
825 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
826 != MMSYSERR_NOERROR )
829 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
830 caps.szPname, caps.wMid, caps.wPid );
831 char *u8 = FromWide(dev_name);
832 if( !stricmp(u8, psz_device_name) )
843 static int Open(vlc_object_t *obj)
845 audio_output_t *aout = (audio_output_t *)obj;
846 aout_sys_t *sys = malloc(sizeof (*sys));
848 if (unlikely(sys == NULL))
853 aout_SoftVolumeInit(aout);
855 vlc_mutex_init( &sys->lock );
856 vlc_cond_init( &sys->cond );
860 static void Close(vlc_object_t *obj)
862 audio_output_t *aout = (audio_output_t *)obj;
863 aout_sys_t *sys = aout->sys;
865 vlc_cond_destroy( &sys->cond );
866 vlc_mutex_destroy( &sys->lock );
871 static int WaveOutTimeGet(audio_output_t * p_aout, mtime_t *delay)
874 mmtime.wType = TIME_SAMPLES;
876 if( !p_aout->sys->i_frames )
879 if( waveOutGetPosition( p_aout->sys->h_waveout, &mmtime, sizeof(MMTIME) )
880 != MMSYSERR_NOERROR )
882 msg_Err( p_aout, "waveOutGetPosition failed");
886 mtime_t i_pos = (mtime_t) mmtime.u.sample * CLOCK_FREQ / p_aout->sys->i_rate;
887 *delay = p_aout->sys->i_played_length - i_pos;
891 static void WaveOutFlush( audio_output_t *p_aout, bool wait)
896 res = waveOutReset( p_aout->sys->h_waveout );
897 p_aout->sys->i_played_length = 0;
898 if( res != MMSYSERR_NOERROR )
899 msg_Err( p_aout, "waveOutReset failed");
903 vlc_mutex_lock( &p_aout->sys->lock );
904 while( p_aout->sys->i_frames )
906 vlc_cond_wait( &p_aout->sys->cond, &p_aout->sys-> lock );
908 vlc_mutex_unlock( &p_aout->sys->lock );
912 static void WaveOutPause( audio_output_t * p_aout, bool pause, mtime_t date)
918 res = waveOutPause( p_aout->sys->h_waveout );
919 if( res != MMSYSERR_NOERROR )
921 msg_Err( p_aout, "waveOutPause failed (0x%x)", res);
927 res = waveOutRestart( p_aout->sys->h_waveout );
928 if( res != MMSYSERR_NOERROR )
930 msg_Err( p_aout, "waveOutRestart failed (0x%x)", res);