00001 #include <iostream>
00002
00003 using namespace std;
00004
00005 #include "mythlogging.h"
00006 #include "audiooutputwin.h"
00007
00008 #include <windows.h>
00009 #include <mmsystem.h>
00010 #include <objbase.h>
00011
00012 #define LOC QString("AOWin: ")
00013
00014 #ifndef WAVE_FORMAT_IEEE_FLOAT
00015 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
00016 #endif
00017
00018 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
00019 #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
00020 #endif
00021
00022 #ifndef WAVE_FORMAT_EXTENSIBLE
00023 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
00024 #endif
00025
00026 #ifndef _WAVEFORMATEXTENSIBLE_
00027 typedef struct {
00028 WAVEFORMATEX Format;
00029 union {
00030 WORD wValidBitsPerSample;
00031 WORD wSamplesPerBlock;
00032 WORD wReserved;
00033 } Samples;
00034 DWORD dwChannelMask;
00035 GUID SubFormat;
00036 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
00037 #endif
00038
00039 const uint AudioOutputWin::kPacketCnt = 4;
00040
00041 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT,
00042 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
00043 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM,
00044 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
00045 DEFINE_GUID(_KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF,
00046 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
00047
00048 class AudioOutputWinPrivate
00049 {
00050 public:
00051 AudioOutputWinPrivate() :
00052 m_hWaveOut(NULL), m_WaveHdrs(NULL), m_hEvent(NULL)
00053 {
00054 m_WaveHdrs = new WAVEHDR[AudioOutputWin::kPacketCnt];
00055 memset(m_WaveHdrs, 0, sizeof(WAVEHDR) * AudioOutputWin::kPacketCnt);
00056 m_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
00057 }
00058
00059 ~AudioOutputWinPrivate()
00060 {
00061 if (m_WaveHdrs)
00062 {
00063 delete[] m_WaveHdrs;
00064 m_WaveHdrs = NULL;
00065 }
00066 if (m_hEvent)
00067 {
00068 CloseHandle(m_hEvent);
00069 m_hEvent = NULL;
00070 }
00071 }
00072
00073 void Close(void)
00074 {
00075 if (m_hWaveOut)
00076 {
00077 waveOutReset(m_hWaveOut);
00078 waveOutClose(m_hWaveOut);
00079 m_hWaveOut = NULL;
00080 }
00081 }
00082
00083 static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
00084 DWORD dwParam1, DWORD dwParam2);
00085
00086 public:
00087 HWAVEOUT m_hWaveOut;
00088 WAVEHDR *m_WaveHdrs;
00089 HANDLE m_hEvent;
00090 };
00091
00092 void CALLBACK AudioOutputWinPrivate::waveOutProc(HWAVEOUT hwo, UINT uMsg,
00093 DWORD dwInstance,
00094 DWORD dwParam1, DWORD dwParam2)
00095 {
00096 if (uMsg != WOM_DONE)
00097 return;
00098
00099 AudioOutputWin *instance = reinterpret_cast<AudioOutputWin*>(dwInstance);
00100 InterlockedDecrement(&instance->m_nPkts);
00101 if (instance->m_nPkts < (int)AudioOutputWin::kPacketCnt)
00102 {
00103 SetEvent(instance->m_priv->m_hEvent);
00104 }
00105 }
00106
00107 AudioOutputWin::AudioOutputWin(const AudioSettings &settings) :
00108 AudioOutputBase(settings),
00109 m_priv(new AudioOutputWinPrivate()),
00110 m_nPkts(0),
00111 m_CurrentPkt(0),
00112 m_OutPkts(NULL),
00113 m_UseSPDIF(settings.use_passthru)
00114 {
00115 InitSettings(settings);
00116 if (settings.init)
00117 Reconfigure(settings);
00118 m_OutPkts = (unsigned char**) calloc(kPacketCnt, sizeof(unsigned char*));
00119 }
00120
00121 AudioOutputWin::~AudioOutputWin()
00122 {
00123 KillAudio();
00124
00125 if (m_priv)
00126 {
00127 delete m_priv;
00128 m_priv = NULL;
00129 }
00130
00131 if (m_OutPkts)
00132 {
00133 for (uint i = 0; i < kPacketCnt; i++)
00134 if (m_OutPkts[i])
00135 free(m_OutPkts[i]);
00136
00137 free(m_OutPkts);
00138 m_OutPkts = NULL;
00139 }
00140 }
00141
00142 AudioOutputSettings* AudioOutputWin::GetOutputSettings(bool )
00143 {
00144 AudioOutputSettings *settings = new AudioOutputSettings();
00145
00146
00147
00148 while (DWORD rate = (DWORD)settings->GetNextRate())
00149 settings->AddSupportedRate(rate);
00150
00151
00152 settings->AddSupportedFormat(FORMAT_U8);
00153 settings->AddSupportedFormat(FORMAT_S16);
00154 settings->AddSupportedFormat(FORMAT_S24);
00155 settings->AddSupportedFormat(FORMAT_S32);
00156 settings->AddSupportedFormat(FORMAT_FLT);
00157
00158
00159 for (uint i = 2; i < 7; i++)
00160 settings->AddSupportedChannels(i);
00161
00162 settings->setPassthrough(0);
00163
00164 return settings;
00165 }
00166
00167 bool AudioOutputWin::OpenDevice(void)
00168 {
00169 CloseDevice();
00170
00171 fragment_size = 50 * output_bytes_per_frame * samplerate / 1000;
00172
00173 soundcard_buffer_size = kPacketCnt * fragment_size;
00174
00175 VBAUDIO(QString("Buffering %1 fragments of %2 bytes each, total: %3 bytes")
00176 .arg(kPacketCnt).arg(fragment_size).arg(soundcard_buffer_size));
00177
00178 m_UseSPDIF = passthru || enc;
00179
00180 WAVEFORMATEXTENSIBLE wf;
00181 wf.Format.nChannels = channels;
00182 wf.Format.nSamplesPerSec = samplerate;
00183 wf.Format.nBlockAlign = output_bytes_per_frame;
00184 wf.Format.nAvgBytesPerSec = samplerate * output_bytes_per_frame;
00185 wf.Format.wBitsPerSample = (output_bytes_per_frame << 3) / channels;
00186 wf.Samples.wValidBitsPerSample =
00187 AudioOutputSettings::FormatToBits(output_format);
00188
00189 if (m_UseSPDIF)
00190 {
00191 wf.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
00192 wf.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
00193 }
00194 else if (output_format == FORMAT_FLT)
00195 {
00196 wf.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
00197 wf.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
00198 }
00199 else
00200 {
00201 wf.Format.wFormatTag = WAVE_FORMAT_PCM;
00202 wf.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
00203 }
00204
00205 VBAUDIO(QString("New format: %1bits %2ch %3Hz %4")
00206 .arg(wf.Samples.wValidBitsPerSample).arg(channels)
00207 .arg(samplerate).arg(m_UseSPDIF ? "data" : "PCM"));
00208
00209
00210 if (channels <= 2)
00211 wf.Format.cbSize = 0;
00212 else
00213 {
00214 wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
00215 wf.dwChannelMask = 0x003F;
00216 wf.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
00217 }
00218
00219 MMRESULT mmr = waveOutOpen(&m_priv->m_hWaveOut, WAVE_MAPPER,
00220 (WAVEFORMATEX *)&wf,
00221 (DWORD)AudioOutputWinPrivate::waveOutProc,
00222 (DWORD)this, CALLBACK_FUNCTION);
00223
00224 if (mmr == WAVERR_BADFORMAT)
00225 {
00226 Error(QString("Unable to set audio output parameters %1")
00227 .arg(wf.Format.nSamplesPerSec));
00228 return false;
00229 }
00230
00231 return true;
00232 }
00233
00234 void AudioOutputWin::CloseDevice(void)
00235 {
00236 m_priv->Close();
00237 }
00238
00239 void AudioOutputWin::WriteAudio(unsigned char * buffer, int size)
00240 {
00241 if (!size)
00242 return;
00243
00244 if (InterlockedIncrement(&m_nPkts) > (int)kPacketCnt)
00245 {
00246 while (m_nPkts > (int)kPacketCnt)
00247 WaitForSingleObject(m_priv->m_hEvent, INFINITE);
00248 }
00249
00250 if (m_CurrentPkt >= kPacketCnt)
00251 m_CurrentPkt = 0;
00252
00253 WAVEHDR *wh = &m_priv->m_WaveHdrs[m_CurrentPkt];
00254 if (wh->dwFlags & WHDR_PREPARED)
00255 waveOutUnprepareHeader(m_priv->m_hWaveOut, wh, sizeof(WAVEHDR));
00256
00257 m_OutPkts[m_CurrentPkt] =
00258 (unsigned char*)realloc(m_OutPkts[m_CurrentPkt], size);
00259
00260 memcpy(m_OutPkts[m_CurrentPkt], buffer, size);
00261
00262 memset(wh, 0, sizeof(WAVEHDR));
00263 wh->lpData = (LPSTR)m_OutPkts[m_CurrentPkt];
00264 wh->dwBufferLength = size;
00265
00266 if (MMSYSERR_NOERROR != waveOutPrepareHeader(m_priv->m_hWaveOut, wh,
00267 sizeof(WAVEHDR)))
00268 VBERROR("WriteAudio: failed to prepare header");
00269 else if (MMSYSERR_NOERROR != waveOutWrite(m_priv->m_hWaveOut, wh,
00270 sizeof(WAVEHDR)))
00271 VBERROR("WriteAudio: failed to write packet");
00272
00273 m_CurrentPkt++;
00274 }
00275
00276 int AudioOutputWin::GetBufferedOnSoundcard(void) const
00277 {
00278 return m_nPkts * fragment_size;
00279 }
00280
00281 int AudioOutputWin::GetVolumeChannel(int channel) const
00282 {
00283 DWORD dwVolume = 0xffffffff;
00284 int Volume = 100;
00285 if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
00286 {
00287 Volume = (channel == 0) ?
00288 (LOWORD(dwVolume) / (0xffff / 100)) :
00289 (HIWORD(dwVolume) / (0xffff / 100));
00290 }
00291
00292 LOG(VB_AUDIO, LOG_INFO, QString("GetVolume(%1) %2 (%3)")
00293 .arg(channel).arg(Volume).arg(dwVolume));
00294
00295 return Volume;
00296 }
00297
00298 void AudioOutputWin::SetVolumeChannel(int channel, int volume)
00299 {
00300 if (channel > 1)
00301 VBERROR("Windows volume only supports stereo!");
00302
00303 DWORD dwVolume = 0xffffffff;
00304 if (MMSYSERR_NOERROR == waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &dwVolume))
00305 {
00306 if (channel == 0)
00307 dwVolume = (dwVolume & 0xffff0000) | (volume * (0xffff / 100));
00308 else
00309 dwVolume = (dwVolume & 0xffff) | ((volume * (0xffff / 100)) << 16);
00310 }
00311 else
00312 {
00313 dwVolume = volume * (0xffff / 100);
00314 dwVolume |= (dwVolume << 16);
00315 }
00316
00317 VBAUDIO(QString("SetVolume(%1) %2(%3)")
00318 .arg(channel).arg(volume).arg(dwVolume));
00319
00320 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, dwVolume);
00321 }