Ticket #6538: aodx_trunk.patch
File aodx_trunk.patch, 37.2 KB (added by , 15 years ago) |
---|
-
libs/libmyth/audiooutputdx.h
1 1 #ifndef AUDIOOUTPUTDX 2 2 #define AUDIOOUTPUTDX 3 3 4 /* ACK! <windows.h> and <dsound.h> should only be in cpp's compiled5 * in windows only. Some of the variables in AudioOutputDX need to6 * be moved to a private class before removing these includes though.7 */8 #include <windows.h> // HACK HACK HACK9 #include <dsound.h> // HACK HACK HACK10 11 4 // MythTV headers 12 5 #include "audiooutputbase.h" 13 6 7 class AudioOutputDXPrivate; 8 14 9 class AudioOutputDX : public AudioOutputBase 15 10 { 16 public: 11 friend class AudioOutputDXPrivate; 12 public: 17 13 AudioOutputDX(const AudioSettings &settings); 18 14 virtual ~AudioOutputDX(); 19 15 20 /// BEGIN HACK HACK HACK HACK These need to actually be implemented!21 bool OpenDevice(void) { return false; }22 virtual void CloseDevice(void) {}23 virtual void WriteAudio(unsigned char*, int) {}24 virtual int GetSpaceOnSoundcard(void) const { return 0; }25 virtual int GetBufferedOnSoundcard(void) const { return 0; }26 #warning Several methods in AudioOutputDX need to be implemented...27 /// END HACK HACK HACK HACK28 29 virtual void Reset(void);30 virtual void Reconfigure(const AudioSettings &settings);31 virtual void SetBlocking(bool blocking);32 33 virtual bool AddSamples(char *buffer, int samples, long long timecode);34 virtual bool AddSamples(char *buffers[], int samples, long long timecode);35 virtual void SetEffDsp(int dsprate);36 virtual void SetTimecode(long long timecode);37 38 virtual bool IsPaused(void) const { return paused; }39 virtual void Pause(bool paused);40 41 virtual void Drain(void);42 43 virtual int GetAudiotime(void);44 45 16 // Volume control 46 17 virtual int GetVolumeChannel(int channel) const; // Returns 0-100 47 18 virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol 48 19 49 private: 50 HINSTANCE dsound_dll; /* handle of the opened dsound dll */ 51 LPDIRECTSOUND dsobject; 52 LPDIRECTSOUNDBUFFER dsbuffer; /* the sound buffer we use (direct sound 53 * takes care of mixing all the 54 * secondary buffers into the primary) */ 55 LPDIRECTSOUNDNOTIFY dsnotify; /* the position notify interface */ 56 DSBPOSITIONNOTIFY notif[4]; 20 protected: 21 virtual bool OpenDevice(void); 22 virtual void CloseDevice(void); 23 virtual void WriteAudio(unsigned char *aubuf, int size); 24 virtual void Pause(bool pause); 25 virtual int GetSpaceOnSoundcard(void) const; 26 virtual int GetBufferedOnSoundcard(void) const; 57 27 58 DWORD write_cursor; 59 DWORD buffer_size; 60 bool blocking; 61 62 bool awaiting_data; 63 64 int effdsp; // from the recorded stream 65 int audio_bytes_per_sample; 66 int audio_bits; 67 int audio_channels; 68 int audbuf_timecode; /* timecode of audio most recently placed into 69 buffer */ 70 bool can_hw_pause; 71 bool paused; 72 73 int InitDirectSound(); 74 int CreateDSBuffer(int audio_bits, int audio_channels, int audio_samplerate, bool b_probe); 75 void DestroyDSBuffer(); 76 int FillBuffer(int frames, char *buffer); 28 protected: 29 AudioOutputDXPrivate *m_priv; 30 bool m_PlayStarted; 31 DWORD m_WriteCursor; 32 bool m_UseSPDIF; 33 static const uint kFramesNum; 77 34 }; 78 35 79 36 #endif // AUDIOOUTPUTDX -
libs/libmyth/audiooutputdx.cpp
1 1 #include <iostream> 2 #include <cmath> 2 3 //#include <stdlib.h> 3 4 4 5 using namespace std; … … 10 11 #include <mmsystem.h> 11 12 #include <dsound.h> 12 13 13 #define FRAMES_NUM 65536 14 #define LOC QString("AODX: ") 15 #define LOC_ERR QString("AODX, ERROR: ") 14 16 17 const uint AudioOutputDX::kFramesNum = 32; 18 15 19 /***************************************************************************** 16 20 * DirectSound GUIDs. 17 21 * Defining them here allows us to get rid of the dxguid library during … … 23 27 /***************************************************************************** 24 28 * Useful macros 25 29 *****************************************************************************/ 26 #ifndef WAVE_FORMAT_IEEE_FLOAT27 # define WAVE_FORMAT_IEEE_FLOAT 0x000328 #endif29 30 30 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF 31 31 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 32 32 #endif … … 35 35 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE 36 36 #endif 37 37 38 #ifndef SPEAKER_FRONT_LEFT39 # define SPEAKER_FRONT_LEFT 0x140 # define SPEAKER_FRONT_RIGHT 0x241 # define SPEAKER_FRONT_CENTER 0x442 # define SPEAKER_LOW_FREQUENCY 0x843 # define SPEAKER_BACK_LEFT 0x1044 # define SPEAKER_BACK_RIGHT 0x2045 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x4046 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x8047 # define SPEAKER_BACK_CENTER 0x10048 # define SPEAKER_SIDE_LEFT 0x20049 # define SPEAKER_SIDE_RIGHT 0x40050 # define SPEAKER_TOP_CENTER 0x80051 # define SPEAKER_TOP_FRONT_LEFT 0x100052 # define SPEAKER_TOP_FRONT_CENTER 0x200053 # define SPEAKER_TOP_FRONT_RIGHT 0x400054 # define SPEAKER_TOP_BACK_LEFT 0x800055 # define SPEAKER_TOP_BACK_CENTER 0x1000056 # define SPEAKER_TOP_BACK_RIGHT 0x2000057 # define SPEAKER_RESERVED 0x8000000058 #endif59 60 #ifndef DSSPEAKER_HEADPHONE61 # define DSSPEAKER_HEADPHONE 0x0000000162 #endif63 #ifndef DSSPEAKER_MONO64 # define DSSPEAKER_MONO 0x0000000265 #endif66 #ifndef DSSPEAKER_QUAD67 # define DSSPEAKER_QUAD 0x0000000368 #endif69 #ifndef DSSPEAKER_STEREO70 # define DSSPEAKER_STEREO 0x0000000471 #endif72 #ifndef DSSPEAKER_SURROUND73 # define DSSPEAKER_SURROUND 0x0000000574 #endif75 #ifndef DSSPEAKER_5POINT176 # define DSSPEAKER_5POINT1 0x0000000677 #endif78 79 38 #ifndef _WAVEFORMATEXTENSIBLE_ 80 39 typedef struct { 81 40 WAVEFORMATEX Format; … … 90 49 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; 91 50 #endif 92 51 93 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );94 52 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); 95 53 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); 96 54 97 98 AudioOutputDX::AudioOutputDX(const AudioSettings &settings) : 99 AudioOutputBase(settings), 100 dsound_dll(NULL), 101 dsobject(NULL), 102 dsbuffer(NULL), 103 write_cursor(0), 104 buffer_size(0), 105 blocking(false), 106 awaiting_data(false), 107 effdsp(0), /* Should this be audio_bits ? */ 108 audio_bytes_per_sample(0), /* ACK! hides version in AudioOutputBase */ 109 audio_bits(0), /* ACK! hides version in AudioOutputBase */ 110 audio_channels(0), /* ACK! hides version in AudioOutputBase */ 111 audbuf_timecode(0), 112 can_hw_pause(false), 113 paused(false) 55 class AudioOutputDXPrivate 114 56 { 115 InitDirectSound(); 116 117 Reconfigure(settings); 118 } 119 120 void AudioOutputDX::SetBlocking(bool blocking) 121 { 122 // FIXME: kedl: not sure what else could be required here? 123 } 124 125 void AudioOutputDX::Reconfigure(const AudioSettings &settings) 126 { 127 if (dsbuffer) 128 DestroyDSBuffer(); 129 130 CreateDSBuffer(settings.bits, settings.channels, settings.samplerate, false); 131 132 awaiting_data = true; 133 paused = true; 134 135 effdsp = settings.samplerate; 136 this->audio_bits = settings.bits; 137 this->audio_channels = settings.channels; 138 this->audio_passthru = settings.use_passthru; 139 } 140 141 AudioOutputDX::~AudioOutputDX() 142 { 143 DestroyDSBuffer(); 144 145 /* release the DirectSound object */ 146 if (dsobject) 147 IDirectSound_Release(dsobject); 148 149 /* free DSOUND.DLL */ 150 if (dsound_dll) 151 FreeLibrary(dsound_dll); 152 } 153 154 void AudioOutputDX::Reset(void) 155 { 156 audbuf_timecode = 0; 157 awaiting_data = true; 158 write_cursor = 0; 159 160 if (dsbuffer) 161 { 162 IDirectSoundBuffer_Stop(dsbuffer); 163 IDirectSoundBuffer_SetCurrentPosition(dsbuffer, 0); 164 } 165 166 } 167 168 bool AudioOutputDX::AddSamples(char *buffer, int frames, long long timecode) 169 { 170 FillBuffer(frames, buffer); 171 172 HRESULT dsresult; 173 174 if (awaiting_data) 175 { 176 // dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING); 177 // if (dsresult == DSERR_BUFFERLOST) 178 // { 179 // IDirectSoundBuffer_Restore(dsbuffer); 180 // dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING ); 181 // } 182 // if (dsresult != DS_OK) 183 // { 184 // VERBOSE(VB_IMPORTANT, "cannot start playing buffer" ); 185 // } 186 187 awaiting_data = false; 188 } 189 190 191 192 // VERBOSE(VB_IMPORTANT, "add_samples(a) " << frames << " " << timecode); 193 194 if (timecode < 0) 195 timecode = audbuf_timecode; // add to current timecode 196 197 /* we want the time at the end -- but the file format stores 198 time at the start of the chunk. */ 199 audbuf_timecode = timecode + (int)((frames*1000.0) / effdsp); 200 201 return true; 202 } 203 204 205 bool AudioOutputDX::AddSamples(char *buffers[], int frames, long long timecode) 206 { 207 // VERBOSE(VB_IMPORTANT, "add_samples(b) " << frames << " " << timecode); 208 209 /* int err; 210 int waud=0; 211 int audio_bytes = audio_bits / 8; 212 int audbufsize = frames*audio_bytes*audio_channels; 213 char *audiobuffer = (char *) calloc(1,audbufsize); 214 215 if (audiobuffer==NULL) 216 { 217 fprintf(stderr, "couldn't get memory to write audio to artsd\n"); 218 return; 219 } 220 221 if (pcm_handle == NULL) 222 { 223 free(audiobuffer); 224 return; 225 } 226 227 for (int itemp = 0; itemp < frames*audio_bytes; itemp+=audio_bytes) 228 { 229 for(int chan = 0; chan < audio_channels; chan++) 57 public: 58 AudioOutputDXPrivate() : 59 dsound_dll(NULL), 60 dsobject(NULL), 61 dsbuffer(NULL) 230 62 { 231 audiobuffer[waud++] = buffers[chan][itemp]; 232 if (audio_bits == 16) 233 audiobuffer[waud++] = buffers[chan][itemp+1]; 234 if (waud >= audbufsize) 235 waud -= audbufsize; 63 InitDirectSound(); 236 64 } 237 }238 65 239 err = arts_write(pcm_handle, audiobuffer, frames*4); 240 free(audiobuffer); 66 ~AudioOutputDXPrivate() 67 { 68 DestroyDSBuffer(); 241 69 242 if (err < 0) 243 { 244 fprintf(stderr, "arts_write error: %s\n", arts_error_text(err)); 245 return; 246 } 247 248 if (timecode < 0) 249 timecode = audbuf_timecode; // add to current timecode*/ 70 if (dsobject) 71 IDirectSound_Release(dsobject); 250 72 251 /* we want the time at the end -- but the file format stores252 time at the start of the chunk. */253 //audbuf_timecode = timecode + (int)((frames*100000.0) / effdsp);73 if (dsound_dll) 74 FreeLibrary(dsound_dll); 75 } 254 76 255 return true; 256 } 77 int InitDirectSound(void); 78 void DestroyDSBuffer(void); 79 bool StartPlayback(void); 257 80 258 void AudioOutputDX::SetTimecode(long long timecode) 259 { 260 audbuf_timecode = timecode; 261 } 81 public: 82 HINSTANCE dsound_dll; 83 LPDIRECTSOUND dsobject; 84 LPDIRECTSOUNDBUFFER dsbuffer; 85 }; 262 86 263 void AudioOutputDX::SetEffDsp(int dsprate)264 {265 VERBOSE(VB_IMPORTANT, "setting dsprate = " << dsprate);266 267 HRESULT dsresult;268 87 269 dsresult = IDirectSoundBuffer_SetFrequency(dsbuffer, dsprate / 100); 270 271 if (dsresult != DS_OK) 272 { 273 VERBOSE(VB_IMPORTANT, "cannot set frequency"); 274 } 275 276 effdsp = dsprate / 100; 277 } 278 279 void AudioOutputDX::Pause(bool pause) 88 AudioOutputDX::AudioOutputDX(const AudioSettings &settings) : 89 AudioOutputBase(settings), 90 m_priv(new AudioOutputDXPrivate()), 91 m_PlayStarted(false), 92 m_WriteCursor(0), 93 m_UseSPDIF(settings.use_passthru) 280 94 { 281 HRESULT dsresult; 282 283 VERBOSE(VB_IMPORTANT, "pause: " << pause); 284 285 if (pause == paused) 286 return; 287 288 if (paused) 289 { 290 VERBOSE(VB_IMPORTANT, "unpausing"); 291 292 dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING); 293 if (dsresult == DSERR_BUFFERLOST) 294 { 295 IDirectSoundBuffer_Restore(dsbuffer); 296 dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING ); 297 } 298 if (dsresult != DS_OK) 299 { 300 VERBOSE(VB_IMPORTANT, "cannot start playing buffer" ); 301 } 302 } 303 else 304 { 305 VERBOSE(VB_IMPORTANT, "pausing"); 306 307 IDirectSoundBuffer_Stop(dsbuffer); 308 } 309 310 paused = pause; 95 Reconfigure(settings); 311 96 } 312 97 313 int AudioOutputDX::GetAudiotime(void)98 AudioOutputDX::~AudioOutputDX() 314 99 { 315 DWORD play_pos; 316 HRESULT dsresult; 100 KillAudio(); 317 101 318 dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, NULL); 319 320 if (dsresult != DS_OK) 102 if (m_priv) 321 103 { 322 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");323 return -1;104 delete m_priv; 105 m_priv = NULL; 324 106 } 325 326 int frames = (write_cursor - play_pos) / audio_bytes_per_sample;327 328 if (frames < 0)329 frames += buffer_size;330 331 return audbuf_timecode - (int)((frames*1000.0) / effdsp);332 107 } 333 108 334 335 109 typedef HRESULT (WINAPI *LPFNDSC) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN); 336 110 337 /***************************************************************************** 338 * InitDirectSound: handle all the gory details of DirectSound initialisation 339 *****************************************************************************/ 340 int AudioOutputDX::InitDirectSound() 111 int AudioOutputDXPrivate::InitDirectSound(void) 341 112 { 342 // HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); 113 343 114 LPFNDSC OurDirectSoundCreate; 344 115 345 VERBOSE(VB_ IMPORTANT,"initialising DirectSound");116 VERBOSE(VB_AUDIO, LOC + "initialising DirectSound"); 346 117 347 118 dsound_dll = LoadLibrary("DSOUND.DLL"); 348 119 if (dsound_dll == NULL ) 349 120 { 350 VERBOSE(VB_IMPORTANT, "cannot open DSOUND.DLL" );121 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot open DSOUND.DLL" ); 351 122 goto error; 352 123 } 353 124 354 OurDirectSoundCreate = (LPFNDSC)355 125 OurDirectSoundCreate = 126 (LPFNDSC)GetProcAddress(dsound_dll, "DirectSoundCreate"); 356 127 if (OurDirectSoundCreate == NULL) 357 128 { 358 VERBOSE(VB_IMPORTANT, "GetProcAddress FAILED" );129 VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProcAddress FAILED" ); 359 130 goto error; 360 131 } 361 132 362 VERBOSE(VB_IMPORTANT, "create DS object");133 // VERBOSE(VB_IMPORTANT, "create DS object"); 363 134 364 135 /* Create the direct sound object */ 365 136 if FAILED(OurDirectSoundCreate(NULL, &dsobject, NULL)) 366 137 { 367 VERBOSE(VB_IMPORTANT, "cannot create a direct sound device" );138 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot create a direct sound device" ); 368 139 goto error; 369 140 } 370 141 371 VERBOSE(VB_IMPORTANT, "setting cooperative level");142 // VERBOSE(VB_IMPORTANT, "setting cooperative level"); 372 143 373 144 /* Set DirectSound Cooperative level, ie what control we want over Windows 374 145 * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the … … 380 151 * sound without any video, and so what window handle should we use ??? 381 152 * The hack for now is to use the Desktop window handle - it seems to be 382 153 * working */ 383 if (IDirectSound_SetCooperativeLevel(dsobject,154 if FAILED(IDirectSound_SetCooperativeLevel(dsobject, 384 155 GetDesktopWindow(), 385 156 DSSCL_EXCLUSIVE)) 386 157 { 387 VERBOSE(VB_IMPORTANT, "cannot set direct soundcooperative level" );158 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot set DS cooperative level" ); 388 159 } 389 160 390 VERBOSE(VB_ IMPORTANT, "creating notificatoin events");161 VERBOSE(VB_AUDIO, LOC + "initialised DirectSound"); 391 162 392 /* Then create the notification events */393 for (int i = 0; i < 4; i++)394 notif[i].hEventNotify = CreateEvent(NULL, FALSE, FALSE, NULL);395 396 VERBOSE(VB_IMPORTANT, "initialised DirectSound");397 398 163 return 0; 399 164 400 165 error: … … 405 170 dsound_dll = NULL; 406 171 } 407 172 return -1; 173 } 408 174 175 void AudioOutputDXPrivate::DestroyDSBuffer(void) 176 { 177 if (dsbuffer) 178 { 179 VERBOSE(VB_AUDIO, LOC + "destroying DirectSound buffer"); 180 IDirectSoundBuffer_Stop(dsbuffer); 181 IDirectSoundBuffer_Release(dsbuffer); 182 dsbuffer = NULL; 183 } 409 184 } 410 185 411 412 /***************************************************************************** 413 * CreateDSBuffer: Creates a direct sound buffer of the required format. 414 ***************************************************************************** 415 * This function creates the buffer we'll use to play audio. 416 * In DirectSound there are two kinds of buffers: 417 * - the primary buffer: which is the actual buffer that the soundcard plays 418 * - the secondary buffer(s): these buffers are the one actually used by 419 * applications and DirectSound takes care of mixing them into the primary. 420 * 421 * Once you create a secondary buffer, you cannot change its format anymore so 422 * you have to release the current one and create another. 423 *****************************************************************************/ 424 int AudioOutputDX::CreateDSBuffer(int audio_bits, int audio_channels, int audio_samplerate, bool b_probe) 186 bool AudioOutputDXPrivate::StartPlayback(void) 425 187 { 426 WAVEFORMATEXTENSIBLE waveformat; 427 DSBUFFERDESC dsbdesc; 428 unsigned int i; 188 HRESULT dsresult; 429 189 430 /* First set the sound buffer format */ 431 /* waveformat.dwChannelMask = 0; 432 for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ ) 190 dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING); 191 if (dsresult == DSERR_BUFFERLOST) 433 192 { 434 if ( i_channels & pi_channels_in[i] ) 435 waveformat.dwChannelMask |= pi_channels_out[i]; 436 }*/ 437 438 /* switch( i_format ) 193 IDirectSoundBuffer_Restore(dsbuffer); 194 dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING ); 195 } 196 if (dsresult != DS_OK) 439 197 { 440 case VLC_FOURCC('s','p','d','i'): 441 i_nb_channels = 2; 442 / * To prevent channel re-ordering * / 443 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; 444 waveformat.Format.wBitsPerSample = 16; 445 waveformat.Samples.wValidBitsPerSample = 446 waveformat.Format.wBitsPerSample; 447 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; 448 waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF; 449 break; 198 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot start playing buffer" ); 199 return false; 200 } 201 else 202 return true; 203 } 450 204 451 case VLC_FOURCC('f','l','3','2'): 452 waveformat.Format.wBitsPerSample = sizeof(float) * 8; 453 waveformat.Samples.wValidBitsPerSample = 454 waveformat.Format.wBitsPerSample; 455 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; 456 waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; 457 break; 205 bool AudioOutputDX::OpenDevice(void) 206 { 207 WAVEFORMATEXTENSIBLE wf; 208 DSBUFFERDESC dsbdesc; 458 209 459 case VLC_FOURCC('s','1','6','l'):*/ 460 waveformat.Format.wBitsPerSample = audio_bits; 461 waveformat.Samples.wValidBitsPerSample = 462 waveformat.Format.wBitsPerSample; 463 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM; 464 waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM; 465 /* break; 466 }*/ 210 if (!m_priv->dsobject || !m_priv->dsound_dll) 211 { 212 Error("DirectSound initialization failed"); 213 return false; 214 } 467 215 468 waveformat.Format.nChannels = audio_channels; 469 waveformat.Format.nSamplesPerSec = audio_samplerate; 470 waveformat.Format.nBlockAlign = 471 waveformat.Format.wBitsPerSample / 8 * audio_channels; 472 waveformat.Format.nAvgBytesPerSec = 473 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign; 216 CloseDevice(); 474 217 475 audio_bytes_per_sample = waveformat.Format.wBitsPerSample / 8 * audio_channels; 218 SetBlocking(true); 219 fragment_size = (source == AUDIOOUTPUT_TELEPHONY) ? 320 : 6144; 220 if (audio_channels > 2) 221 fragment_size *= 2; 222 soundcard_buffer_size = kFramesNum * fragment_size; 223 audio_bytes_per_sample = audio_bits / 8 * audio_channels; 224 if (m_UseSPDIF && (audio_channels != 2)) 225 { 226 Error("SPDIF passthru requires 2 channel data"); 227 return false; 228 } 476 229 477 VERBOSE(VB_IMPORTANT, "New format: " << audio_bits << "bits, " << audio_channels << "ch, " << audio_samplerate << "Hz"); 230 /* First set the sound buffer format */ 231 wf.Format.wFormatTag = 232 (m_UseSPDIF) ? WAVE_FORMAT_DOLBY_AC3_SPDIF : WAVE_FORMAT_PCM; 233 wf.Format.nChannels = audio_channels; 234 wf.Format.nSamplesPerSec = audio_samplerate; 235 wf.Format.nBlockAlign = audio_bytes_per_sample; 236 wf.Format.nAvgBytesPerSec = 237 wf.Format.nSamplesPerSec * wf.Format.nBlockAlign; 238 wf.Format.wBitsPerSample = audio_bits; 239 wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; 240 wf.SubFormat = 241 (m_UseSPDIF) ? _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF : _KSDATAFORMAT_SUBTYPE_PCM; 478 242 243 VERBOSE(VB_AUDIO, LOC + "New format: " << audio_bits << "bits, " 244 << audio_channels << "ch, " << audio_samplerate << "Hz"); 245 479 246 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ 480 247 if (audio_channels <= 2) 481 248 { 482 w aveformat.Format.cbSize = 0;249 wf.Format.cbSize = 0; 483 250 } 484 251 else 485 252 { 486 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 487 waveformat.Format.cbSize = 253 wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 254 wf.dwChannelMask = 0x003F; // 0x003F = 5.1 channels 255 wf.Format.cbSize = 488 256 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); 489 257 } 490 258 491 492 259 /* Then fill in the direct sound descriptor */ 493 260 memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); 494 261 dsbdesc.dwSize = sizeof(DSBUFFERDESC); 495 262 dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ 496 | DSBCAPS_CTRLPOSITIONNOTIFY /* We need notification */497 263 | DSBCAPS_GLOBALFOCUS /* Allows background playing */ 498 264 | DSBCAPS_LOCHARDWARE; /* Needed for 5.1 on emu101k */ 499 dsbdesc.dwBufferBytes = FRAMES_NUM * audio_bits/8 * audio_channels; /* buffer size */ 500 dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat; 265 if (!m_UseSPDIF) 266 dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; /* Allow volume control */ 267 dsbdesc.dwBufferBytes = soundcard_buffer_size; /* buffer size */ 268 dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf; 501 269 502 if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL)) 270 if FAILED(IDirectSound_CreateSoundBuffer( 271 m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL)) 503 272 { 273 /* Vista does not support hardware mixing */ 504 274 /* Try without DSBCAPS_LOCHARDWARE */ 505 275 dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; 506 if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL)) 276 HRESULT dsresult = IDirectSound_CreateSoundBuffer( 277 m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL); 278 if FAILED(dsresult) 507 279 { 508 return -1; 280 Error(QString("Failed to create DS buffer %1").arg((DWORD)dsresult)); 281 return false; 509 282 } 510 if ( !b_probe ) VERBOSE(VB_IMPORTANT, "couldn't use hardware sound buffer" );283 VERBOSE(VB_AUDIO, LOC + "Using software mixer" ); 511 284 } 285 VERBOSE(VB_AUDIO, LOC + "created DirectSound buffer"); 512 286 513 write_cursor = 0; 514 buffer_size = FRAMES_NUM * audio_bits/8 * audio_channels; 515 516 /* Stop here if we were just probing */ 517 if ( b_probe ) 518 { 519 IDirectSoundBuffer_Release(dsbuffer); 520 dsbuffer = NULL; 521 return 0; 522 } 523 524 /* Now the secondary buffer is created, we need to setup its position 525 * notification */ 526 for (i = 0; i < 4; i++) 527 { 528 notif[i].dwOffset = buffer_size / 4 * i; 529 } 530 531 /* Get the IDirectSoundNotify interface */ 532 if FAILED(IDirectSoundBuffer_QueryInterface(dsbuffer, IID_IDirectSoundNotify, (LPVOID*) &dsnotify)) 533 { 534 VERBOSE(VB_IMPORTANT, "cannot get IDirectSoundNotify interface" ); 535 goto error; 536 } 537 538 if FAILED(IDirectSoundNotify_SetNotificationPositions(dsnotify, 4, notif)) 539 { 540 VERBOSE(VB_IMPORTANT, "cannot set position notification" ); 541 goto error; 542 } 543 544 // p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask; 545 // CheckReordering( p_aout, i_nb_channels ); 546 547 VERBOSE(VB_IMPORTANT, "created DirectSound buffer"); 548 549 return 0; 550 551 error: 552 DestroyDSBuffer(); 553 return -1; 287 return true; 554 288 } 555 289 556 557 /***************************************************************************** 558 * DestroyDSBuffer 559 ***************************************************************************** 560 * This function destroys the secondary buffer. 561 *****************************************************************************/ 562 void AudioOutputDX::DestroyDSBuffer() 290 void AudioOutputDX::CloseDevice(void) 563 291 { 564 if (dsnotify) 565 { 566 IDirectSoundNotify_Release(dsnotify); 567 dsnotify = NULL; 568 } 569 570 VERBOSE(VB_IMPORTANT, "destroying DirectSound buffer"); 571 572 if (dsbuffer) 573 { 574 IDirectSoundBuffer_Stop(dsbuffer); 575 IDirectSoundBuffer_Release(dsbuffer); 576 dsbuffer = NULL; 577 } 292 if (m_priv->dsbuffer) 293 m_priv->DestroyDSBuffer(); 294 m_WriteCursor = 0; 295 m_PlayStarted = false; 578 296 } 579 297 580 /***************************************************************************** 581 * FillBuffer: Fill in one of the direct sound frame buffers. 582 ***************************************************************************** 583 * Returns VLC_SUCCESS on success. 584 *****************************************************************************/ 585 int AudioOutputDX::FillBuffer(int frames, char *buffer) 298 void AudioOutputDX::WriteAudio(unsigned char * buffer, int size) 586 299 { 587 DWORD play_pos, write_pos, end_write; 588 void *p_write_position, *p_wrap_around; 589 DWORD l_bytes1, l_bytes2; 590 HRESULT dsresult; 300 if (size == 0) 301 return; 591 302 592 if ( !awaiting_data && !paused)303 if (audio_channels == 6) 593 304 { 594 595 // VERBOSE(VB_IMPORTANT, "checking buffer positions");596 597 dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos);598 599 if (dsresult != DS_OK)305 // Linux and Windows have different 5.1 channel order conventions 306 const uint kReorder[6] = {0,1,4,5,2,3}; 307 int abytes = audio_bits / 8; 308 unsigned char p_tmp[24]; 309 unsigned char *obuf = buffer; 310 for(int i = 0; i < size / audio_channels / abytes; i++) 600 311 { 601 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions"); 602 return -1; 603 } 604 605 end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample; 606 607 while (!(((play_pos < write_pos) && (write_cursor >= write_pos || write_cursor < play_pos) && 608 (end_write >= write_pos || end_write < play_pos)) || 609 ((play_pos < write_pos) && (write_cursor >= write_pos && write_cursor < play_pos) && 610 (end_write >= write_pos && end_write < play_pos)))) 611 { 612 // VERBOSE(VB_IMPORTANT, "cannot write audio data: " << write_cursor << " " << write_pos << " " << play_pos << " sleeping"); 613 614 HANDLE notification_events[4]; 615 616 for(int i = 0; i < 4; i++) 617 notification_events[i] = notif[i].hEventNotify; 618 619 WaitForMultipleObjects(4, notification_events, 0, INFINITE ); 620 621 // VERBOSE(VB_IMPORTANT, "woken"); 622 623 dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos); 624 625 if (dsresult != DS_OK) 312 for(int j = 0; j < audio_channels; j++) 626 313 { 627 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions"); 628 return -1; 314 for(int k = 0; k < abytes; k++) 315 { 316 p_tmp[abytes * kReorder[j] + k] = buffer[abytes * j + k]; 317 } 629 318 } 630 631 end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample;319 memcpy(buffer, p_tmp, abytes * audio_channels); 320 buffer += abytes * audio_channels; 632 321 } 322 buffer = obuf; 633 323 } 634 635 324 636 // VERBOSE(VB_IMPORTANT, "Locking buffer"); 325 void *p_write_position, *p_wrap_around; 326 DWORD l_bytes1, l_bytes2; 327 HRESULT dsresult; 637 328 638 329 /* Before copying anything, we have to lock the buffer */ 639 330 dsresult = IDirectSoundBuffer_Lock( 640 dsbuffer,/* DS buffer */641 write_cursor,/* Start offset */642 frames * audio_bytes_per_sample,/* Number of bytes */331 m_priv->dsbuffer, /* DS buffer */ 332 m_WriteCursor, /* Start offset */ 333 size, /* Number of bytes */ 643 334 &p_write_position, /* Address of lock start */ 644 335 &l_bytes1, /* Count of bytes locked before wrap around */ 645 336 &p_wrap_around, /* Buffer adress (if wrap around) */ 646 337 &l_bytes2, /* Count of bytes after wrap around */ 647 0); 338 0); /* Flags */ 648 339 if (dsresult == DSERR_BUFFERLOST) 649 340 { 650 IDirectSoundBuffer_Restore( dsbuffer);341 IDirectSoundBuffer_Restore(m_priv->dsbuffer); 651 342 dsresult = IDirectSoundBuffer_Lock( 652 dsbuffer,653 write_cursor,654 frames * audio_bytes_per_sample,343 m_priv->dsbuffer, 344 m_WriteCursor, 345 size, 655 346 &p_write_position, 656 347 &l_bytes1, 657 348 &p_wrap_around, … … 660 351 } 661 352 if (dsresult != DS_OK) 662 353 { 663 VERBOSE(VB_IMPORTANT, "cannot lock buffer");664 return -1;354 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot lock buffer, audio dropped"); 355 return; 665 356 } 666 357 667 358 if (buffer == NULL) 668 359 { 669 VERBOSE(VB_ IMPORTANT,"Writing null bytes");360 VERBOSE(VB_AUDIO, LOC + "Writing null bytes"); 670 361 671 362 memset(p_write_position, 0, l_bytes1); 672 363 if (p_wrap_around) 673 364 memset(p_wrap_around, 0, l_bytes2); 674 365 675 write_cursor += l_bytes1 + l_bytes2;366 m_WriteCursor += l_bytes1 + l_bytes2; 676 367 677 while (write_cursor >=buffer_size)678 write_cursor -=buffer_size;368 while (m_WriteCursor >= (DWORD)soundcard_buffer_size) 369 m_WriteCursor -= soundcard_buffer_size; 679 370 } 680 /* else if ( p_aout->output.p_sys->b_chan_reorder )681 {682 /* Do the channel reordering here * /683 684 if ( p_aout->output.output.i_format == VLC_FOURCC('s','1','6','l') )685 InterleaveS16( (int16_t *)p_buffer->p_buffer,686 (int16_t *)p_write_position,687 p_aout->output.p_sys->pi_chan_table,688 aout_FormatNbChannels( &p_aout->output.output ) );689 else690 InterleaveFloat32( (float *)p_buffer->p_buffer,691 (float *)p_write_position,692 p_aout->output.p_sys->pi_chan_table,693 aout_FormatNbChannels( &p_aout->output.output ) );694 695 aout_BufferFree( p_buffer );696 }*/697 371 else 698 372 { 699 // VERBOSE(VB_IMPORTANT, "filling buffer");700 701 373 memcpy(p_write_position, buffer, l_bytes1); 702 // VERBOSE(VB_IMPORTANT, "buf_fill: " << l_bytes1 << " bytes, " << p_write_position << "-" << ((int)p_write_position + l_bytes1));703 374 if (p_wrap_around) { 704 375 memcpy(p_wrap_around, buffer + l_bytes1, l_bytes2); 705 // VERBOSE(VB_IMPORTANT, "buf_fill2: " << l_bytes2 << " bytes, " << p_wrap_around << "-" << ((int)p_wrap_around + l_bytes2));706 376 } 707 377 708 write_cursor += l_bytes1 + l_bytes2;378 m_WriteCursor += l_bytes1 + l_bytes2; 709 379 710 while (write_cursor >=buffer_size)711 write_cursor -=buffer_size;380 while (m_WriteCursor >= (DWORD)soundcard_buffer_size) 381 m_WriteCursor -= soundcard_buffer_size; 712 382 } 713 383 714 // VERBOSE(VB_IMPORTANT, "unlocking buffer");715 716 384 /* Now the data has been copied, unlock the buffer */ 717 IDirectSoundBuffer_Unlock( dsbuffer, p_write_position, l_bytes1,385 IDirectSoundBuffer_Unlock(m_priv->dsbuffer, p_write_position, l_bytes1, 718 386 p_wrap_around, l_bytes2 ); 719 387 388 m_PlayStarted = m_priv->StartPlayback(); 389 } 720 390 721 // VERBOSE(VB_IMPORTANT, "finished fillbuffer"); 391 void AudioOutputDX::Pause(bool pause) 392 { 393 if (pause) 394 { 395 IDirectSoundBuffer_Stop(m_priv->dsbuffer); 396 VERBOSE(VB_AUDIO, LOC + "buffer paused"); 397 } 398 else 399 { 400 if (! m_priv->StartPlayback()) 401 VERBOSE(VB_IMPORTANT, LOC_ERR + "unpause failed" ); 402 VERBOSE(VB_AUDIO, LOC + "buffer unpaused"); 403 } 722 404 723 return 0;405 AudioOutputBase::Pause(pause); 724 406 } 725 407 726 // Wait for all data to finish playing 727 void AudioOutputDX::Drain() 408 int AudioOutputDX::GetSpaceOnSoundcard(void) const 728 409 { 729 // TODO: Wait until all data has been played... 410 HRESULT dsresult; 411 DWORD play_pos, write_pos; 730 412 413 dsresult = IDirectSoundBuffer_GetCurrentPosition( 414 m_priv->dsbuffer, &play_pos, &write_pos); 415 if (dsresult != DS_OK) 416 { 417 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position"); 418 return 0; 419 } 420 421 if (!m_PlayStarted) 422 return soundcard_buffer_size; 423 else 424 { 425 int buffer_free = (int)play_pos - (int)m_WriteCursor; 426 if ( buffer_free < 0 ) 427 buffer_free += soundcard_buffer_size; 428 429 if (((write_pos > play_pos) && (m_WriteCursor <= write_pos) 430 && (m_WriteCursor > play_pos)) 431 || ((write_pos < play_pos) && ((m_WriteCursor <= write_pos) 432 || (play_pos < m_WriteCursor)))) 433 { 434 VERBOSE (VB_AUDIO, LOC + "buffer underrun " 435 << play_pos << " " << write_pos << " " << m_WriteCursor); 436 // WriteCursor is in unsafe zone - stop playback for now 437 // Next call to WriteAudio will restart the buffer 438 IDirectSoundBuffer_Stop(m_priv->dsbuffer); 439 } 440 return buffer_free; 441 } 731 442 } 732 443 444 int AudioOutputDX::GetBufferedOnSoundcard(void) const 445 { 446 HRESULT dsresult; 447 DWORD play_pos; 448 449 dsresult = IDirectSoundBuffer_GetCurrentPosition(m_priv->dsbuffer, &play_pos, NULL); 450 if (dsresult != DS_OK) 451 { 452 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position"); 453 return 0; 454 } 455 456 int buffered = (int)m_WriteCursor - (int)play_pos; 457 if ( buffered < 0 ) 458 buffered += soundcard_buffer_size; 459 return buffered; 460 } 461 733 462 int AudioOutputDX::GetVolumeChannel(int channel) const 734 463 { 735 // Do nothing 736 return 100; 464 HRESULT dsresult; 465 long dxVolume = 0; 466 int volume; 467 468 if (m_UseSPDIF) 469 return 100; 470 471 dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume); 472 if (dsresult != DS_OK) 473 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get volume " << dxVolume ); 474 475 volume = (int)(pow(10,(float)dxVolume/20)*100); 476 VERBOSE(VB_AUDIO, LOC + "got volume " << volume ); 477 478 return volume; 737 479 } 480 738 481 void AudioOutputDX::SetVolumeChannel(int channel, int volume) 739 482 { 740 // Do nothing 483 HRESULT dsresult; 484 float dbAtten = 20 * log10((float)volume/100); 485 long dxVolume = (volume == 0) ? DSBVOLUME_MIN : 100 * dbAtten; 486 487 if (m_UseSPDIF) 488 return; 489 490 // dxVolume is attenuation in 100ths of a decibel 491 dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume); 492 493 if (dsresult != DS_OK) 494 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set volume " << dxVolume ); 495 496 VERBOSE(VB_AUDIO, LOC + "set volume " << dxVolume ); 741 497 } 742 498 499 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/NuppelVideoPlayer.cpp
4475 4475 if (audioOutput) 4476 4476 { 4477 4477 audioOutput->SetStretchFactor(play_speed); 4478 #ifdef USING_DIRECTX4479 audioOutput->Reset();4480 #endif4481 4478 } 4482 4479 } 4483 4480