📄 winaudio.cpp
字号:
// we want MS if we can get them mmTime.wType = TIME_MS; MMRESULT res = waveOutGetPosition(m_hWave, &mmTime, sizeof(MMTIME)); if (MMSYSERR_NOERROR == res) { // We must check the output format and convert to MS if possible switch (mmTime.wType) { case TIME_MS: { ulDeviceTime = mmTime.u.ms;#if defined(_WIN32) ULONG32 BitsPerSample = (pWFmt->nChannels * pWFmt->wBitsPerSample);#elif _WIN16 ULONG32 BitsPerSample = (pWFmt->nAvgBytesPerSec * 8 / pWFmt->nSamplesPerSec);#endif ULONG32 BitsPerSecond = (BitsPerSample * pWFmt->nSamplesPerSec); ulDeviceBytesPlayed = (mmTime.u.ms * BitsPerSecond) / 8000; } break; case TIME_SAMPLES: { // Convert samples to MS ulDeviceSamplesPlayed = mmTime.u.sample; if (m_ulLastDeviceSamplesPlayed > ulDeviceSamplesPlayed && ((m_ulLastDeviceSamplesPlayed - ulDeviceSamplesPlayed) > MAX_TIMESTAMP_GAP)) { m_ulDevPosRollOver++; } m_ulLastDeviceSamplesPlayed = ulDeviceSamplesPlayed; m_llDeviceSamplesPlayed = (INT64)ulDeviceSamplesPlayed + (INT64)m_ulDevPosRollOver * (INT64)MAX_UINT32; ulDeviceTime = (ULONG32)(((float)m_llDeviceSamplesPlayed/(float)pWFmt->nSamplesPerSec)*1000.f);#if defined(_WIN32) ULONG32 BitsPerSample = (pWFmt->nChannels * pWFmt->wBitsPerSample);#elif _WIN16 ULONG32 BitsPerSample = (pWFmt->nAvgBytesPerSec * 8 / pWFmt->nSamplesPerSec);#endif ulDeviceBytesPlayed = (ULONG32)(mmTime.u.sample * 8.0f) / BitsPerSample; } break; case TIME_BYTES: { // Convert Bytes to MS ulDeviceBytesPlayed = mmTime.u.cb; if (m_ulLastDeviceBytesPlayed > ulDeviceBytesPlayed && ((m_ulLastDeviceBytesPlayed - ulDeviceBytesPlayed) > MAX_TIMESTAMP_GAP)) { m_ulDevPosRollOver++; } m_ulLastDeviceBytesPlayed = ulDeviceBytesPlayed; m_llDeviceBytesPlayed = (INT64)ulDeviceBytesPlayed + (INT64)m_ulDevPosRollOver * (INT64)MAX_UINT32;//{FILE* f1 = ::fopen("c:\\audio.txt", "a+"); ::fprintf(f1, "ulDeviceBytesPlayed: %lu\n", ulDeviceBytesPlayed);::fclose(f1);}#if defined(_WIN32) ULONG32 BitsPerSample = (pWFmt->nChannels * pWFmt->wBitsPerSample);#elif _WIN16 ULONG32 BitsPerSample = (pWFmt->nAvgBytesPerSec * 8 / pWFmt->nSamplesPerSec);#endif ULONG32 BitsPerSecond = (BitsPerSample * pWFmt->nSamplesPerSec); ulDeviceTime = (ULONG32)((m_llDeviceBytesPlayed * 8000)/(INT64)BitsPerSecond); } break; } // ?? ulCurrentTime = ulDeviceTime + m_StreamTimeOffset + m_CorrectionOffset; ulCurrentTime = m_ulCurrentTime = ulDeviceTime; } else { ulCurrentTime = m_ulCurrentTime = 0; } //{FILE* f1 = ::fopen("c:\\audio.txt", "a+"); ::fprintf(f1, "%lu\t%lu\n", HX_GET_TICKCOUNT(), m_ulCurrentTime);::fclose(f1);} return HXR_OK;}/************************************************************************ * Method: * CAudioOutWindows::WaveOutProc * Purpose: * This static member function is called when the wave * device is finished playing its audio buffer. We use * it to tell audio services that we're ready for more. */#if defined(_WIN32) LRESULT __declspec(dllexport) CALLBACK #else LRESULT CALLBACK __export #endifCAudioOutWindows::WaveOutWndProc(HWND hWnd, // handle of window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam) // second message parameter){ DWORD dwParam1 = lParam; CAudioOutWindows* pThis = 0; if (uMsg == WM_NCCREATE) { CREATESTRUCT* lpCreate = 0; // Set our this pointer, so our WndProc can find us again lpCreate = (CREATESTRUCT FAR*) lParam; pThis = (CAudioOutWindows*) lpCreate->lpCreateParams; SetWindowLong(hWnd, OFFSET_THIS, (long) pThis); } else if (uMsg == WM_NCDESTROY) { // remove our this pointer so if somebody calls this function // again after the window is gone (and the object is gone // too) we don't try to call a method from the pointer SetWindowLong(hWnd, OFFSET_THIS, 0L); } else { pThis = (CAudioOutWindows*) (LPHANDLE)GetWindowLong(hWnd, OFFSET_THIS); } if (!pThis) { goto exit; } switch (uMsg) { case MM_WOM_DONE: HX_ASSERT(zm_bClosed || zm_pCurrentAudioDevice == pThis); if (!zm_bClosed && zm_pCurrentAudioDevice == pThis) { // Only do this on WOM_DONE, note there are other messages sent to this // callback function, like WOM_OPEN and WOM_CLOSE //DWORD dwTime1 = timeGetTime(); //OutputDebugString("START:(uMsg == MM_WOM_DONE) in WaveOutThreadProc\r\n"); pThis->m_pMutex->Lock(); if (zm_bClosed) { pThis->m_pMutex->Unlock(); goto exit; } WAVEHDR* pWAVEHDR; CWaveHeader* pWaveHeader; pWAVEHDR = (WAVEHDR*)dwParam1; pWaveHeader = (CWaveHeader*)pWAVEHDR->dwUser; /* We may have already removed it from the queue * while checking for _NumberOfBlocksRemainingToPlay */ if ((pWAVEHDR->dwFlags & WHDR_DONE) && !pThis->m_UsedBuffersList.IsEmpty() && pThis->m_UsedBuffersList.GetHead() == (void*) pWaveHeader) { // put it back in the queue pWaveHeader->m_bAvail = TRUE; pThis->m_rAvailBuffers.EnQueuePtr(pWaveHeader); /* This is assuming that we get WOM_DONEs sequentially * There seems to be a bug in WIN16 where it may return * WOM_DONEs out of order. Need to be fixed for that * XXX Rahul */ pThis->m_UsedBuffersList.RemoveHead(); } pThis->m_pMutex->Unlock(); if (pThis && !pThis->m_bResetting) { // Call the base class's OnTimeSync to let it know that we're done playing // the current chunk of audio //OutputDebugString("BEFORE:pThis->OnTimeSync()\r\n"); pThis->OnTimeSync(); } } break; case MM_WOM_OPEN: break; case MM_WOM_CLOSE: break; default: break; } if (uMsg == zm_uDestroyMessage) { LRESULT result = (LRESULT)DestroyWindow(hWnd); // free the memory used by this class now that our window is destroyed UnregisterClass(WND_CLASS, g_hInstance); return result; }exit: return ( DefWindowProc(hWnd, uMsg, wParam, lParam) ); }UINT16 CAudioOutWindows::_NumberOfBlocksRemainingToPlay(void){ m_pMutex->Lock(); UINT16 unRemaining = m_UsedBuffersList.GetCount(); /* There may be some buffers for which we have not receoved WOM_DONEs * but they have already been played */ if (unRemaining > 0) { LISTPOSITION ndxLastUsed = NULL; LISTPOSITION ndxUsed = m_UsedBuffersList.GetHeadPosition(); while (ndxUsed != NULL) { ndxLastUsed = ndxUsed; CWaveHeader* pWaveHeader = (CWaveHeader*) m_UsedBuffersList.GetNext(ndxUsed); if (pWaveHeader->m_WAVEHDR.dwFlags & WHDR_DONE) { if (unRemaining > 0) unRemaining--; // put it back in the queue pWaveHeader->m_bAvail = TRUE; m_rAvailBuffers.EnQueuePtr(pWaveHeader); m_UsedBuffersList.RemoveAt(ndxLastUsed); } else { /* We assume that subsequent blocks are also not done playing */ break; } } } m_pMutex->Unlock(); return unRemaining;}#if defined(_WIN32) && !defined(_WINCE)voidCAudioOutWindows::CheckForVolumeSupport(){ zm_bMixerVolSupportChecked = TRUE; if (!m_hWnd) { Register(); } // if there is more than 1 mixer, we need to find out which is the current one // we do this by determining the mixer being used by the current wave device int startIndex = 0; if (m_hWave != NULL && mixerGetNumDevs() > 1) { UINT nId = -1; if ((mixerGetID((HMIXEROBJ)m_hWave, &nId, MIXER_OBJECTF_HWAVEOUT) == MMSYSERR_NOERROR) && nId != -1) { startIndex = nId; } } for(UINT index = startIndex; index < mixerGetNumDevs(); index++) { if(mixerOpen(&m_hMixer, index, (DWORD)m_hWnd, 0, CALLBACK_WINDOW) == MMSYSERR_NOERROR) { MIXERLINE mxLine; mxLine.cbStruct = sizeof(MIXERLINE); mxLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT; if(mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxLine, MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR) { // use waveOutSetVolume for bad device(i.e. crystal audio) if (zm_audioDevice == HXAUDIO_UNKNOWN && mxLine.Target.szPname) { for (int i = 0; i < g_nBadDrivers; i++) { if (_tcsstr(mxLine.Target.szPname, g_badDrivers[i])) { zm_audioDevice = HXAUDIO_BADDEVICE; break; } } if (zm_audioDevice == HXAUDIO_UNKNOWN) { zm_audioDevice = HXAUDIO_GOODDEVICE; } } if (zm_audioDevice != HXAUDIO_BADDEVICE) { MIXERCONTROL mxControl; mxControl.cbStruct = sizeof(MIXERCONTROL); MIXERLINECONTROLS mxLineControls; mxLineControls.cbStruct = sizeof(MIXERLINECONTROLS); mxLineControls.dwLineID = mxLine.dwLineID; mxLineControls.cControls = 1; mxLineControls.cbmxctrl = mxControl.cbStruct; mxLineControls.pamxctrl = &mxControl; mxLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME | MIXERCONTROL_CONTROLF_UNIFORM; if(mixerGetLineControls((HMIXEROBJ)m_hMixer, &mxLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR) { if(mxLineControls.cControls) { zm_bVolSupport = TRUE; zm_bMixerVolSupport = TRUE; m_VolumeControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); m_VolumeControlDetails.dwControlID = mxControl.dwControlID; m_VolumeControlDetails.cChannels = 1; m_VolumeControlDetails.cMultipleItems = mxControl.cMultipleItems; } } } } break; } }}#endif /*_WIN32*/HX_RESULTCAudioOutWindows::Register(){ WNDCLASS internalClass;// OutputDebugString("BEFORE CALL TO:Register\r\n"); if (m_hWnd) { return HXR_OK; } //m_hInst = hInst; m_hInst = g_hInstance; if (!m_hInst) {#ifdef _DEBUG MessageBox(NULL, _T("Don't have a valid handle"), NULL, MB_OK);#endif return HXR_OUTOFMEMORY; } // XXXKM - let's see if we can get the class info first; added this additional // check due to a strange problem when registering a class that seems to already // be registered. For some reason, under some circumstance, RegisterClass returns // NULL and GetLastError returns 0x57 (invalid parameter), however the class // is already registered if (!::GetClassInfo(m_hInst, WND_CLASS, &internalClass)) { // First register our window class internalClass.style = 0; internalClass.lpfnWndProc = CAudioOutWindows::WaveOutWndProc; internalClass.cbClsExtra = 0; internalClass.cbWndExtra = sizeof( this ); internalClass.hInstance = m_hInst; // Use app's instance internalClass.hIcon = 0; internalClass.hCursor = 0; internalClass.hbrBackground = 0; internalClass.lpszMenuName = NULL; internalClass.lpszClassName = WND_CLASS; #ifdef _WIN16 if (!RegisterClass( &internalClass )) #else if (!RegisterClass( &internalClass ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) #endif /* _WIN16 */ { #ifdef _DEBUG MessageBox(NULL, _T("Could Not register class"), NULL, MB_OK); #endif return(HXR_OUTOFMEMORY); } m_bClassRegistered = TRUE; }// OutputDebugString("BEFORE CALL TO:CreateWindow\r\n"); // Now create an instance of the window m_hWnd = CreateWindow( WND_CLASS /*"AudioServicesInternal"*/, _T("Audio Services Internal Messages"), WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, m_hInst, this);#if defined(_WIN32) m_ulOriginalThreadId = GetCurrentThreadId();#endif if (!m_hWnd) {#ifdef _DEBUG MessageBox(NULL, _T("Could Not create messageWindow"), NULL, MB_OK);#endif return HXR_OUTOFMEMORY; } return HXR_OK;}voidCAudioOutWindows::UnRegister(){// OutputDebugString("BEFORE CALL TO:UnRegister\r\n"); // Ask the window to destroy itself if (m_hWnd) {#if defined(_WIN32) if (m_ulOriginalThreadId == GetCurrentThreadId()) { SendMessage(m_hWnd, zm_uDestroyMessage, 0, 0); } else { PostMessage(m_hWnd, zm_uDestroyMessage, 0, 0); Sleep(0); }#else SendMessage(m_hWnd, zm_uDestroyMessage, 0, 0);#endif m_hWnd = NULL; }/* // Ask the window to destroy itself if (m_hWnd && SendMessage(m_hWnd, zm_uDestroyMessage, 0, 0)) { m_hWnd = NULL; } // free the memory used by this class now that our window is destroyed UnregisterClass(WND_CLASS, g_hInstance);*/}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -