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

📄 hxaudevds.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ***** BEGIN LICENSE BLOCK ***** 
 * Version: RCSL 1.0/RPSL 1.0 
 *  
 * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
 *	
 * The contents of this file, and the files included with this file, are 
 * subject to the current version of the RealNetworks Public Source License 
 * Version 1.0 (the "RPSL") available at 
 * http://www.helixcommunity.org/content/rpsl unless you have licensed 
 * the file under the RealNetworks Community Source License Version 1.0 
 * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
 * in which case the RCSL will apply. You may also obtain the license terms 
 * directly from RealNetworks.	You may not use this file except in 
 * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
 * applicable to this file, the RCSL.  Please see the applicable RPSL or 
 * RCSL for the rights, obligations and limitations governing use of the 
 * contents of the file.  
 *  
 * This file is part of the Helix DNA Technology. RealNetworks is the 
 * developer of the Original Code and owns the copyrights in the portions 
 * it created. 
 *  
 * This file, and the files included with this file, is distributed and made 
 * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
 * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 * 
 * Technology Compatibility Kit Test Suite(s) Location: 
 *    http://www.helixcommunity.org/content/tck 
 * 
 * Contributor(s): 
 *  
 * ***** END LICENSE BLOCK ***** */ 

#include "hxtypes.h"
#if defined( _WINDOWS ) || defined( _WIN32 )
#include <windows.h>
#include <tchar.h>
#include <mmsystem.h>
#include "mmreg.h"
#endif /*defined( _WINDOWS ) || defined( _WIN32 )*/

#include <stdio.h>
#include <string.h>

#include "hxresult.h"
#include "cbqueue.h"
#include "cpqueue.h"
#include "hxslist.h"


#include "hxcom.h"
#include "hxengin.h"
#include "ihxpckts.h"	
#include "hxausvc.h"
#include "auderrs.h"
#include "math.h"   

#include "hxaudev.h"
#include "tsconvrt.h"

#include "hxaudevds.h"

extern HINSTANCE g_hInstance;

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE		
static const char HX_THIS_FILE[] = __FILE__;
#endif

typedef HRESULT (WINAPI* FPDIRECTSOUNDCREATE)(LPGUID lpGuid, LPDIRECTSOUND * ppDS, IUnknown FAR * pUnkOuter);

static LRESULT CALLBACK HXDSWndProc(HWND, UINT, WPARAM, LPARAM);
UINT	CHXAudioDeviceDS::zm_uDestroyMessage = 0;

const UINT32 kExitThreadWaitTime = 3000; // ms
#define HXMSG_TIMESYNC	WM_USER+501

const TCHAR* szTitle = _T("Helix DSWnd");
const TCHAR* szWindowClass = _T("Helix DSWndClass");
const TCHAR* kDSWaitEvent = _T("HelixDirectSoundNotifyWait");
const TCHAR* kDSDestroyMessage = _T("HX_DestroyDSWindowInternal");
const int BUFFER_TIME = 8;

extern BOOL RMEnableLogging();
extern void RMDSLog(const char* pFormatString, ...);
#define RMDS_LOG RMDSLog

CHXAudioDeviceDS::CHXAudioDeviceDS():
	m_ulLastPlayCursor(0)
    ,	m_ulLastWriteCursor(0)
    ,	m_ulCurrPlayTime(0)
    ,	m_ulCurrLoopTime(0)
    ,	m_pDSDev(NULL)
    ,	m_pPrimaryBuffer(NULL)
    ,	m_pSecondaryBuffer(NULL)
    ,	m_hwnd(NULL)
    ,	m_pAudioPtrStart(NULL)
    ,	m_hSoundDll(NULL)
    ,	m_ulLoops(0)
    ,	m_ulLoopTime(0)
    ,	m_hDSNotifyEvent(NULL)
    ,	m_hWaitThread(NULL)
    ,	m_nBlocksPerBuffer(0)
    ,	m_bExitThread(FALSE)
    ,	m_ulOriginalThreadId(0)
{
    // Create a unique message for destroying the audio window
    if (!zm_uDestroyMessage)
    {
	zm_uDestroyMessage = RegisterWindowMessage(kDSDestroyMessage);
    }

    #ifdef _WINCE
	WNDCLASS wcex;
    #else
	WNDCLASSEX wcex;
	wcex.cbSize 	= sizeof(WNDCLASSEX); 
	wcex.hIconSm	= NULL;
    #endif

    wcex.style		= CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc	= (WNDPROC)HXDSWndProc;
    wcex.cbClsExtra	= 0;
    wcex.cbWndExtra	= 0;
    wcex.hInstance	= g_hInstance;
    wcex.hIcon		= NULL;
    wcex.hCursor	= LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName	= NULL;
    wcex.lpszClassName	= szWindowClass;

    #ifdef _WINCE
	RegisterClass(&wcex);
    #else
	RegisterClassEx(&wcex);
    #endif

    #ifdef _WINCE
	m_hwnd = ::CreateWindow(szWindowClass, szTitle, 
				WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU,
				-5000, -5000, 1, 1, NULL, NULL, g_hInstance, NULL );
    #else
	m_hwnd = ::CreateWindow(szWindowClass, szTitle, 
				WS_OVERLAPPEDWINDOW,
				-5000, -5000, 1, 1, NULL, NULL, g_hInstance, NULL );
    #endif
    m_ulOriginalThreadId = GetCurrentThreadId();
    
    m_hSoundDll = ::LoadLibrary(_T("dsound.dll"));

}

CHXAudioDeviceDS::~CHXAudioDeviceDS()
{
    if (m_hSoundDll)
    {
	FreeLibrary(m_hSoundDll);
	m_hSoundDll = NULL;
    }

    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;
    }
}

/*
 * Set the format of the primary buffer, if possible. On WDM drivers, this has
 * no effect -- the kernel mixer determines that format.
 */

HX_RESULT CHXAudioDeviceDS::SetPrimaryBufferFormat()
{
    HX_RESULT res = HXR_OK ;

    DSBUFFERDESC bufferDesc;
    ::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC));

    bufferDesc.dwSize	   = sizeof(DSBUFFERDESC);
    bufferDesc.lpwfxFormat = 0 ;

    bufferDesc.dwBufferBytes = 0 ;
    bufferDesc.dwFlags	=  DSBCAPS_PRIMARYBUFFER ;

    /* close the primary buffer if we had one open before. */
    HX_RELEASE(m_pPrimaryBuffer) ;

    /* try to open with WAVE_FORMAT_EXTENSIBLE */
    res = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pPrimaryBuffer, NULL);

    if (res == DS_OK)
    {
        res = !DS_OK ;
        if (m_WaveFormat.Format.nChannels > 2)
        {
            res = m_pPrimaryBuffer->SetFormat(&m_WaveFormat.Format) ;
        }
        if (res != DS_OK)
        {
	    /* if that fails, try to open with WAVE_FORMAT_PCM */
	    m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_PCM ;
	    res = m_pPrimaryBuffer->SetFormat(&m_WaveFormat.Format) ;
        }
    }
    return res ;
}

/*
 *  IHXAudioDevice override methods
 */

HX_RESULT CHXAudioDeviceDS::_Imp_Open(const HXAudioFormat* pFormat)
{
    HX_RESULT theErr = HXR_FAIL;

    if(!m_hwnd || !m_hSoundDll)
	return theErr;

    // close open resources
    _Imp_Close() ;

    /* Get the IDirectSound interface */
    FPDIRECTSOUNDCREATE fpCreateDS = (FPDIRECTSOUNDCREATE) ::GetProcAddress(m_hSoundDll, _T("DirectSoundCreate"));
    if(!fpCreateDS)
	return theErr;

    theErr = fpCreateDS(NULL, &m_pDSDev, NULL);
    if (FAILED(theErr))
	return theErr;

    /* set the cooperative level. Because we want control over the format of the
       primary buffer (16 bit, multichannel!), we need DSSCL_PRIORITY. */
    m_pDSDev->SetCooperativeLevel(m_hwnd, DSSCL_PRIORITY );

    /* fill out the wave format structure */
    ::memset(&m_WaveFormat, 0, sizeof(m_WaveFormat));
    m_WaveFormat.Format.wFormatTag	= WAVE_FORMAT_EXTENSIBLE;
    m_WaveFormat.Format.nChannels	= pFormat->uChannels;
    m_WaveFormat.Format.nSamplesPerSec	= pFormat->ulSamplesPerSec;	
    m_WaveFormat.Format.wBitsPerSample	= pFormat->uBitsPerSample;
    m_WaveFormat.Format.nBlockAlign	= pFormat->uBitsPerSample/8 * pFormat->uChannels;
    m_WaveFormat.Format.nAvgBytesPerSec = m_WaveFormat.Format.nBlockAlign * pFormat->ulSamplesPerSec ;
    m_WaveFormat.Format.cbSize = 22;

    m_WaveFormat.Samples.wValidBitsPerSample = pFormat->uBitsPerSample;
    m_WaveFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM ;

    m_WaveFormat.dwChannelMask = defaultChannelMapping(pFormat->uChannels) ;

    /* set the format of the primary buffer. This will fail on WDM systems (because
       the kernel mixer termines the primary buffer format), but is important on
       non-WDM systems.
    
       This might change the m_WaveFormat structure from a WAVE_FORMAT_EXTENSIBLE
       to a WAVEFORMATEX.

       Ignore the result.
    */
    SetPrimaryBufferFormat() ;

    /* Now open a secondary buffer. */

    DSBUFFERDESC bufferDesc;
    ::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC));

    bufferDesc.dwSize	   = sizeof(DSBUFFERDESC);
    bufferDesc.lpwfxFormat = &m_WaveFormat.Format;

    // Manipulate the buffer size so that is is an exact multiple of the block size.
    // This will ensure that our write positions on the buffer are the same in every loop.
    // We need to do this so that we have fixed playback notification positions marking the end each write block.
    m_nBlocksPerBuffer = (m_WaveFormat.Format.nAvgBytesPerSec*BUFFER_TIME)/pFormat->uMaxBlockSize;
    m_ulTotalBuffer = pFormat->uMaxBlockSize*m_nBlocksPerBuffer;
    m_ulLoopTime = (double)m_ulTotalBuffer / (double)m_WaveFormat.Format.nAvgBytesPerSec;

    bufferDesc.dwBufferBytes = m_ulTotalBuffer ;
    bufferDesc.dwFlags	=
		      DSBCAPS_CTRLVOLUME | // so we can control the volume
		      DSBCAPS_GETCURRENTPOSITION2 | // finer position reports
		      DSBCAPS_CTRLPOSITIONNOTIFY | // have them reported here
		      DSBCAPS_GLOBALFOCUS | // take control!
		      DSBCAPS_STICKYFOCUS ;

    /* Again, try with WAVE_FORMAT_EXTENSIBLE first, but only if multichannel. */

    theErr = !DS_OK ;
    if (m_WaveFormat.Format.nChannels > 2)
    {
        m_WaveFormat.Format.wFormatTag	= WAVE_FORMAT_EXTENSIBLE;
        theErr = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pSecondaryBuffer, NULL);
    }

    if (theErr != DS_OK)
    {
	/* and if that fails, try WAVEFORMATEX */
	m_WaveFormat.Format.wFormatTag	= WAVE_FORMAT_PCM;
	theErr = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pSecondaryBuffer, NULL);
    }

    /* call it a day and count our blessings. */
    switch (theErr)
    {
	case DS_OK: 
	    theErr = HXR_OK;
	    break;
	case DSERR_OUTOFMEMORY:
	    theErr = HXR_OUTOFMEMORY;
	    break;
	default:
	    theErr = HXR_FAIL;
	    break;
    }

    if (SUCCEEDED(theErr) && m_pSecondaryBuffer)
    {
	m_eState = E_DEV_OPENED;

	KillThreadAndEvent();

	SetWindowLong(m_hwnd, GWL_USERDATA, (LONG)this);

	// Create the event to be signalled on playback position notifications and the thread to wait for those events to be signalled.
	m_hDSNotifyEvent = CreateEvent(NULL, TRUE, FALSE, kDSWaitEvent);

	// now set the notification positions for direct sound playback.
	IDirectSoundNotify* pNotify = NULL;
	m_pSecondaryBuffer->QueryInterface(IID_IDirectSoundNotify, (void**)&pNotify);
	if(pNotify && m_hDSNotifyEvent)
	{
	    DSBPOSITIONNOTIFY* aPositionNotify = new DSBPOSITIONNOTIFY[m_nBlocksPerBuffer];
	    if(aPositionNotify)
	    {
		for(int i = 0; i < m_nBlocksPerBuffer; i++)
		{
		    aPositionNotify[i].dwOffset = i * pFormat->uMaxBlockSize;
		    aPositionNotify[i].hEventNotify = m_hDSNotifyEvent;
		}
	    }
	    pNotify->SetNotificationPositions(m_nBlocksPerBuffer, aPositionNotify);
	    delete[] aPositionNotify;
	    DWORD dwWaitThreadID(0);
	    m_hWaitThread = CreateThread(NULL, 0, EventThreadProc, (LPVOID)this, 0, &dwWaitThreadID);
	}
	HX_RELEASE(pNotify);

	m_pSecondaryBuffer->SetVolume(DSBVOLUME_MAX);
	m_pSecondaryBuffer->SetCurrentPosition(0);
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -