MythTV  master
audiooutputdx.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cmath>
3 
5 #include "audiooutputdx.h"
6 
7 #include <windows.h>
8 #include <mmsystem.h>
9 #include <dsound.h>
10 #include <unistd.h>
11 
12 #define LOC QString("AODX: ")
13 
14 #include <initguid.h>
15 DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0,
16  0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
17 
18 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
19 #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
20 #endif
21 
22 #ifndef WAVE_FORMAT_IEEE_FLOAT
23 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
24 #endif
25 
26 #ifndef WAVE_FORMAT_EXTENSIBLE
27 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
28 #endif
29 
30 #ifndef _WAVEFORMATEXTENSIBLE_
32  WAVEFORMATEX Format;
33  union {
34  WORD wValidBitsPerSample; // bits of precision
35  WORD wSamplesPerBlock; // valid if wBitsPerSample==0
36  WORD wReserved; // If neither applies, set to zero
37  } Samples;
38  DWORD dwChannelMask; // which channels are present in stream
39  GUID SubFormat;
40 };
42 #endif
43 
44 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT,
45  0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
46 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM,
47  0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
48 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF,
49  0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
50 
52 {
53  public:
54  explicit AudioOutputDXPrivate(AudioOutputDX *in_parent) :
55  m_parent(in_parent) {}
56 
58  {
60 
61  if (m_dsobject)
62  IDirectSound_Release(m_dsobject);
63 
64  if (m_dsound_dll)
65  FreeLibrary(m_dsound_dll);
66  }
67 
68  int InitDirectSound(bool passthrough = false);
69  void ResetDirectSound(void);
70  void DestroyDSBuffer(void);
71  void FillBuffer(unsigned char *buffer, int size);
72  bool StartPlayback(void);
73 #ifdef UNICODE
74  static int CALLBACK DSEnumCallback(LPGUID lpGuid,
75  LPCWSTR lpcstrDesc,
76  LPCWSTR lpcstrModule,
77  LPVOID lpContext);
78 #else
79  static int CALLBACK DSEnumCallback(LPGUID lpGuid,
80  LPCSTR lpcstrDesc,
81  LPCSTR lpcstrModule,
82  LPVOID lpContext);
83 #endif
84  public:
85  AudioOutputDX *m_parent {nullptr};
86  HINSTANCE m_dsound_dll {nullptr};
87  LPDIRECTSOUND m_dsobject {nullptr};
88  LPDIRECTSOUNDBUFFER m_dsbuffer {nullptr};
89  bool m_playStarted {false};
90  DWORD m_writeCursor {0};
92  GUID *m_chosenGUID {nullptr};
93  int m_device_count {0};
94  int m_device_num {0};
95  QString m_device_name;
96  QMap<int, QString> m_device_list;
97 };
98 
99 
101  AudioOutputBase(settings),
102  m_priv(new AudioOutputDXPrivate(this)),
103  m_UseSPDIF(settings.m_usePassthru)
104 {
105  timeBeginPeriod(1);
106  InitSettings(settings);
107  if (m_passthruDevice == "auto" || m_passthruDevice.toLower() == "default")
109  else
110  m_discreteDigital = true;
111  if (settings.m_init)
112  Reconfigure(settings);
113 }
114 
116 {
117  KillAudio();
118  if (m_priv)
119  {
120  delete m_priv;
121  m_priv = nullptr;
122  }
123  timeEndPeriod(1);
124 }
125 
126 using LPFNDSC = HRESULT (WINAPI *) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
127 using LPFNDSE = HRESULT (WINAPI *) (LPDSENUMCALLBACK, LPVOID);
128 
129 #ifdef UNICODE
130 int CALLBACK AudioOutputDXPrivate::DSEnumCallback(LPGUID lpGuid,
131  LPCWSTR lpcstrDesc,
132  [[maybe_unused]] LPCWSTR lpcstrModule,
133  LPVOID lpContext)
134 {
135  QString enum_desc = QString::fromWCharArray( lpcstrDesc );
136 #else
137 int CALLBACK AudioOutputDXPrivate::DSEnumCallback(LPGUID lpGuid,
138  LPCSTR lpcstrDesc,
139  [[maybe_unused]] LPCSTR lpcstrModule,
140  LPVOID lpContext)
141 {
142  QString enum_desc = QString::fromLocal8Bit( lpcstrDesc );
143 
144 #endif
145  AudioOutputDXPrivate *context = static_cast<AudioOutputDXPrivate*>(lpContext);
146  const QString cfg_desc = context->m_device_name;
147  const int device_num = context->m_device_num;
148  const int device_count = context->m_device_count;
149 
150  VBAUDIO(QString("Device %1:" + enum_desc).arg(device_count));
151 
152  if ((device_num == device_count ||
153  (device_num == 0 && !cfg_desc.isEmpty() &&
154  enum_desc.startsWith(cfg_desc, Qt::CaseInsensitive))) && lpGuid)
155  {
156  context->m_deviceGUID = *lpGuid;
157  context->m_chosenGUID =
158  &(context->m_deviceGUID);
159  context->m_device_name = enum_desc;
160  context->m_device_num = device_count;
161  }
162 
163  context->m_device_list.insert(device_count, enum_desc);
164  context->m_device_count++;
165  return 1;
166 }
167 
169 {
170  DestroyDSBuffer();
171 
172  if (m_dsobject)
173  {
174  IDirectSound_Release(m_dsobject);
175  m_dsobject = nullptr;
176  }
177 
178  if (m_dsound_dll)
179  {
180  FreeLibrary(m_dsound_dll);
181  m_dsound_dll = nullptr;
182  }
183 
184  m_chosenGUID = nullptr;
185  m_device_count = 0;
186  m_device_num = 0;
187  m_device_list.clear();
188 }
189 
191 {
192  LPFNDSC OurDirectSoundCreate;
193  LPFNDSE OurDirectSoundEnumerate;
194  bool ok;
195 
197 
198  m_dsound_dll = LoadLibrary(TEXT("DSOUND.DLL"));
199  if (m_dsound_dll == nullptr)
200  {
201  VBERROR("Cannot open DSOUND.DLL");
202  goto error;
203  }
204 
205  if (m_parent) // parent can be nullptr only when called from GetDXDevices()
206  m_device_name = passthrough ?
208  m_device_name = m_device_name.section(':', 1);
209  m_device_num = m_device_name.toInt(&ok, 10);
210 
211  VBAUDIO(QString("Looking for device num:%1 or name:%2")
212  .arg(m_device_num).arg(m_device_name));
213 
214  OurDirectSoundEnumerate =
215  (LPFNDSE)GetProcAddress(m_dsound_dll, "DirectSoundEnumerateA");
216 
217  if(OurDirectSoundEnumerate)
218  if(FAILED(OurDirectSoundEnumerate(DSEnumCallback, this) != DS_OK))
219  VBERROR("DirectSoundEnumerate FAILED");
220 
221  if (!m_chosenGUID)
222  {
223  m_device_num = 0;
224  m_device_name = "Primary Sound Driver";
225  }
226 
227  VBAUDIO(QString("Using device %1:%2").arg(m_device_num).arg(m_device_name));
228 
229  OurDirectSoundCreate =
230  (LPFNDSC)GetProcAddress(m_dsound_dll, "DirectSoundCreate");
231 
232  if (OurDirectSoundCreate == nullptr)
233  {
234  VBERROR("GetProcAddress FAILED");
235  goto error;
236  }
237 
238  if (FAILED(OurDirectSoundCreate(m_chosenGUID, &m_dsobject, nullptr)))
239  {
240  VBERROR("Cannot create a direct sound device");
241  goto error;
242  }
243 
244  /* Set DirectSound Cooperative level, ie what control we want over Windows
245  * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
246  * settings of the primary buffer, but also that only the sound of our
247  * application will be hearable when it will have the focus.
248  * !!! (this is not really working as intended yet because to set the
249  * cooperative level you need the window handle of your application, and
250  * I don't know of any easy way to get it. Especially since we might play
251  * sound without any video, and so what window handle should we use ???
252  * The hack for now is to use the Desktop window handle - it seems to be
253  * working */
254  if (FAILED(IDirectSound_SetCooperativeLevel(m_dsobject, GetDesktopWindow(),
255  DSSCL_EXCLUSIVE)))
256  VBERROR("Cannot set DS cooperative level");
257 
258  VBAUDIO("Initialised DirectSound");
259 
260  return 0;
261 
262  error:
263  m_dsobject = nullptr;
264  if (m_dsound_dll)
265  {
266  FreeLibrary(m_dsound_dll);
267  m_dsound_dll = nullptr;
268  }
269  return -1;
270 }
271 
273 {
274  if (!m_dsbuffer)
275  return;
276 
277  VBAUDIO("Destroying DirectSound buffer");
278  IDirectSoundBuffer_Stop(m_dsbuffer);
279  m_writeCursor = 0;
280  IDirectSoundBuffer_SetCurrentPosition(m_dsbuffer, m_writeCursor);
281  m_playStarted = false;
282  IDirectSoundBuffer_Release(m_dsbuffer);
283  m_dsbuffer = nullptr;
284 }
285 
286 void AudioOutputDXPrivate::FillBuffer(unsigned char *buffer, int size)
287 {
288  void *p_write_position, *p_wrap_around;
289  DWORD l_bytes1, l_bytes2, play_pos, write_pos;
290  HRESULT dsresult;
291 
292  if (!m_dsbuffer)
293  return;
294 
295  while (true)
296  {
297 
298  dsresult = IDirectSoundBuffer_GetCurrentPosition(m_dsbuffer,
299  &play_pos, &write_pos);
300  if (dsresult != DS_OK)
301  {
302  VBERROR("Cannot get current buffer position");
303  return;
304  }
305 
306  VBAUDIOTS(QString("play: %1 write: %2 wcursor: %3")
307  .arg(play_pos).arg(write_pos).arg(m_writeCursor));
308 
309  while ((m_writeCursor < write_pos &&
310  ((m_writeCursor >= play_pos && write_pos >= play_pos) ||
311  (m_writeCursor < play_pos && write_pos < play_pos))) ||
312  (m_writeCursor >= play_pos && write_pos < play_pos))
313  {
314  VBERROR("buffer underrun");
315  m_writeCursor += size;
316  while (m_writeCursor >= (DWORD)m_parent->m_soundcardBufferSize)
318  }
319 
320  if ((m_writeCursor < play_pos && m_writeCursor + size >= play_pos) ||
321  (m_writeCursor >= play_pos &&
322  m_writeCursor + size >= play_pos + m_parent->m_soundcardBufferSize))
323  {
324  usleep(50000);
325  continue;
326  }
327 
328  break;
329  }
330 
331  dsresult = IDirectSoundBuffer_Lock(
332  m_dsbuffer, /* DS buffer */
333  m_writeCursor, /* Start offset */
334  size, /* Number of bytes */
335  &p_write_position, /* Address of lock start */
336  &l_bytes1, /* Bytes locked before wrap */
337  &p_wrap_around, /* Buffer address (if wrap around) */
338  &l_bytes2, /* Count of bytes after wrap around */
339  0); /* Flags */
340 
341  if (dsresult == DSERR_BUFFERLOST)
342  {
343  IDirectSoundBuffer_Restore(m_dsbuffer);
344  dsresult = IDirectSoundBuffer_Lock(m_dsbuffer, m_writeCursor, size,
345  &p_write_position, &l_bytes1,
346  &p_wrap_around, &l_bytes2, 0);
347  }
348 
349  if (dsresult != DS_OK)
350  {
351  VBERROR("Cannot lock buffer, audio dropped");
352  return;
353  }
354 
355  memcpy(p_write_position, buffer, l_bytes1);
356  if (p_wrap_around)
357  memcpy(p_wrap_around, buffer + l_bytes1, l_bytes2);
358 
359  m_writeCursor += l_bytes1 + l_bytes2;
360 
361  while (m_writeCursor >= (DWORD)m_parent->m_soundcardBufferSize)
363 
364  IDirectSoundBuffer_Unlock(m_dsbuffer, p_write_position, l_bytes1,
365  p_wrap_around, l_bytes2);
366 }
367 
369 {
370  HRESULT dsresult;
371 
372  dsresult = IDirectSoundBuffer_Play(m_dsbuffer, 0, 0, DSBPLAY_LOOPING);
373  if (dsresult == DSERR_BUFFERLOST)
374  {
375  IDirectSoundBuffer_Restore(m_dsbuffer);
376  dsresult = IDirectSoundBuffer_Play(m_dsbuffer, 0, 0, DSBPLAY_LOOPING);
377  }
378  if (dsresult != DS_OK)
379  {
380  VBERROR("Cannot start playing buffer");
381  m_playStarted = false;
382  return false;
383  }
384 
385  m_playStarted=true;
386  return true;
387 }
388 
390 {
391  AudioOutputSettings *settings = new AudioOutputSettings();
392  DSCAPS devcaps;
393  devcaps.dwSize = sizeof(DSCAPS);
394 
395  m_priv->InitDirectSound(passthrough);
396  if ((!m_priv->m_dsobject || !m_priv->m_dsound_dll) ||
397  FAILED(IDirectSound_GetCaps(m_priv->m_dsobject, &devcaps)) )
398  {
399  delete settings;
400  return nullptr;
401  }
402 
403  VBAUDIO(QString("GetCaps sample rate min: %1 max: %2")
404  .arg(devcaps.dwMinSecondarySampleRate)
405  .arg(devcaps.dwMaxSecondarySampleRate));
406 
407  /* We shouldn't assume we can do everything between min and max but
408  there's no way to test individual rates, so we'll have to */
409  while (DWORD rate = (DWORD)settings->GetNextRate())
410  if((rate >= devcaps.dwMinSecondarySampleRate) ||
411  (rate <= devcaps.dwMaxSecondarySampleRate))
412  settings->AddSupportedRate(rate);
413 
414  /* We can only test for 8 and 16 bit support, DS uses float internally */
415  if (devcaps.dwFlags & DSCAPS_PRIMARY8BIT)
416  settings->AddSupportedFormat(FORMAT_U8);
417  if (devcaps.dwFlags & DSCAPS_PRIMARY16BIT)
418  settings->AddSupportedFormat(FORMAT_S16);
419 #if 0 // 24-bit integer is not supported
420  settings->AddSupportedFormat(FORMAT_S24);
421 #endif
422 #if 0 // 32-bit integer (OGG) is not supported on all platforms.
423  settings->AddSupportedFormat(FORMAT_S32);
424 #endif
425 #if 0 // 32-bit floating point (AC3) is not supported on all platforms.
426  settings->AddSupportedFormat(FORMAT_FLT);
427 #endif
428 
429  /* No way to test anything other than mono or stereo, guess that we can do
430  up to 5.1 */
431  for (uint i = 2; i < 7; i++)
432  settings->AddSupportedChannels(i);
433 
434  settings->setPassthrough(0); // Maybe passthrough
435 
436  return settings;
437 }
438 
440 {
442  DSBUFFERDESC dsbdesc;
443 
444  CloseDevice();
445 
446  m_UseSPDIF = m_passthru || m_enc;
447  m_priv->InitDirectSound(m_UseSPDIF);
448  if (!m_priv->m_dsobject || !m_priv->m_dsound_dll)
449  {
450  Error(QObject::tr("DirectSound initialization failed"));
451  return false;
452  }
453 
454  // fragments are 50ms worth of samples
455  m_fragmentSize = 50 * m_outputBytesPerFrame * m_sampleRate / 1000;
456  // DirectSound buffer holds 4 fragments = 200ms worth of samples
457  m_soundcardBufferSize = m_fragmentSize << 2;
458 
459  VBAUDIO(QString("DirectSound buffer size: %1").arg(m_soundcardBufferSize));
460 
461  wf.Format.nChannels = m_channels;
462  wf.Format.nSamplesPerSec = m_sampleRate;
463  wf.Format.nBlockAlign = m_outputBytesPerFrame;
464  wf.Format.nAvgBytesPerSec = m_sampleRate * m_outputBytesPerFrame;
465  wf.Format.wBitsPerSample = (m_outputBytesPerFrame << 3) / m_channels;
467  AudioOutputSettings::FormatToBits(m_outputFormat);
468 
469  if (m_UseSPDIF)
470  {
471  wf.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
472  wf.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
473  }
474  else if (m_outputFormat == FORMAT_FLT)
475  {
476  wf.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
477  wf.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
478  }
479  else
480  {
481  wf.Format.wFormatTag = WAVE_FORMAT_PCM;
482  wf.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
483  }
484 
485  VBAUDIO(QString("New format: %1bits %2ch %3Hz %4")
486  .arg(wf.Samples.wValidBitsPerSample).arg(m_channels)
487  .arg(m_sampleRate).arg(m_UseSPDIF ? "data" : "PCM"));
488 
489  if (m_channels <= 2)
490  wf.Format.cbSize = 0;
491  else
492  {
493  wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
494  wf.dwChannelMask = 0x003F; // 0x003F = 5.1 channels
495  wf.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
496  }
497 
498  memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
499  dsbdesc.dwSize = sizeof(DSBUFFERDESC);
500  dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 // Better position accuracy
501  | DSBCAPS_GLOBALFOCUS // Allows background playing
502  | DSBCAPS_LOCHARDWARE; // Needed for 5.1 on emu101k
503 
504  if (!m_UseSPDIF)
505  dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; // Allow volume control
506 
507  dsbdesc.dwBufferBytes = m_soundcardBufferSize; // buffer size
508  dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wf;
509 
510  if (FAILED(IDirectSound_CreateSoundBuffer(m_priv->m_dsobject, &dsbdesc,
511  &m_priv->m_dsbuffer, nullptr)))
512  {
513  /* Vista does not support hardware mixing
514  try without DSBCAPS_LOCHARDWARE */
515  dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;
516  HRESULT dsresult =
517  IDirectSound_CreateSoundBuffer(m_priv->m_dsobject, &dsbdesc,
518  &m_priv->m_dsbuffer, nullptr);
519  if (FAILED(dsresult))
520  {
521  if (dsresult == DSERR_UNSUPPORTED)
522  Error(QObject::tr("Unsupported format for device %1:%2")
523  .arg(m_priv->m_device_num).arg(m_priv->m_device_name));
524  else
525  Error(QObject::tr("Failed to create DS buffer 0x%1")
526  .arg((DWORD)dsresult, 0, 16));
527  return false;
528  }
529  VBAUDIO("Using software mixer");
530  }
531  VBAUDIO("Created DirectSound buffer");
532 
533  return true;
534 }
535 
537 {
538  if (m_priv->m_dsbuffer)
539  m_priv->DestroyDSBuffer();
540 }
541 
542 void AudioOutputDX::WriteAudio(unsigned char * buffer, int size)
543 {
544  if (size == 0)
545  return;
546 
547  m_priv->FillBuffer(buffer, size);
548  if (!m_priv->m_playStarted)
549  m_priv->StartPlayback();
550 }
551 
553 {
554  if (!m_priv->m_playStarted)
555  return 0;
556 
557  HRESULT dsresult;
558  DWORD play_pos, write_pos;
559  int buffered;
560 
561  dsresult = IDirectSoundBuffer_GetCurrentPosition(m_priv->m_dsbuffer,
562  &play_pos, &write_pos);
563  if (dsresult != DS_OK)
564  {
565  VBERROR("Cannot get current buffer position");
566  return 0;
567  }
568 
569  buffered = (int)m_priv->m_writeCursor - (int)play_pos;
570 
571  if (buffered <= 0)
572  buffered += m_soundcardBufferSize;
573 
574  return buffered;
575 }
576 
577 int AudioOutputDX::GetVolumeChannel([[maybe_unused]] int channel) const
578 {
579  HRESULT dsresult;
580  long dxVolume = 0;
581  int volume;
582 
583  if (m_UseSPDIF)
584  return 100;
585 
586  dsresult = IDirectSoundBuffer_GetVolume(m_priv->m_dsbuffer, &dxVolume);
587  volume = (int)(pow(10,(float)dxVolume/20)*100);
588 
589  if (dsresult != DS_OK)
590  {
591  VBERROR(QString("Failed to get volume %1").arg(dxVolume));
592  return volume;
593  }
594 
595  VBAUDIO(QString("Got volume %1").arg(volume));
596  return volume;
597 }
598 
599 void AudioOutputDX::SetVolumeChannel([[maybe_unused]] int channel, int volume)
600 {
601  HRESULT dsresult;
602  long dxVolume { DSBVOLUME_MIN };
603  if (volume > 0)
604  {
605  float dbAtten = 20 * log10((float)volume/100.F);
606  dxVolume = (long)(100.0F * dbAtten);
607  }
608 
609  if (m_UseSPDIF)
610  return;
611 
612  // dxVolume is attenuation in 100ths of a decibel
613  dsresult = IDirectSoundBuffer_SetVolume(m_priv->m_dsbuffer, dxVolume);
614 
615  if (dsresult != DS_OK)
616  {
617  VBERROR(QString("Failed to set volume %1").arg(dxVolume));
618  return;
619  }
620 
621  VBAUDIO(QString("Set volume %1").arg(dxVolume));
622 }
623 
624 QMap<int, QString> *AudioOutputDX::GetDXDevices(void)
625 {
626  AudioOutputDXPrivate *tmp_priv = new AudioOutputDXPrivate(nullptr);
627  tmp_priv->InitDirectSound(false);
628  QMap<int, QString> *dxdevs = new QMap<int, QString>(tmp_priv->m_device_list);
629  delete tmp_priv;
630  return dxdevs;
631 }
632 
633 /* vim: set expandtab tabstop=4 shiftwidth=4: */
AudioOutputDXPrivate::AudioOutputDXPrivate
AudioOutputDXPrivate(AudioOutputDX *in_parent)
Definition: audiooutputdx.cpp:54
AudioOutputDXPrivate::m_dsbuffer
LPDIRECTSOUNDBUFFER m_dsbuffer
Definition: audiooutputdx.cpp:88
LPFNDSC
HRESULT(WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN) LPFNDSC
Definition: audiooutputdx.cpp:126
WAVEFORMATEXTENSIBLE::SubFormat
GUID SubFormat
Definition: audiooutputdx.cpp:39
AudioOutputSettings::GetNextRate
int GetNextRate()
Definition: audiooutputsettings.cpp:67
AudioOutputBase::m_discreteDigital
bool m_discreteDigital
Definition: audiooutputbase.h:187
AudioOutputDXPrivate::m_device_name
QString m_device_name
Definition: audiooutputdx.cpp:95
AudioOutputDX
Definition: audiooutputdx.h:12
WAVEFORMATEXTENSIBLE::Samples
union WAVEFORMATEXTENSIBLE::@2 Samples
AudioOutputSettings::setPassthrough
void setPassthrough(int val)
Definition: audiooutputsettings.h:76
VBAUDIO
#define VBAUDIO(str)
Definition: audiooutputbase.h:20
error
static void error(const char *str,...)
Definition: vbi.cpp:37
AudioOutputDXPrivate::DestroyDSBuffer
void DestroyDSBuffer(void)
Definition: audiooutputdx.cpp:272
AudioOutputSettings::AddSupportedFormat
void AddSupportedFormat(AudioFormat format)
Definition: audiooutputsettings.cpp:127
AudioOutputDX::~AudioOutputDX
virtual ~AudioOutputDX()
Definition: audiooutputdx.cpp:115
FORMAT_S16
@ FORMAT_S16
Definition: audiooutputsettings.h:27
FORMAT_S24
@ FORMAT_S24
Definition: audiooutputsettings.h:29
AudioOutputDXPrivate::DSEnumCallback
static int CALLBACK DSEnumCallback(LPGUID lpGuid, LPCSTR lpcstrDesc, LPCSTR lpcstrModule, LPVOID lpContext)
Definition: audiooutputdx.cpp:137
AudioOutputDX::AudioOutputDX
AudioOutputDX(const AudioSettings &settings)
Definition: audiooutputdx.cpp:100
FORMAT_S32
@ FORMAT_S32
Definition: audiooutputsettings.h:30
AudioOutputDX::OpenDevice
bool OpenDevice(void) override
Definition: audiooutputdx.cpp:439
AudioOutputBase::KillAudio
void KillAudio(void)
Kill the output thread and cleanup.
Definition: audiooutputbase.cpp:870
AudioOutputDX::GetVolumeChannel
int GetVolumeChannel(int channel) const override
Definition: audiooutputdx.cpp:577
AudioOutputSettings::FormatToBits
static int FormatToBits(AudioFormat format)
Definition: audiooutputsettings.cpp:150
AudioOutputDXPrivate::m_deviceGUID
GUID m_deviceGUID
Definition: audiooutputdx.cpp:91
WAVE_FORMAT_DOLBY_AC3_SPDIF
#define WAVE_FORMAT_DOLBY_AC3_SPDIF
Definition: audiooutputdx.cpp:19
VBERROR
#define VBERROR(str)
Definition: audiooutputbase.h:23
x0
static int x0
Definition: mythsocket.cpp:49
AudioOutputDXPrivate
Definition: audiooutputdx.cpp:51
AudioOutputDXPrivate::ResetDirectSound
void ResetDirectSound(void)
Definition: audiooutputdx.cpp:168
AudioOutputDX::m_priv
AudioOutputDXPrivate * m_priv
Definition: audiooutputdx.h:31
DEFINE_GUID
DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16)
WAVE_FORMAT_EXTENSIBLE
#define WAVE_FORMAT_EXTENSIBLE
Definition: audiooutputdx.cpp:27
AudioOutputSettings::AddSupportedChannels
void AddSupportedChannels(int channels)
Definition: audiooutputsettings.cpp:237
AudioOutputDX::GetDXDevices
static QMap< int, QString > * GetDXDevices(void)
Definition: audiooutputdx.cpp:624
FORMAT_U8
@ FORMAT_U8
Definition: audiooutputsettings.h:26
AudioSettings
Definition: audiosettings.h:28
AudioOutputBase::m_mainDevice
QString m_mainDevice
Definition: audiooutputbase.h:185
AudioOutputBase::m_soundcardBufferSize
long m_soundcardBufferSize
Definition: audiooutputbase.h:183
AudioOutputBase
Definition: audiooutputbase.h:51
AudioSettings::m_init
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
Definition: audiosettings.h:85
AudioOutputDXPrivate::m_parent
AudioOutputDX * m_parent
Definition: audiooutputdx.cpp:85
mythlogging.h
AudioOutputDXPrivate::FillBuffer
void FillBuffer(unsigned char *buffer, int size)
Definition: audiooutputdx.cpp:286
AudioOutputDXPrivate::InitDirectSound
int InitDirectSound(bool passthrough=false)
Definition: audiooutputdx.cpp:190
AudioOutputBase::Reconfigure
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
Definition: audiooutputbase.cpp:472
AudioOutputDXPrivate::m_dsound_dll
HINSTANCE m_dsound_dll
Definition: audiooutputdx.cpp:86
AudioOutputSettings::AddSupportedRate
void AddSupportedRate(int rate)
Definition: audiooutputsettings.cpp:78
hardwareprofile.smolt.long
long
Definition: smolt.py:75
AudioOutputDXPrivate::m_playStarted
bool m_playStarted
Definition: audiooutputdx.cpp:89
AudioOutputDXPrivate::m_device_list
QMap< int, QString > m_device_list
Definition: audiooutputdx.cpp:96
AudioOutputDXPrivate::m_chosenGUID
GUID * m_chosenGUID
Definition: audiooutputdx.cpp:92
WAVEFORMATEXTENSIBLE::dwChannelMask
DWORD dwChannelMask
Definition: audiooutputdx.cpp:38
WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT
Definition: audiooutputdx.cpp:23
AudioOutputBase::m_passthruDevice
QString m_passthruDevice
Definition: audiooutputbase.h:186
AudioOutputDXPrivate::m_device_num
int m_device_num
Definition: audiooutputdx.cpp:94
AudioOutputSettings
Definition: audiooutputsettings.h:48
AudioOutputDX::GetOutputSettings
AudioOutputSettings * GetOutputSettings(bool passthrough) override
Definition: audiooutputdx.cpp:389
WAVEFORMATEXTENSIBLE::wValidBitsPerSample
WORD wValidBitsPerSample
Definition: audiooutputdx.cpp:34
AudioOutputBase::InitSettings
void InitSettings(const AudioSettings &settings)
Definition: audiooutputbase.cpp:119
audiooutputdx.h
AudioOutputDX::GetBufferedOnSoundcard
int GetBufferedOnSoundcard(void) const override
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
Definition: audiooutputdx.cpp:552
scrapertest.FAILED
list FAILED
Definition: scrapertest.py:17
AudioOutputDXPrivate::m_dsobject
LPDIRECTSOUND m_dsobject
Definition: audiooutputdx.cpp:87
LPFNDSE
HRESULT(WINAPI *)(LPDSENUMCALLBACK, LPVOID) LPFNDSE
Definition: audiooutputdx.cpp:127
AudioOutputDX::CloseDevice
void CloseDevice(void) override
Definition: audiooutputdx.cpp:536
FORMAT_FLT
@ FORMAT_FLT
Definition: audiooutputsettings.h:31
AudioOutputDXPrivate::m_device_count
int m_device_count
Definition: audiooutputdx.cpp:93
AudioOutputDX::SetVolumeChannel
void SetVolumeChannel(int channel, int volume) override
Definition: audiooutputdx.cpp:599
AudioOutputDX::WriteAudio
void WriteAudio(unsigned char *buffer, int size) override
Definition: audiooutputdx.cpp:542
AudioOutputDXPrivate::m_writeCursor
DWORD m_writeCursor
Definition: audiooutputdx.cpp:90
AudioOutputDXPrivate::StartPlayback
bool StartPlayback(void)
Definition: audiooutputdx.cpp:368
WAVEFORMATEXTENSIBLE::wSamplesPerBlock
WORD wSamplesPerBlock
Definition: audiooutputdx.cpp:35
WAVEFORMATEXTENSIBLE
Definition: audiooutputdx.cpp:31
uint
unsigned int uint
Definition: freesurround.h:24
WAVEFORMATEXTENSIBLE::wReserved
WORD wReserved
Definition: audiooutputdx.cpp:36
VBAUDIOTS
#define VBAUDIOTS(str)
Definition: audiooutputbase.h:21
WAVEFORMATEXTENSIBLE::Format
WAVEFORMATEX Format
Definition: audiooutputdx.cpp:32
AudioOutputDXPrivate::~AudioOutputDXPrivate
~AudioOutputDXPrivate()
Definition: audiooutputdx.cpp:57