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