00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <string.h>
00028 #include <stdlib.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/aout.h>
00032 #include "aout_internal.h"
00033
00034 #include <windows.h>
00035 #include <mmsystem.h>
00036
00037 #define FRAME_SIZE 4096
00038 #define FRAMES_NUM 8
00039
00040
00041
00042
00043 #ifdef UNDER_CE
00044 # define DWORD_PTR DWORD
00045 # ifdef waveOutGetDevCaps
00046 # undef waveOutGetDevCaps
00047 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
00048 # endif
00049 #endif
00050
00051 #ifndef WAVE_FORMAT_IEEE_FLOAT
00052 # define WAVE_FORMAT_IEEE_FLOAT 0x0003
00053 #endif
00054
00055 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
00056 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
00057 #endif
00058
00059 #ifndef WAVE_FORMAT_EXTENSIBLE
00060 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
00061 #endif
00062
00063 #ifndef SPEAKER_FRONT_LEFT
00064 # define SPEAKER_FRONT_LEFT 0x1
00065 # define SPEAKER_FRONT_RIGHT 0x2
00066 # define SPEAKER_FRONT_CENTER 0x4
00067 # define SPEAKER_LOW_FREQUENCY 0x8
00068 # define SPEAKER_BACK_LEFT 0x10
00069 # define SPEAKER_BACK_RIGHT 0x20
00070 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
00071 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
00072 # define SPEAKER_BACK_CENTER 0x100
00073 # define SPEAKER_SIDE_LEFT 0x200
00074 # define SPEAKER_SIDE_RIGHT 0x400
00075 # define SPEAKER_TOP_CENTER 0x800
00076 # define SPEAKER_TOP_FRONT_LEFT 0x1000
00077 # define SPEAKER_TOP_FRONT_CENTER 0x2000
00078 # define SPEAKER_TOP_FRONT_RIGHT 0x4000
00079 # define SPEAKER_TOP_BACK_LEFT 0x8000
00080 # define SPEAKER_TOP_BACK_CENTER 0x10000
00081 # define SPEAKER_TOP_BACK_RIGHT 0x20000
00082 # define SPEAKER_RESERVED 0x80000000
00083 #endif
00084
00085 #ifndef _WAVEFORMATEXTENSIBLE_
00086 typedef struct {
00087 WAVEFORMATEX Format;
00088 union {
00089 WORD wValidBitsPerSample;
00090 WORD wSamplesPerBlock;
00091 WORD wReserved;
00092 } Samples;
00093 DWORD dwChannelMask;
00094
00095 GUID SubFormat;
00096 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
00097 #endif
00098
00099 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
00100 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
00101 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
00102
00103
00104
00105
00106 static int Open ( vlc_object_t * );
00107 static void Close ( vlc_object_t * );
00108 static void Play ( aout_instance_t * );
00109
00110
00111
00112
00113 typedef struct notification_thread_t
00114 {
00115 VLC_COMMON_MEMBERS
00116 aout_instance_t *p_aout;
00117
00118 } notification_thread_t;
00119
00120
00121 static void Probe ( aout_instance_t * );
00122 static int OpenWaveOut ( aout_instance_t *, int, int, int, int, vlc_bool_t );
00123 static int OpenWaveOutPCM( aout_instance_t *, int*, int, int, int, vlc_bool_t );
00124 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
00125 aout_buffer_t * );
00126
00127 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
00128 static void WaveOutThread( notification_thread_t * );
00129
00130 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
00131 static int VolumeGet( aout_instance_t *, audio_volume_t * );
00132 static int VolumeSet( aout_instance_t *, audio_volume_t );
00133
00134
00135
00136
00137 #define FLOAT_TEXT N_("Use float32 output")
00138 #define FLOAT_LONGTEXT N_( \
00139 "The option allows you to enable or disable the high-quality float32 " \
00140 "audio output mode (which is not well supported by some soundcards)." )
00141
00142 vlc_module_begin();
00143 set_shortname( "WaveOut" );
00144 set_description( _("Win32 waveOut extension output") );
00145 set_capability( "audio output", 50 );
00146 set_category( CAT_AUDIO );
00147 set_subcategory( SUBCAT_AUDIO_AOUT );
00148 add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE );
00149 set_callbacks( Open, Close );
00150 vlc_module_end();
00151
00152
00153
00154
00155
00156
00157
00158 struct aout_sys_t
00159 {
00160 HWAVEOUT h_waveout;
00161
00162 WAVEFORMATEXTENSIBLE waveformat;
00163
00164 WAVEHDR waveheader[FRAMES_NUM];
00165
00166 notification_thread_t *p_notif;
00167 HANDLE event;
00168
00169 int i_buffer_size;
00170
00171 byte_t *p_silence_buffer;
00172
00173 vlc_bool_t b_chan_reorder;
00174 int pi_chan_table[AOUT_CHAN_MAX];
00175 };
00176
00177 static const uint32_t pi_channels_src[] =
00178 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00179 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
00180 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00181 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
00182 static const uint32_t pi_channels_in[] =
00183 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
00184 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
00185 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
00186 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
00187 static const uint32_t pi_channels_out[] =
00188 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
00189 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
00190 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
00191 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
00192
00193
00194
00195
00196
00197
00198 static int Open( vlc_object_t *p_this )
00199 {
00200 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00201 vlc_value_t val;
00202 int i;
00203
00204
00205 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
00206
00207 if( p_aout->output.p_sys == NULL )
00208 {
00209 msg_Err( p_aout, "out of memory" );
00210 return VLC_EGENERIC;
00211 }
00212
00213 p_aout->output.pf_play = Play;
00214 p_aout->b_die = VLC_FALSE;
00215
00216 if( var_Type( p_aout, "audio-device" ) == 0 )
00217 {
00218 Probe( p_aout );
00219 }
00220
00221 if( var_Get( p_aout, "audio-device", &val ) < 0 )
00222 {
00223
00224 free( p_aout->output.p_sys );
00225 return VLC_EGENERIC;
00226 }
00227
00228 var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00229
00230
00231 if( val.i_int == AOUT_VAR_SPDIF )
00232 {
00233 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
00234
00235 if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'),
00236 p_aout->output.output.i_physical_channels,
00237 aout_FormatNbChannels( &p_aout->output.output ),
00238 p_aout->output.output.i_rate, VLC_FALSE )
00239 != VLC_SUCCESS )
00240 {
00241 msg_Err( p_aout, "cannot open waveout audio device" );
00242 free( p_aout->output.p_sys );
00243 return VLC_EGENERIC;
00244 }
00245
00246
00247 p_aout->output.i_nb_samples = A52_FRAME_NB;
00248 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
00249 p_aout->output.output.i_frame_length = A52_FRAME_NB;
00250 p_aout->output.p_sys->i_buffer_size =
00251 p_aout->output.output.i_bytes_per_frame;
00252
00253 aout_VolumeNoneInit( p_aout );
00254 }
00255 else
00256 {
00257 WAVEOUTCAPS wocaps;
00258
00259 if( val.i_int == AOUT_VAR_5_1 )
00260 {
00261 p_aout->output.output.i_physical_channels
00262 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00263 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
00264 | AOUT_CHAN_LFE;
00265 }
00266 else if( val.i_int == AOUT_VAR_2F2R )
00267 {
00268 p_aout->output.output.i_physical_channels
00269 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00270 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00271 }
00272 else if( val.i_int == AOUT_VAR_MONO )
00273 {
00274 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
00275 }
00276 else
00277 {
00278 p_aout->output.output.i_physical_channels
00279 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00280 }
00281
00282 if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format,
00283 p_aout->output.output.i_physical_channels,
00284 aout_FormatNbChannels( &p_aout->output.output ),
00285 p_aout->output.output.i_rate, VLC_FALSE )
00286 != VLC_SUCCESS )
00287 {
00288 msg_Err( p_aout, "cannot open waveout audio device" );
00289 free( p_aout->output.p_sys );
00290 return VLC_EGENERIC;
00291 }
00292
00293
00294 p_aout->output.i_nb_samples = FRAME_SIZE;
00295 aout_FormatPrepare( &p_aout->output.output );
00296 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
00297 p_aout->output.output.i_bytes_per_frame;
00298
00299 aout_VolumeSoftInit( p_aout );
00300
00301
00302 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
00303 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
00304 wocaps.dwSupport & WAVECAPS_VOLUME )
00305 {
00306 DWORD i_dummy;
00307 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
00308 == MMSYSERR_NOERROR )
00309 {
00310 p_aout->output.pf_volume_infos = VolumeInfos;
00311 p_aout->output.pf_volume_get = VolumeGet;
00312 p_aout->output.pf_volume_set = VolumeSet;
00313 }
00314 }
00315 }
00316
00317
00318 waveOutReset( p_aout->output.p_sys->h_waveout );
00319
00320
00321 p_aout->output.p_sys->p_silence_buffer =
00322 malloc( p_aout->output.p_sys->i_buffer_size );
00323 if( p_aout->output.p_sys->p_silence_buffer == NULL )
00324 {
00325 free( p_aout->output.p_sys );
00326 msg_Err( p_aout, "out of memory" );
00327 return 1;
00328 }
00329
00330
00331 memset( p_aout->output.p_sys->p_silence_buffer, 0,
00332 p_aout->output.p_sys->i_buffer_size );
00333
00334
00335 p_aout->output.p_sys->p_notif =
00336 vlc_object_create( p_aout, sizeof(notification_thread_t) );
00337 p_aout->output.p_sys->p_notif->p_aout = p_aout;
00338 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
00339
00340
00341 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
00342 "waveOut Notification Thread", WaveOutThread,
00343 VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
00344 {
00345 msg_Err( p_aout, "cannot create WaveOutThread" );
00346 }
00347
00348
00349
00350 for( i = 0; i < FRAMES_NUM; i++ )
00351 {
00352 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
00353 p_aout->output.p_sys->waveheader[i].dwUser = 0;
00354 }
00355 PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
00356 &p_aout->output.p_sys->waveheader[0], NULL );
00357
00358 return 0;
00359 }
00360
00361
00362
00363
00364 static void Probe( aout_instance_t * p_aout )
00365 {
00366 vlc_value_t val, text;
00367 int i_format;
00368 unsigned int i_physical_channels;
00369
00370 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
00371 text.psz_string = _("Audio Device");
00372 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
00373
00374
00375 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00376 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
00377 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
00378 if( p_aout->output.output.i_physical_channels == i_physical_channels )
00379 {
00380 if( OpenWaveOutPCM( p_aout, &i_format,
00381 i_physical_channels, 6,
00382 p_aout->output.output.i_rate, VLC_TRUE )
00383 == VLC_SUCCESS )
00384 {
00385 val.i_int = AOUT_VAR_5_1;
00386 text.psz_string = N_("5.1");
00387 var_Change( p_aout, "audio-device",
00388 VLC_VAR_ADDCHOICE, &val, &text );
00389 msg_Dbg( p_aout, "device supports 5.1 channels" );
00390 }
00391 }
00392
00393
00394 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00395 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00396 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
00397 == i_physical_channels )
00398 {
00399 if( OpenWaveOutPCM( p_aout, &i_format,
00400 i_physical_channels, 4,
00401 p_aout->output.output.i_rate, VLC_TRUE )
00402 == VLC_SUCCESS )
00403 {
00404 val.i_int = AOUT_VAR_2F2R;
00405 text.psz_string = N_("2 Front 2 Rear");
00406 var_Change( p_aout, "audio-device",
00407 VLC_VAR_ADDCHOICE, &val, &text );
00408 msg_Dbg( p_aout, "device supports 4 channels" );
00409 }
00410 }
00411
00412
00413 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00414 if( OpenWaveOutPCM( p_aout, &i_format,
00415 i_physical_channels, 2,
00416 p_aout->output.output.i_rate, VLC_TRUE )
00417 == VLC_SUCCESS )
00418 {
00419 val.i_int = AOUT_VAR_STEREO;
00420 text.psz_string = N_("Stereo");
00421 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
00422 msg_Dbg( p_aout, "device supports 2 channels" );
00423 }
00424
00425
00426 i_physical_channels = AOUT_CHAN_CENTER;
00427 if( OpenWaveOutPCM( p_aout, &i_format,
00428 i_physical_channels, 1,
00429 p_aout->output.output.i_rate, VLC_TRUE )
00430 == VLC_SUCCESS )
00431 {
00432 val.i_int = AOUT_VAR_MONO;
00433 text.psz_string = N_("Mono");
00434 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
00435 msg_Dbg( p_aout, "device supports 1 channel" );
00436 }
00437
00438
00439 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
00440 {
00441 if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'),
00442 p_aout->output.output.i_physical_channels,
00443 aout_FormatNbChannels( &p_aout->output.output ),
00444 p_aout->output.output.i_rate, VLC_TRUE )
00445 == VLC_SUCCESS )
00446 {
00447 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
00448 val.i_int = AOUT_VAR_SPDIF;
00449 text.psz_string = N_("A/52 over S/PDIF");
00450 var_Change( p_aout, "audio-device",
00451 VLC_VAR_ADDCHOICE, &val, &text );
00452 if( config_GetInt( p_aout, "spdif" ) )
00453 var_Set( p_aout, "audio-device", val );
00454 }
00455 }
00456
00457 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
00458 if( val.i_int <= 0 )
00459 {
00460
00461 var_Destroy( p_aout, "audio-device" );
00462 return;
00463 }
00464
00465 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
00466
00467 val.b_bool = VLC_TRUE;
00468 var_Set( p_aout, "intf-change", val );
00469 }
00470
00471
00472
00473
00474
00475
00476
00477 static void Play( aout_instance_t *_p_aout )
00478 {
00479 }
00480
00481
00482
00483
00484 static void Close( vlc_object_t *p_this )
00485 {
00486 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00487 aout_sys_t *p_sys = p_aout->output.p_sys;
00488
00489
00490 p_aout->b_die = VLC_TRUE;
00491
00492 waveOutReset( p_sys->h_waveout );
00493
00494
00495 SetEvent( p_sys->event );
00496 vlc_thread_join( p_sys->p_notif );
00497 vlc_object_destroy( p_sys->p_notif );
00498 CloseHandle( p_sys->event );
00499
00500
00501 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
00502 {
00503 msg_Err( p_aout, "waveOutClose failed" );
00504 }
00505
00506 free( p_sys->p_silence_buffer );
00507 free( p_sys );
00508 }
00509
00510
00511
00512
00513 static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
00514 int i_channels, int i_nb_channels, int i_rate,
00515 vlc_bool_t b_probe )
00516 {
00517 MMRESULT result;
00518 unsigned int i;
00519
00520
00521
00522 #define waveformat p_aout->output.p_sys->waveformat
00523
00524 waveformat.dwChannelMask = 0;
00525 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
00526 {
00527 if( i_channels & pi_channels_src[i] )
00528 waveformat.dwChannelMask |= pi_channels_in[i];
00529 }
00530
00531 switch( i_format )
00532 {
00533 case VLC_FOURCC('s','p','d','i'):
00534 i_nb_channels = 2;
00535
00536 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
00537 waveformat.Format.wBitsPerSample = 16;
00538 waveformat.Samples.wValidBitsPerSample =
00539 waveformat.Format.wBitsPerSample;
00540 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
00541 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
00542 break;
00543
00544 case VLC_FOURCC('f','l','3','2'):
00545 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
00546 waveformat.Samples.wValidBitsPerSample =
00547 waveformat.Format.wBitsPerSample;
00548 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
00549 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
00550 break;
00551
00552 case VLC_FOURCC('s','1','6','l'):
00553 waveformat.Format.wBitsPerSample = 16;
00554 waveformat.Samples.wValidBitsPerSample =
00555 waveformat.Format.wBitsPerSample;
00556 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
00557 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
00558 break;
00559 }
00560
00561 waveformat.Format.nChannels = i_nb_channels;
00562 waveformat.Format.nSamplesPerSec = i_rate;
00563 waveformat.Format.nBlockAlign =
00564 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
00565 waveformat.Format.nAvgBytesPerSec =
00566 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
00567
00568
00569 if( i_nb_channels <= 2 )
00570 {
00571 waveformat.Format.cbSize = 0;
00572 }
00573 else
00574 {
00575 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
00576 waveformat.Format.cbSize =
00577 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
00578 }
00579
00580
00581 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER,
00582 (WAVEFORMATEX *)&waveformat,
00583 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
00584 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
00585 if( result == WAVERR_BADFORMAT )
00586 {
00587 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
00588 return VLC_EGENERIC;
00589 }
00590 if( result == MMSYSERR_ALLOCATED )
00591 {
00592 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
00593 return VLC_EGENERIC;
00594 }
00595 if( result != MMSYSERR_NOERROR )
00596 {
00597 msg_Warn( p_aout, "waveOutOpen failed" );
00598 return VLC_EGENERIC;
00599 }
00600
00601 p_aout->output.p_sys->b_chan_reorder =
00602 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
00603 waveformat.dwChannelMask, i_nb_channels,
00604 p_aout->output.p_sys->pi_chan_table );
00605
00606 if( p_aout->output.p_sys->b_chan_reorder )
00607 {
00608 msg_Dbg( p_aout, "channel reordering needed" );
00609 }
00610
00611 return VLC_SUCCESS;
00612
00613 #undef waveformat
00614
00615 }
00616
00617
00618
00619
00620 static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format,
00621 int i_channels, int i_nb_channels, int i_rate,
00622 vlc_bool_t b_probe )
00623 {
00624 vlc_value_t val;
00625
00626 var_Get( p_aout, "waveout-float32", &val );
00627
00628 if( !val.b_bool || OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'),
00629 i_channels, i_nb_channels, i_rate, b_probe )
00630 != VLC_SUCCESS )
00631 {
00632 if ( OpenWaveOut( p_aout, VLC_FOURCC('s','1','6','l'),
00633 i_channels, i_nb_channels, i_rate, b_probe )
00634 != VLC_SUCCESS )
00635 {
00636 return VLC_EGENERIC;
00637 }
00638 else
00639 {
00640 *i_format = VLC_FOURCC('s','1','6','l');
00641 return VLC_SUCCESS;
00642 }
00643 }
00644 else
00645 {
00646 *i_format = VLC_FOURCC('f','l','3','2');
00647 return VLC_SUCCESS;
00648 }
00649 }
00650
00651
00652
00653
00654 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
00655 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer )
00656 {
00657 MMRESULT result;
00658
00659
00660 if( p_buffer != NULL )
00661 p_waveheader->lpData = p_buffer->p_buffer;
00662 else
00663
00664 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
00665
00666 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
00667 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
00668 p_waveheader->dwFlags = 0;
00669
00670 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
00671 if( result != MMSYSERR_NOERROR )
00672 {
00673 msg_Err( p_aout, "waveOutPrepareHeader failed" );
00674 return VLC_EGENERIC;
00675 }
00676
00677
00678 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
00679 if( result != MMSYSERR_NOERROR )
00680 {
00681 msg_Err( p_aout, "waveOutWrite failed" );
00682 return VLC_EGENERIC;
00683 }
00684
00685 return VLC_SUCCESS;
00686 }
00687
00688
00689
00690
00691 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
00692 DWORD _p_aout,
00693 DWORD dwParam1, DWORD dwParam2 )
00694 {
00695 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
00696 int i, i_queued_frames = 0;
00697
00698 if( uMsg != WOM_DONE ) return;
00699
00700 if( p_aout->b_die ) return;
00701
00702
00703 for( i = 0; i < FRAMES_NUM; i++ )
00704 {
00705
00706 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
00707 {
00708 i_queued_frames++;
00709 }
00710 }
00711
00712
00713 if( i_queued_frames < FRAMES_NUM / 2 )
00714 SetEvent( p_aout->output.p_sys->event );
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724 static void WaveOutThread( notification_thread_t *p_notif )
00725 {
00726 aout_instance_t *p_aout = p_notif->p_aout;
00727 aout_sys_t *p_sys = p_aout->output.p_sys;
00728 aout_buffer_t *p_buffer = NULL;
00729 WAVEHDR *p_waveheader = p_sys->waveheader;
00730 int i, i_queued_frames;
00731 vlc_bool_t b_sleek;
00732
00733
00734 b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
00735
00736 while( 1 )
00737 {
00738 WaitForSingleObject( p_sys->event, INFINITE );
00739
00740
00741 i_queued_frames = 0;
00742 for( i = 0; i < FRAMES_NUM; i++ )
00743 {
00744 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
00745 p_waveheader[i].dwUser )
00746 {
00747
00748 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
00749 sizeof(WAVEHDR) );
00750
00751 if( p_waveheader[i].dwUser != 1 )
00752 aout_BufferFree( (aout_buffer_t *)p_waveheader[i].dwUser );
00753
00754 p_waveheader[i].dwUser = 0;
00755 }
00756
00757
00758 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
00759 {
00760 i_queued_frames++;
00761 }
00762 }
00763
00764 if( p_aout->b_die ) return;
00765
00766
00767 for( i = 0; i < FRAMES_NUM; i++ )
00768 {
00769
00770 if( p_waveheader[i].dwFlags & WHDR_DONE )
00771 {
00772
00773 p_buffer = aout_OutputNextBuffer( p_aout,
00774 mdate() + 1000000 * i_queued_frames /
00775 p_aout->output.output.i_rate * p_aout->output.i_nb_samples,
00776 b_sleek );
00777
00778 if( !p_buffer && i_queued_frames )
00779 {
00780
00781 break;
00782 }
00783
00784
00785 if( p_buffer && p_sys->b_chan_reorder )
00786 {
00787 aout_ChannelReorder( p_buffer->p_buffer,
00788 p_buffer->i_nb_bytes,
00789 p_sys->waveformat.Format.nChannels,
00790 p_sys->pi_chan_table,
00791 p_sys->waveformat.Format.wBitsPerSample );
00792 }
00793
00794 PlayWaveOut( p_aout, p_sys->h_waveout,
00795 &p_waveheader[i], p_buffer );
00796
00797 i_queued_frames++;
00798 }
00799 }
00800 }
00801 }
00802
00803 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
00804 {
00805 *pi_soft = AOUT_VOLUME_MAX / 2;
00806 return 0;
00807 }
00808
00809 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
00810 {
00811 DWORD i_waveout_vol;
00812
00813 #ifdef UNDER_CE
00814 waveOutGetVolume( 0, &i_waveout_vol );
00815 #else
00816 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
00817 #endif
00818
00819 i_waveout_vol &= 0xFFFF;
00820 *pi_volume = p_aout->output.i_volume =
00821 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF ) / 2 / 0xFFFF;
00822 return 0;
00823 }
00824
00825 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
00826 {
00827 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
00828 i_waveout_vol |= (i_waveout_vol << 16);
00829
00830 #ifdef UNDER_CE
00831 waveOutSetVolume( 0, i_waveout_vol );
00832 #else
00833 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
00834 #endif
00835
00836 p_aout->output.i_volume = i_volume;
00837 return 0;
00838 }