⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winaudio.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		// 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 
#endif
CAudioOutWindows::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)
void
CAudioOutWindows::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_RESULT
CAudioOutWindows::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;
}

void
CAudioOutWindows::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 + -