input: add an input_item_t arg to input_CreateFilename()
[vlc.git] / modules / audio_output / waveout.c
blob62bf37ac3fdb78addca3c2ae7e153c44a7bf9da6
1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2009 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * André Weber
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <math.h>
35 #ifndef UNICODE
36 # define UNICODE
37 #endif
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_aout.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 /*****************************************************************************
48 * Local prototypes
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;
60 struct lkwavehdr
62 WAVEHDR hdr;
63 struct lkwavehdr * p_next;
66 /* local functions */
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 *,
72 block_t *, bool );
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 *****************************************************************************/
99 struct aout_sys_t
101 HWAVEOUT h_waveout; /* handle to waveout instance */
103 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
105 size_t i_frames;
107 int i_repeat_counter;
109 int i_buffer_size;
111 int i_rate;
113 uint8_t *p_silence_buffer; /* buffer we use to play silence */
115 float f_volume;
117 bool b_spdif;
118 bool b_mute;
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];
123 vlc_fourcc_t format;
125 vlc_tick_t i_played_length;
127 struct lkwavehdr * p_free_list;
129 vlc_mutex_t lock;
130 vlc_cond_t cond;
131 vlc_timer_t volume_poll_timer;
134 /*****************************************************************************
135 * Module descriptor
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 "\
140 "to apply.")
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")
149 vlc_module_begin ()
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 )
165 vlc_module_end ()
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 )
175 return VLC_EGENERIC;
177 p_aout->time_get = WaveOutTimeGet;
178 p_aout->play = Play;
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 */
185 sys->b_soft = true;
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 );
193 free( 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 )
218 == VLC_SUCCESS )
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;
226 sys->b_spdif = true;
229 else
230 msg_Err( p_aout,
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;
247 switch(i_channels)
249 case 9:
250 fmt->i_physical_channels = AOUT_CHANS_8_1;
251 break;
252 case 8:
253 fmt->i_physical_channels = AOUT_CHANS_7_1;
254 break;
255 case 7:
256 fmt->i_physical_channels = AOUT_CHANS_7_0;
257 break;
258 case 6:
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;
262 break;
263 case 5:
264 fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
265 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
266 | AOUT_CHAN_LFE;
267 break;
268 case 4:
269 fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
270 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
271 break;
272 case 3:
273 fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
274 | AOUT_CHAN_LFE;
275 break;
276 case 2:
277 fmt->i_physical_channels = AOUT_CHANS_STEREO;
278 break;
279 case 1:
280 default:
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 ) &&
288 --i_channels );
290 if( !i_channels )
292 msg_Err(p_aout, "Waveout couldn't find appropriate channel mapping");
293 return VLC_EGENERIC;
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 );
303 sys->b_soft = false;
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");
321 return VLC_ENOMEM;
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 */
331 sys->i_frames = 0;
332 sys->i_played_length = 0;
333 sys->p_free_list = NULL;
335 fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
337 return VLC_SUCCESS;
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));
352 if(!p_waveheader)
354 msg_Err(p_aout, "Couldn't alloc WAVEHDR");
355 if( block )
356 block_Release( block );
357 return;
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 );
376 WaveOutClean( sys );
377 WaveoutPollVolume( p_aout );
379 vlc_mutex_lock( &sys->lock );
380 sys->i_frames++;
381 sys->i_played_length += block->i_length;
382 vlc_mutex_unlock( &sys->lock );
383 (void) date;
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,
437 bool b_probe )
439 MMRESULT result;
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];
451 switch( i_format )
453 case VLC_CODEC_SPDIFL:
454 i_nb_channels = 2;
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;
462 break;
464 case VLC_CODEC_FL32:
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;
470 break;
472 case VLC_CODEC_S16N:
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;
478 break;
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;
493 else
495 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
496 waveformat.Format.cbSize =
497 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
500 if(!b_probe) {
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" );
532 return VLC_EGENERIC;
534 if( result == MMSYSERR_ALLOCATED )
536 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
537 return VLC_EGENERIC;
539 if( result != MMSYSERR_NOERROR )
541 msg_Warn( p_aout, "waveOutOpen failed" );
542 return VLC_EGENERIC;
545 sys->chans_to_reorder =
546 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
547 waveformat.dwChannelMask,
548 sys->chan_table );
549 if( sys->chans_to_reorder )
550 msg_Dbg( p_aout, "channel reordering needed" );
551 sys->format = i_format;
553 return VLC_SUCCESS;
555 #undef waveformat
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,
565 bool b_probe )
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 )
571 != VLC_SUCCESS )
573 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16N,
574 i_channels, i_nb_channels, i_rate, b_probe )
575 != VLC_SUCCESS )
577 return VLC_EGENERIC;
579 else
581 *i_format = VLC_CODEC_S16N;
582 return VLC_SUCCESS;
585 else
587 *i_format = VLC_CODEC_FL32;
588 return VLC_SUCCESS;
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)
598 MMRESULT result;
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
610 a hickup)
612 if(b_spdif)
614 memcpy( sys->p_silence_buffer,
615 p_buffer->p_buffer,
616 sys->i_buffer_size );
617 sys->i_repeat_counter = 2;
619 } else {
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" );
641 return VLC_EGENERIC;
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" );
649 return VLC_EGENERIC;
652 return VLC_SUCCESS;
655 /*****************************************************************************
656 * WaveOutCallback: what to do once WaveOut has played its sound samples
657 *****************************************************************************/
658 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
659 DWORD_PTR _p_aout,
660 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
662 (void) h_waveout;
663 (void) 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;
672 sys->i_frames--;
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);
686 while( p_list )
688 p_whdr = p_list;
689 p_list = p_list->p_next;
690 WaveOutClearBuffer( p_sys->h_waveout, &p_whdr->hdr );
691 free(p_whdr);
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") );
720 n++;
722 for(int i = 0; i < nb_devices; i++)
724 WAVEOUTCAPS caps;
725 wchar_t dev_name[MAXPNAMELEN+32];
727 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
728 != MMSYSERR_NOERROR)
729 continue;
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] );
735 n++;
738 return 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
745 should be used.
747 static uint32_t findDeviceID(char *psz_device_name)
749 if( !psz_device_name )
750 return WAVE_MAPPER;
752 uint32_t wave_devices = waveOutGetNumDevs();
754 for( uint32_t i = 0; i < wave_devices; i++ )
756 WAVEOUTCAPS caps;
757 wchar_t dev_name[MAXPNAMELEN+32];
759 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
760 != MMSYSERR_NOERROR )
761 continue;
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) )
768 free( u8 );
769 return i;
771 free( u8 );
774 return WAVE_MAPPER;
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);
782 return 0;
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))
791 return VLC_ENOMEM;
792 aout->sys = sys;
793 aout->start = Start;
794 aout->stop = Stop;
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" );
809 free( sys );
810 return VLC_ENOMEM;
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 */
817 char **ids, **names;
818 int count = ReloadWaveoutDevices(NULL, &ids, &names);
819 if (count >= 0)
821 for (int i = 0; i < count; i++)
823 aout_HotplugReport(aout, ids[i], names[i]);
824 free(names[i]);
825 free(ids[i]);
827 free(names);
828 free(ids);
831 char *dev = var_CreateGetNonEmptyString(aout, "waveout-audio-device");
832 aout_DeviceReport(aout, dev);
833 free(dev);
835 return VLC_SUCCESS;
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 );
849 free(sys);
852 static int WaveOutTimeGet(audio_output_t * p_aout, vlc_tick_t *delay)
854 MMTIME mmtime;
855 mmtime.wType = TIME_SAMPLES;
856 aout_sys_t *sys = p_aout->sys;
858 if( !sys->i_frames )
859 return -1;
861 if( waveOutGetPosition( sys->h_waveout, &mmtime, sizeof(MMTIME) )
862 != MMSYSERR_NOERROR )
864 msg_Err( p_aout, "waveOutGetPosition failed");
865 return -1;
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;
870 return 0;
873 static void WaveOutFlush( audio_output_t *p_aout, bool wait)
875 MMRESULT res;
876 aout_sys_t *sys = p_aout->sys;
878 if( !wait )
880 res = waveOutReset( sys->h_waveout );
881 sys->i_played_length = 0;
882 if( res != MMSYSERR_NOERROR )
883 msg_Err( p_aout, "waveOutReset failed");
885 else
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)
898 MMRESULT res;
899 (void) date;
900 aout_sys_t *sys = p_aout->sys;
902 if(pause)
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);
909 return;
912 else
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);
919 return;
924 static int WaveoutVolumeSet( audio_output_t *p_aout, float volume )
926 aout_sys_t *sys = p_aout->sys;
928 if( sys->b_soft )
930 float gain = volume * volume * volume;
931 if ( !sys->b_mute && aout_GainRequest( p_aout, gain ) )
932 return -1;
934 else
936 const HWAVEOUT hwo = sys->h_waveout;
938 uint32_t vol = lroundf( volume * 0x7fff.fp0 );
940 if( !sys->b_mute )
942 if( vol > 0xffff )
944 vol = 0xffff;
945 volume = 2.0f;
948 MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
949 if( r != MMSYSERR_NOERROR )
951 msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
952 return -1;
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);
966 return 0;
969 static int WaveoutMuteSet( audio_output_t * p_aout, bool mute )
971 aout_sys_t *sys = p_aout->sys;
973 if( sys->b_soft )
975 float gain = sys->f_volume * sys->f_volume * sys->f_volume;
976 if ( aout_GainRequest( p_aout, mute ? 0.f : gain ) )
977 return -1;
979 else
982 const HWAVEOUT hwo = sys->h_waveout;
983 uint32_t vol = mute ? 0 : lroundf( sys->f_volume * 0x7fff.fp0 );
985 if( vol > 0xffff )
986 vol = 0xffff;
988 MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
989 if( r != MMSYSERR_NOERROR )
991 msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
992 return -1;
996 vlc_mutex_lock(&sys->lock);
997 sys->b_mute = mute;
998 aout_MuteReport( p_aout, mute );
999 vlc_mutex_unlock(&sys->lock);
1001 return 0;
1004 static void WaveoutPollVolume( void * _aout )
1006 audio_output_t * aout = (audio_output_t *) _aout;
1007 aout_sys_t *sys = aout->sys;
1008 uint32_t vol;
1010 MMRESULT r = waveOutGetVolume( sys->h_waveout, (LPDWORD) &vol );
1012 if( r != MMSYSERR_NOERROR )
1014 msg_Err( aout, "waveOutGetVolume failed (%u)", r );
1015 return;
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);
1033 return;