Ticket #6538: 6538-aodx_trunk.patch
File 6538-aodx_trunk.patch, 40.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 *buffer, 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_UseSPDIF; 31 static const uint kFramesNum; 77 32 }; 78 33 79 34 #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 … … 20 24 #include <initguid.h> 21 25 DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); 22 26 23 /*****************************************************************************24 * Useful macros25 *****************************************************************************/26 #ifndef WAVE_FORMAT_IEEE_FLOAT27 # define WAVE_FORMAT_IEEE_FLOAT 0x000328 #endif29 30 27 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF 31 28 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 32 29 #endif … … 35 32 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE 36 33 #endif 37 34 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 35 #ifndef _WAVEFORMATEXTENSIBLE_ 80 36 typedef struct { 81 37 WAVEFORMATEX Format; … … 90 46 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; 91 47 #endif 92 48 93 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );94 49 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); 95 50 DEFINE_GUID( _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); 96 51 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) 52 class AudioOutputDXPrivate 114 53 { 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++) 54 public: 55 AudioOutputDXPrivate(AudioOutputDX *in_parent) : 56 parent(in_parent), 57 dsound_dll(NULL), 58 dsobject(NULL), 59 dsbuffer(NULL), 60 playStarted(false), 61 writeCursor(0), 62 lastValidTime(0) 230 63 { 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; 64 InitDirectSound(); 236 65 } 237 }238 66 239 err = arts_write(pcm_handle, audiobuffer, frames*4); 240 free(audiobuffer); 67 ~AudioOutputDXPrivate() 68 { 69 DestroyDSBuffer(); 241 70 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*/ 71 if (dsobject) 72 IDirectSound_Release(dsobject); 250 73 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);74 if (dsound_dll) 75 FreeLibrary(dsound_dll); 76 } 254 77 255 return true; 256 } 78 int InitDirectSound(void); 79 void DestroyDSBuffer(void); 80 void FillBuffer(unsigned char *buffer, int size); 81 bool StartPlayback(void); 82 void StopPlayback(bool reset); 257 83 258 void AudioOutputDX::SetTimecode(long long timecode) 259 { 260 audbuf_timecode = timecode; 261 } 84 public: 85 AudioOutputDX *parent; 86 HINSTANCE dsound_dll; 87 LPDIRECTSOUND dsobject; 88 LPDIRECTSOUNDBUFFER dsbuffer; 89 bool playStarted; 90 DWORD writeCursor; 91 DWORD lastValidTime; 92 }; 262 93 263 void AudioOutputDX::SetEffDsp(int dsprate)264 {265 VERBOSE(VB_IMPORTANT, "setting dsprate = " << dsprate);266 267 HRESULT dsresult;268 94 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) 95 AudioOutputDX::AudioOutputDX(const AudioSettings &settings) : 96 AudioOutputBase(settings), 97 m_priv(new AudioOutputDXPrivate(this)), 98 m_UseSPDIF(settings.use_passthru) 280 99 { 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; 100 timeBeginPeriod(1); 101 Reconfigure(settings); 311 102 } 312 103 313 int AudioOutputDX::GetAudiotime(void)104 AudioOutputDX::~AudioOutputDX() 314 105 { 315 DWORD play_pos; 316 HRESULT dsresult; 106 KillAudio(); 317 107 318 dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, NULL); 319 320 if (dsresult != DS_OK) 108 if (m_priv) 321 109 { 322 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");323 return -1;110 delete m_priv; 111 m_priv = NULL; 324 112 } 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); 113 timeEndPeriod(1); 332 114 } 333 115 334 335 116 typedef HRESULT (WINAPI *LPFNDSC) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN); 336 117 337 /***************************************************************************** 338 * InitDirectSound: handle all the gory details of DirectSound initialisation 339 *****************************************************************************/ 340 int AudioOutputDX::InitDirectSound() 118 int AudioOutputDXPrivate::InitDirectSound(void) 341 119 { 342 // HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); 120 343 121 LPFNDSC OurDirectSoundCreate; 344 122 345 VERBOSE(VB_ IMPORTANT,"initialising DirectSound");123 VERBOSE(VB_AUDIO, LOC + "initialising DirectSound"); 346 124 347 125 dsound_dll = LoadLibrary("DSOUND.DLL"); 348 126 if (dsound_dll == NULL ) 349 127 { 350 VERBOSE(VB_IMPORTANT, "cannot open DSOUND.DLL" );128 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot open DSOUND.DLL" ); 351 129 goto error; 352 130 } 353 131 354 OurDirectSoundCreate = (LPFNDSC)355 132 OurDirectSoundCreate = 133 (LPFNDSC)GetProcAddress(dsound_dll, "DirectSoundCreate"); 356 134 if (OurDirectSoundCreate == NULL) 357 135 { 358 VERBOSE(VB_IMPORTANT, "GetProcAddress FAILED" );136 VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProcAddress FAILED" ); 359 137 goto error; 360 138 } 361 139 362 VERBOSE(VB_IMPORTANT, "create DS object");140 // VERBOSE(VB_IMPORTANT, "create DS object"); 363 141 364 142 /* Create the direct sound object */ 365 143 if FAILED(OurDirectSoundCreate(NULL, &dsobject, NULL)) 366 144 { 367 VERBOSE(VB_IMPORTANT, "cannot create a direct sound device" );145 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot create a direct sound device" ); 368 146 goto error; 369 147 } 370 148 371 VERBOSE(VB_IMPORTANT, "setting cooperative level");149 // VERBOSE(VB_IMPORTANT, "setting cooperative level"); 372 150 373 151 /* Set DirectSound Cooperative level, ie what control we want over Windows 374 152 * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the … … 380 158 * sound without any video, and so what window handle should we use ??? 381 159 * The hack for now is to use the Desktop window handle - it seems to be 382 160 * working */ 383 if (IDirectSound_SetCooperativeLevel(dsobject,161 if FAILED(IDirectSound_SetCooperativeLevel(dsobject, 384 162 GetDesktopWindow(), 385 163 DSSCL_EXCLUSIVE)) 386 164 { 387 VERBOSE(VB_IMPORTANT, "cannot set direct soundcooperative level" );165 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot set DS cooperative level" ); 388 166 } 389 167 390 VERBOSE(VB_ IMPORTANT, "creating notificatoin events");168 VERBOSE(VB_AUDIO, LOC + "initialised DirectSound"); 391 169 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 170 return 0; 399 171 400 172 error: … … 405 177 dsound_dll = NULL; 406 178 } 407 179 return -1; 180 } 408 181 182 void AudioOutputDXPrivate::DestroyDSBuffer(void) 183 { 184 if (dsbuffer) 185 { 186 VERBOSE(VB_AUDIO, LOC + "destroying DirectSound buffer"); 187 IDirectSoundBuffer_Stop(dsbuffer); 188 IDirectSoundBuffer_Release(dsbuffer); 189 dsbuffer = NULL; 190 } 191 writeCursor = 0; 192 playStarted = false; 409 193 } 410 194 195 void AudioOutputDXPrivate::FillBuffer(unsigned char *buffer, int size) 196 { 197 void *p_write_position, *p_wrap_around; 198 DWORD l_bytes1, l_bytes2; 199 HRESULT dsresult; 411 200 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) 201 /* Before copying anything, we have to lock the buffer */ 202 dsresult = IDirectSoundBuffer_Lock( 203 dsbuffer, /* DS buffer */ 204 writeCursor, /* Start offset */ 205 size, /* Number of bytes */ 206 &p_write_position, /* Address of lock start */ 207 &l_bytes1, /* Bytes locked before wrap */ 208 &p_wrap_around, /* Buffer address (if wrap around) */ 209 &l_bytes2, /* Count of bytes after wrap around */ 210 0); /* Flags */ 211 if (dsresult == DSERR_BUFFERLOST) 212 { 213 IDirectSoundBuffer_Restore(dsbuffer); 214 dsresult = IDirectSoundBuffer_Lock( 215 dsbuffer, 216 writeCursor, 217 size, 218 &p_write_position, 219 &l_bytes1, 220 &p_wrap_around, 221 &l_bytes2, 222 0); 223 } 224 if (dsresult != DS_OK) 225 { 226 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot lock buffer, audio dropped"); 227 return; 228 } 229 230 if (buffer == NULL) 231 { 232 VERBOSE(VB_AUDIO, LOC + "Writing null bytes"); 233 234 memset(p_write_position, 0, l_bytes1); 235 if (p_wrap_around) 236 memset(p_wrap_around, 0, l_bytes2); 237 238 writeCursor += l_bytes1 + l_bytes2; 239 240 while (writeCursor >= (DWORD)parent->soundcard_buffer_size) 241 writeCursor -= parent->soundcard_buffer_size; 242 } 243 else 244 { 245 memcpy(p_write_position, buffer, l_bytes1); 246 if (p_wrap_around) { 247 memcpy(p_wrap_around, buffer + l_bytes1, l_bytes2); 248 } 249 250 writeCursor += l_bytes1 + l_bytes2; 251 252 while (writeCursor >= (DWORD)parent->soundcard_buffer_size) 253 writeCursor -= parent->soundcard_buffer_size; 254 } 255 256 /* Now the data has been copied, unlock the buffer */ 257 IDirectSoundBuffer_Unlock(dsbuffer, p_write_position, l_bytes1, 258 p_wrap_around, l_bytes2 ); 259 } 260 261 bool AudioOutputDXPrivate::StartPlayback(void) 425 262 { 426 WAVEFORMATEXTENSIBLE waveformat; 427 DSBUFFERDESC dsbdesc; 428 unsigned int i; 263 HRESULT dsresult; 264 lastValidTime = 0; 429 265 430 /* First set the sound buffer format */ 431 /* waveformat.dwChannelMask = 0; 432 for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ ) 266 dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING); 267 if (dsresult == DSERR_BUFFERLOST) 433 268 { 434 if ( i_channels & pi_channels_in[i] ) 435 waveformat.dwChannelMask |= pi_channels_out[i]; 436 }*/ 269 IDirectSoundBuffer_Restore(dsbuffer); 270 dsresult = IDirectSoundBuffer_Play(dsbuffer, 0, 0, DSBPLAY_LOOPING ); 271 } 272 if (dsresult != DS_OK) 273 { 274 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot start playing buffer" ); 275 playStarted=false; 276 return false; 277 } 278 playStarted=true; 279 280 // set buffer expiration time (adding 1ms due to integer math) 281 lastValidTime = 1 + timeGetTime() + (parent->GetBufferedOnSoundcard() * 282 1000 / (parent->audio_bytes_per_sample * parent->audio_samplerate)); 437 283 438 /* switch( i_format ) 284 return true; 285 } 286 287 void AudioOutputDXPrivate::StopPlayback(bool reset) 288 { 289 IDirectSoundBuffer_Stop(dsbuffer); 290 lastValidTime=0; 291 if (reset) 439 292 { 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; 293 writeCursor = 0; 294 IDirectSoundBuffer_SetCurrentPosition(dsbuffer, writeCursor); 295 FillBuffer(NULL, parent->soundcard_buffer_size); 296 playStarted=false; 297 } 298 } 450 299 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; 300 bool AudioOutputDX::OpenDevice(void) 301 { 302 WAVEFORMATEXTENSIBLE wf; 303 DSBUFFERDESC dsbdesc; 458 304 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 }*/ 305 if (!m_priv->dsobject || !m_priv->dsound_dll) 306 { 307 Error("DirectSound initialization failed"); 308 return false; 309 } 467 310 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; 311 CloseDevice(); 474 312 475 audio_bytes_per_sample = waveformat.Format.wBitsPerSample / 8 * audio_channels; 313 SetBlocking(true); 314 fragment_size = (source == AUDIOOUTPUT_TELEPHONY) ? 320 : 6144; 315 if (audio_channels > 2) 316 fragment_size *= 2; 317 soundcard_buffer_size = kFramesNum * fragment_size; 318 audio_bytes_per_sample = audio_bits / 8 * audio_channels; 319 if (m_UseSPDIF && (audio_channels != 2)) 320 { 321 Error("SPDIF passthru requires 2 channel data"); 322 return false; 323 } 476 324 477 VERBOSE(VB_IMPORTANT, "New format: " << audio_bits << "bits, " << audio_channels << "ch, " << audio_samplerate << "Hz"); 325 /* First set the sound buffer format */ 326 wf.Format.wFormatTag = 327 (m_UseSPDIF) ? WAVE_FORMAT_DOLBY_AC3_SPDIF : WAVE_FORMAT_PCM; 328 wf.Format.nChannels = audio_channels; 329 wf.Format.nSamplesPerSec = audio_samplerate; 330 wf.Format.nBlockAlign = audio_bytes_per_sample; 331 wf.Format.nAvgBytesPerSec = 332 wf.Format.nSamplesPerSec * wf.Format.nBlockAlign; 333 wf.Format.wBitsPerSample = audio_bits; 334 wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; 335 wf.SubFormat = (m_UseSPDIF) ? _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF 336 : _KSDATAFORMAT_SUBTYPE_PCM; 337 338 VERBOSE(VB_AUDIO, LOC + "New format: " << audio_bits << "bits, " 339 << audio_channels << "ch, " << audio_samplerate << "Hz"); 478 340 479 341 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ 480 342 if (audio_channels <= 2) 481 343 { 482 w aveformat.Format.cbSize = 0;344 wf.Format.cbSize = 0; 483 345 } 484 346 else 485 347 { 486 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 487 waveformat.Format.cbSize = 348 wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 349 wf.dwChannelMask = 0x003F; // 0x003F = 5.1 channels 350 wf.Format.cbSize = 488 351 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); 489 352 } 490 353 491 492 354 /* Then fill in the direct sound descriptor */ 493 355 memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); 494 356 dsbdesc.dwSize = sizeof(DSBUFFERDESC); 495 357 dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ 496 | DSBCAPS_CTRLPOSITIONNOTIFY /* We need notification */497 358 | DSBCAPS_GLOBALFOCUS /* Allows background playing */ 498 359 | 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; 360 if (!m_UseSPDIF) 361 dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; /* Allow volume control */ 362 dsbdesc.dwBufferBytes = soundcard_buffer_size; /* buffer size */ 363 dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf; 501 364 502 if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL)) 365 if FAILED(IDirectSound_CreateSoundBuffer( 366 m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL)) 503 367 { 368 /* Vista does not support hardware mixing */ 504 369 /* Try without DSBCAPS_LOCHARDWARE */ 505 370 dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; 506 if FAILED(IDirectSound_CreateSoundBuffer(dsobject, &dsbdesc, &dsbuffer, NULL)) 371 HRESULT dsresult = IDirectSound_CreateSoundBuffer( 372 m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL); 373 if FAILED(dsresult) 507 374 { 508 return -1; 375 Error(QString("Failed to create DS buffer %1").arg((DWORD)dsresult)); 376 return false; 509 377 } 510 if ( !b_probe ) VERBOSE(VB_IMPORTANT, "couldn't use hardware sound buffer" );378 VERBOSE(VB_AUDIO, LOC + "Using software mixer" ); 511 379 } 380 VERBOSE(VB_AUDIO, LOC + "created DirectSound buffer"); 512 381 513 write_cursor = 0;514 buffer_size = FRAMES_NUM * audio_bits/8 * audio_channels; 382 return true; 383 } 515 384 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; 385 void AudioOutputDX::CloseDevice(void) 386 { 387 if (m_priv->dsbuffer) 388 m_priv->DestroyDSBuffer(); 554 389 } 555 390 556 557 /***************************************************************************** 558 * DestroyDSBuffer 559 ***************************************************************************** 560 * This function destroys the secondary buffer. 561 *****************************************************************************/ 562 void AudioOutputDX::DestroyDSBuffer() 391 void AudioOutputDX::WriteAudio(unsigned char * buffer, int size) 563 392 { 564 if (dsnotify) 565 { 566 IDirectSoundNotify_Release(dsnotify); 567 dsnotify = NULL; 568 } 393 if (size == 0) 394 return; 569 395 570 VERBOSE(VB_IMPORTANT, "destroying DirectSound buffer"); 571 572 if (dsbuffer) 396 if (audio_channels == 6) 573 397 { 574 IDirectSoundBuffer_Stop(dsbuffer); 575 IDirectSoundBuffer_Release(dsbuffer); 576 dsbuffer = NULL; 398 // Linux and Windows have different 5.1 channel order conventions 399 const uint kReorder[6] = {0,1,4,5,2,3}; 400 int abytes = audio_bits / 8; 401 unsigned char p_tmp[24]; 402 unsigned char *obuf = buffer; 403 for(int i = 0; i < size / audio_channels / abytes; i++) 404 { 405 for(int j = 0; j < audio_channels; j++) 406 { 407 for(int k = 0; k < abytes; k++) 408 { 409 p_tmp[abytes * kReorder[j] + k] = buffer[abytes * j + k]; 410 } 411 } 412 memcpy(buffer, p_tmp, abytes * audio_channels); 413 buffer += abytes * audio_channels; 414 } 415 buffer = obuf; 577 416 } 417 418 m_priv->FillBuffer(buffer, size); 419 m_priv->StartPlayback(); 578 420 } 579 421 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) 422 void AudioOutputDX::Pause(bool pause) 586 423 { 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; 591 592 if (!awaiting_data && !paused) 424 if (m_priv->dsbuffer) 593 425 { 594 595 // VERBOSE(VB_IMPORTANT, "checking buffer positions"); 596 597 dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos); 598 599 if (dsresult != DS_OK) 426 if (pause) 600 427 { 601 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions");602 return -1;428 m_priv->StopPlayback(false); 429 VERBOSE(VB_AUDIO, LOC + "buffer paused"); 603 430 } 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)))) 431 else 611 432 { 612 // VERBOSE(VB_IMPORTANT, "cannot write audio data: " << write_cursor << " " << write_pos << " " << play_pos << " sleeping"); 433 if (! m_priv->StartPlayback()) 434 VERBOSE(VB_IMPORTANT, LOC_ERR + "unpause failed" ); 435 VERBOSE(VB_AUDIO, LOC + "buffer unpaused"); 436 } 437 } 613 438 614 HANDLE notification_events[4]; 439 AudioOutputBase::Pause(pause); 440 } 615 441 616 for(int i = 0; i < 4; i++) 617 notification_events[i] = notif[i].hEventNotify; 442 int AudioOutputDX::GetSpaceOnSoundcard(void) const 443 { 444 if (!m_priv->playStarted) 445 return soundcard_buffer_size; 618 446 619 WaitForMultipleObjects(4, notification_events, 0, INFINITE ); 620 621 // VERBOSE(VB_IMPORTANT, "woken"); 622 623 dsresult = IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &play_pos, &write_pos); 447 HRESULT dsresult; 448 DWORD play_pos, write_pos; 449 DWORD currentTime = timeGetTime(); 624 450 625 if (dsresult != DS_OK) 626 { 627 VERBOSE(VB_IMPORTANT, "cannot get current buffer positions"); 628 return -1; 629 } 630 631 end_write = write_cursor + (frames + FRAMES_NUM/4) * audio_bytes_per_sample; 632 } 451 dsresult = IDirectSoundBuffer_GetCurrentPosition( 452 m_priv->dsbuffer, &play_pos, &write_pos); 453 if (dsresult != DS_OK) 454 { 455 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position"); 456 return 0; 633 457 } 634 635 458 636 // VERBOSE(VB_IMPORTANT, "Locking buffer"); 459 int buffer_free = (int)play_pos - (int)m_priv->writeCursor; 460 if ( buffer_free < 0 ) 461 buffer_free += soundcard_buffer_size; 637 462 638 /* Before copying anything, we have to lock the buffer */ 639 dsresult = IDirectSoundBuffer_Lock( 640 dsbuffer, /* DS buffer */ 641 write_cursor, /* Start offset */ 642 frames * audio_bytes_per_sample, /* Number of bytes */ 643 &p_write_position, /* Address of lock start */ 644 &l_bytes1, /* Count of bytes locked before wrap around */ 645 &p_wrap_around, /* Buffer adress (if wrap around) */ 646 &l_bytes2, /* Count of bytes after wrap around */ 647 0); /* Flags */ 648 if (dsresult == DSERR_BUFFERLOST) 463 if (((write_pos > play_pos) && (m_priv->writeCursor <= write_pos) 464 && (m_priv->writeCursor > play_pos)) 465 || ((write_pos < play_pos) && ((m_priv->writeCursor <= write_pos) 466 || (play_pos < m_priv->writeCursor)))) 649 467 { 650 IDirectSoundBuffer_Restore(dsbuffer); 651 dsresult = IDirectSoundBuffer_Lock( 652 dsbuffer, 653 write_cursor, 654 frames * audio_bytes_per_sample, 655 &p_write_position, 656 &l_bytes1, 657 &p_wrap_around, 658 &l_bytes2, 659 0); 468 VERBOSE(VB_AUDIO, LOC + "buffer underrun(1) " 469 << play_pos << " " << write_pos << " " << m_priv->writeCursor); 470 // WriteCursor is in unsafe zone - stop playback for now 471 // Next call to WriteAudio will restart the buffer 472 m_priv->StopPlayback(false); 660 473 } 661 if (dsresult != DS_OK)474 else if (m_priv->lastValidTime && (currentTime > m_priv->lastValidTime)) 662 475 { 663 VERBOSE(VB_IMPORTANT, "cannot lock buffer"); 664 return -1; 476 VERBOSE(VB_AUDIO, LOC + "buffer underrun(2) " 477 << play_pos << " " << write_pos << " " << m_priv->writeCursor 478 << " " << currentTime - m_priv->lastValidTime); 479 m_priv->StopPlayback(true); 665 480 } 666 481 667 if (buffer == NULL) 668 { 669 VERBOSE(VB_IMPORTANT, "Writing null bytes"); 670 671 memset(p_write_position, 0, l_bytes1); 672 if (p_wrap_around) 673 memset(p_wrap_around, 0, l_bytes2); 674 675 write_cursor += l_bytes1 + l_bytes2; 676 677 while (write_cursor >= buffer_size) 678 write_cursor -= buffer_size; 679 } 680 /* else if ( p_aout->output.p_sys->b_chan_reorder ) 681 { 682 /* Do the channel reordering here * / 482 return buffer_free; 483 } 683 484 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 else 690 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 ) ); 485 int AudioOutputDX::GetBufferedOnSoundcard(void) const 486 { 487 if (!m_priv->playStarted) 488 return 0; 694 489 695 aout_BufferFree( p_buffer ); 696 }*/ 697 else 490 HRESULT dsresult; 491 DWORD play_pos; 492 493 dsresult = IDirectSoundBuffer_GetCurrentPosition(m_priv->dsbuffer, 494 &play_pos, NULL); 495 if (dsresult != DS_OK) 698 496 { 699 // VERBOSE(VB_IMPORTANT, "filling buffer"); 700 701 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 if (p_wrap_around) { 704 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 } 707 708 write_cursor += l_bytes1 + l_bytes2; 709 710 while (write_cursor >= buffer_size) 711 write_cursor -= buffer_size; 497 VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot get current buffer position"); 498 return 0; 712 499 } 713 500 714 // VERBOSE(VB_IMPORTANT, "unlocking buffer"); 501 int buffered = (int)m_priv->writeCursor - (int)play_pos; 502 if (buffered <= 0) 503 buffered += soundcard_buffer_size; 504 return buffered; 505 } 715 506 716 /* Now the data has been copied, unlock the buffer */ 717 IDirectSoundBuffer_Unlock(dsbuffer, p_write_position, l_bytes1, 718 p_wrap_around, l_bytes2 ); 507 int AudioOutputDX::GetVolumeChannel(int channel) const 508 { 509 HRESULT dsresult; 510 long dxVolume = 0; 511 int volume; 719 512 513 if (m_UseSPDIF) 514 return 100; 720 515 721 // VERBOSE(VB_IMPORTANT, "finished fillbuffer"); 516 dsresult = IDirectSoundBuffer_GetVolume(m_priv->dsbuffer, &dxVolume); 517 if (dsresult != DS_OK) 518 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get volume " << dxVolume ); 722 519 723 return 0; 520 volume = (int)(pow(10,(float)dxVolume/20)*100); 521 VERBOSE(VB_AUDIO, LOC + "got volume " << volume ); 522 523 return volume; 724 524 } 725 525 726 // Wait for all data to finish playing 727 void AudioOutputDX::Drain() 526 void AudioOutputDX::SetVolumeChannel(int channel, int volume) 728 527 { 729 // TODO: Wait until all data has been played... 528 HRESULT dsresult; 529 float dbAtten = 20 * log10((float)volume/100); 530 long dxVolume = (volume == 0) ? DSBVOLUME_MIN : 100 * dbAtten; 730 531 731 } 532 if (m_UseSPDIF) 533 return; 732 534 733 int AudioOutputDX::GetVolumeChannel(int channel) const 734 { 735 // Do nothing 736 return 100; 535 // dxVolume is attenuation in 100ths of a decibel 536 dsresult = IDirectSoundBuffer_SetVolume(m_priv->dsbuffer, dxVolume); 537 538 if (dsresult != DS_OK) 539 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set volume " << dxVolume ); 540 541 VERBOSE(VB_AUDIO, LOC + "set volume " << dxVolume ); 737 542 } 738 void AudioOutputDX::SetVolumeChannel(int channel, int volume)739 {740 // Do nothing741 }742 543 544 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/NuppelVideoPlayer.cpp
4481 4481 if (audioOutput) 4482 4482 { 4483 4483 audioOutput->SetStretchFactor(play_speed); 4484 #ifdef USING_DIRECTX4485 audioOutput->Reset();4486 #endif4487 4484 } 4488 4485 } 4489 4486