www.pudn.com > helix.src.0812.rar > audsymbian.cpp
/* ***** BEGIN LICENSE BLOCK ***** * Version: RCSL 1.0/RPSL 1.0 * * Portions Copyright (c) 1995-2003 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#include #include "hxassert.h" #include "hxresult.h" #include "hxslist.h" #include "hxcom.h" #include "hxausvc.h" #include "ihxpckts.h" #include "audiosvr/audio_svr.h" #include "audiosvr/audio_svr_cntxt.h" #include "audsymbian.h" static UINT32 Scale(UINT32 v, UINT32 f0, UINT32 f1, UINT32 t0, UINT32 t1); CHXAudioDevice::CHXAudioDevice() : CActive(EPriorityHigh), m_lRefCount(0), m_deviceOpen(false), m_pWriteList(NULL), m_pDeviceResponse(NULL), m_pAudioStream(NULL), m_pAudioServerContext(NULL), m_paused(false), m_uMinPlayerVolume(0), m_uMaxPlayerVolume(100), m_uMinDevVolume(0), m_uMaxDevVolume(100) { CActiveScheduler::Add(this); } CHXAudioDevice::~CHXAudioDevice() { Close(TRUE); } ULONG32 CHXAudioDevice::AddRef() { return InterlockedIncrement(&m_lRefCount); } ULONG32 CHXAudioDevice::Release() { if (InterlockedDecrement(&m_lRefCount) > 0) { return m_lRefCount; } delete this; return 0; } HX_RESULT CHXAudioDevice::QueryInterface(REFIID riid, void** ppvObj) { if (IsEqualIID(riid, IID_IHXAudioDevice)) { AddRef(); *ppvObj = (IHXAudioDevice*)this; return HXR_OK; } else if (IsEqualIID(riid, IID_IUnknown)) { AddRef(); *ppvObj = this; return HXR_OK; } *ppvObj = NULL; return HXR_NOINTERFACE; } HX_RESULT CHXAudioDevice::Open(const HXAudioFormat* pFormat, IHXAudioDeviceResponse* pDeviceResponse) { HX_RESULT res = HXR_OK; HX_ASSERT(!m_pDeviceResponse); HX_RELEASE(m_pDeviceResponse); if( pDeviceResponse ) { m_pDeviceResponse = pDeviceResponse; m_pDeviceResponse->AddRef(); } if (NULL == (m_pWriteList = new CHXSimpleList)) { res = HXR_OUTOFMEMORY; } else if (HXR_OK != OpenDevice() || HXR_OK != InitDevice(pFormat)) { res = HXR_FAIL; } return res; } HX_RESULT CHXAudioDevice::Close(const BOOL bFlush) { Reset(); if (m_pAudioStream) { m_pAudioStream->Close(); m_pAudioServerContext->Stop(); m_deviceOpen = false; HX_DELETE(m_pAudioStream); HX_DELETE(m_pAudioServerContext); HX_DELETE(m_pWriteList); HX_RELEASE(m_pDeviceResponse); } return HXR_OK; } HX_RESULT CHXAudioDevice::Write(const HXAudioData* pAudioData) { HX_RESULT res = HXR_OK; if (pAudioData) { // add the buffer to the pending write list IHXBuffer* pAudioBuf = pAudioData->pData; pAudioBuf->AddRef(); LISTPOSITION listRet = m_pWriteList->AddTail(pAudioBuf); if( listRet == NULL ) { HX_RELEASE(pAudioBuf); res = HXR_OUTOFMEMORY; } // if we are not waiting for a write to complete, // write the next pending buffer if (!IsActive() && !m_paused && res == HXR_OK) { IHXBuffer* pWriteBuf = (IHXBuffer*)m_pWriteList->GetHead(); if (pWriteBuf) { res = WriteToDevice(pWriteBuf); } } } return res; } HX_RESULT CHXAudioDevice::Reset() { if (m_pAudioStream) { if (!m_pAudioStream->Stopped()) { m_pAudioStream->Stop(); } } if (IsActive()) { Cancel(); } if (m_pWriteList) { while(!m_pWriteList->IsEmpty()) { IHXBuffer* pBuf = (IHXBuffer*)m_pWriteList->RemoveHead(); HX_RELEASE(pBuf); } } return HXR_OK; } HX_RESULT CHXAudioDevice::Drain() { HX_ASSERT("Not implemented"==NULL); return HXR_FAIL; } HX_RESULT CHXAudioDevice::SetVolume( const UINT16 uVolume ) { HX_RESULT res = HXR_FAIL; if( m_pAudioStream ) { m_pAudioStream->SetVolume(TInt(Scale(UINT32(uVolume), m_uMinPlayerVolume, m_uMaxPlayerVolume, m_uMinDevVolume, m_uMaxDevVolume))); res = HXR_OK; } return res; } HX_RESULT CHXAudioDevice::GetCurrentAudioTime( ULONG32& ulCurrentTime ) { HX_RESULT res = HXR_FAIL; HX_ASSERT(m_pAudioStream); if( m_pAudioStream ) { ulCurrentTime = m_pAudioStream->GetTime(); res = HXR_OK; } return res; } BOOL CHXAudioDevice::SupportsVolume() { return TRUE; } UINT16 CHXAudioDevice::GetVolume() { UINT16 vol = 0; if (m_pAudioStream) { vol = UINT16(Scale(UINT32(m_pAudioStream->GetVolume()), m_uMinDevVolume, m_uMaxDevVolume, m_uMinPlayerVolume, m_uMaxPlayerVolume)); } return vol; } short CHXAudioDevice::GetAudioFd( void ) { //We don't have file descriptors on symbian for the //audio device. return 0; } HX_RESULT CHXAudioDevice::Seek(ULONG32 ulSeekTime) { HX_ASSERT( "Not implemented"==NULL); return HXR_OK; } HX_RESULT CHXAudioDevice::Resume() { m_paused = false; if (m_pAudioStream) { m_pAudioStream->Play(); } // write the next buffer on the pending write list if (!IsActive() && !m_pWriteList->IsEmpty()) { IHXBuffer* pWriteBuf = (IHXBuffer*)m_pWriteList->GetHead(); if (pWriteBuf) { WriteToDevice(pWriteBuf); } } return HXR_OK; } HX_RESULT CHXAudioDevice::Pause() { HX_RESULT res = HXR_OK; m_paused = true; if (m_pAudioStream) { m_pAudioStream->Pause(); } return res; } HX_RESULT CHXAudioDevice::CheckFormat(const HXAudioFormat* pFormat) { HX_RESULT res = HXR_FAIL; //Symbian only supports 16-bit PCM. if (pFormat->uBitsPerSample == 16 && HXR_OK == OpenDevice() && HXR_OK == InitDevice(pFormat)) { res = HXR_OK; } return res; } UINT16 CHXAudioDevice::NumberOfBlocksRemainingToPlay(void) { return (UINT16)(m_pWriteList->GetCount() + m_pAudioStream->GetBlocksBuffered()); } BOOL CHXAudioDevice::InitVolume(const UINT16 uMinVolume, const UINT16 uMaxVolume ) { HX_ASSERT(m_uMaxPlayerVolume > m_uMinPlayerVolume); if (m_uMaxPlayerVolume > m_uMinPlayerVolume) { m_uMinPlayerVolume = uMinVolume; m_uMaxPlayerVolume = uMaxVolume; } return (m_uMaxPlayerVolume > m_uMinPlayerVolume) && SupportsVolume(); } // // CActive methods // void CHXAudioDevice::RunL() { if (iStatus != KErrCancel) { // the buffer at the head of the list is the one we just wrote // remove it from the list and release it if (!m_pWriteList->IsEmpty()) { IHXBuffer* m_pHeadBuf = (IHXBuffer*)m_pWriteList->RemoveHead(); HX_ASSERT(m_pHeadBuf); HX_RELEASE(m_pHeadBuf); } // write the next buffer on the pending write list if (!m_paused && !m_pWriteList->IsEmpty()) { IHXBuffer* pWriteBuf = (IHXBuffer*)m_pWriteList->GetHead(); if (pWriteBuf) { WriteToDevice(pWriteBuf); } } // call back the response object to update time if (m_pDeviceResponse) { ULONG32 ulAudioTime = 0; GetCurrentAudioTime(ulAudioTime); m_pDeviceResponse->OnTimeSync(ulAudioTime); } } } void CHXAudioDevice::DoCancel() { if (m_pAudioStream) { m_pAudioStream->CancelWrite(); } } ////////////////////////////////////////////////////////////////////// // private methods /////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// HX_RESULT CHXAudioDevice::OpenDevice() { HX_RESULT res = HXR_FAIL; if (m_deviceOpen) return HXR_OK; if(!m_pAudioStream) { m_pAudioStream = new HXSymbianAudioClient; } if (m_pAudioStream) { // create the thread context for the audio server to run if (!m_pAudioServerContext) { m_pAudioServerContext = new HXSymbianAudioServerContext; } // start the audio sevrver thread if (m_pAudioServerContext && !m_pAudioServerContext->Running()) { m_pAudioServerContext->Start(); } // connect to the audio server and share the session if (m_pAudioServerContext->Running() && KErrNone == m_pAudioStream->Connect() && KErrNone == m_pAudioStream->Share(RSessionBase::EAutoAttach)) { m_deviceOpen = true; res = HXR_OK; } } return res; } HX_RESULT CHXAudioDevice::InitDevice(const HXAudioFormat* pFormat) { HX_RESULT res = HXR_FAIL; // attempt to init device with given audio format if (m_pAudioStream && (KErrNone == m_pAudioStream->Init(pFormat->ulSamplesPerSec, pFormat->uChannels))) { // grab device volume info (first opportunity) m_uMinDevVolume = m_pAudioStream->GetMinVolume(); m_uMaxDevVolume = m_pAudioStream->GetMaxVolume(); res = HXR_OK; } return res; } HX_RESULT CHXAudioDevice::WriteToDevice(IHXBuffer* pAudioBuf ) { HX_RESULT res = HXR_FAIL; HX_ASSERT( m_pAudioStream!=NULL ); if (m_pAudioStream) { // async call -- called back in RunL() on completion m_pAudioStream->Write(pAudioBuf, iStatus); SetActive(); res = HXR_OK; } return res; } ////////////////////////////////////////////////////////////////////// // convenience methods /////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// UINT32 Scale(UINT32 v, UINT32 f0, UINT32 f1, UINT32 t0, UINT32 t1) { HX_ASSERT(f1 > f0); HX_ASSERT(t1 >= t0); HX_ASSERT(v >= f0); if (f1 > f0 && v > f0) { UINT64 tr = t1 - t0; UINT64 fr = f1 - f0; UINT64 n = v - f0; UINT64 q = n / fr; UINT64 r = n % fr; return t0 + INT64_TO_UINT32((q * tr + (r * tr + (fr >> 1)) / fr)); } return 0; }