|
MythTV
0.26-pre
|
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> // For DEFINE_GUID 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; // bits of precision 00031 WORD wSamplesPerBlock; // valid if wBitsPerSample==0 00032 WORD wReserved; // If neither applies, set to zero 00033 } Samples; 00034 DWORD dwChannelMask; // which channels are present in stream 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 /*digital*/) 00143 { 00144 AudioOutputSettings *settings = new AudioOutputSettings(); 00145 00146 // We use WAVE_MAPPER to find a compatible device, so just claim support 00147 // for all of the standard rates 00148 while (DWORD rate = (DWORD)settings->GetNextRate()) 00149 settings->AddSupportedRate(rate); 00150 00151 // Support all standard formats 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 // Guess that we can do up to 5.1 00159 for (uint i = 2; i < 7; i++) 00160 settings->AddSupportedChannels(i); 00161 00162 settings->setPassthrough(0); //Maybe passthrough 00163 00164 return settings; 00165 } 00166 00167 bool AudioOutputWin::OpenDevice(void) 00168 { 00169 CloseDevice(); 00170 // fragments are 50ms worth of samples 00171 fragment_size = 50 * output_bytes_per_frame * samplerate / 1000; 00172 // DirectSound buffer holds 4 fragments = 200ms worth of samples 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 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ 00210 if (channels <= 2) 00211 wf.Format.cbSize = 0; 00212 else 00213 { 00214 wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 00215 wf.dwChannelMask = 0x003F; // 0x003F = 5.1 channels 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 }
1.7.6.1