audio_session-mda.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:19k
- /* ***** 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 ***** */
- #if defined (HELIX_CONFIG_CALYPSO_AUDIO_PREF)
- #include <calypso/audiopreference.h>
- #endif
- #include <mda/common/audio.h>
- #include "hxcom.h"
- #include "hxslist.h"
- #include "hxausvc.h"
- #include "hxbuffer.h"
- #include "audio_session-mda.h"
- #include "hxtick.h"
- static const TInt KClientPriority = 69; //EMdaPriorityNormal;
- #if defined(HELIX_CONFIG_CALYPSO_AUDIO_PREF)
- static const TMdaPriorityPreference KPriorityPref = (TMdaPriorityPreference)KAudioPrefComposer;
- #else
- static const TMdaPriorityPreference KPriorityPref = EMdaPriorityPreferenceTime;
- #endif // SERIES60_PLAYER
- const INT32 WriteBufferDepth = 10; // Number of buffers we allow in the queue before blocking the caller
- ////////////////////////////////////////////////////
- //
- static TInt FlagToNumber(TMdaAudioDataSettings::TAudioCaps flag)
- {
- switch( flag )
- {
- case TMdaAudioDataSettings::ESampleRate8000Hz:
- return 8000;
- case TMdaAudioDataSettings::ESampleRate11025Hz:
- return 11025;
- case TMdaAudioDataSettings::ESampleRate16000Hz:
- return 16000;
- case TMdaAudioDataSettings::ESampleRate22050Hz:
- return 22050;
- case TMdaAudioDataSettings::ESampleRate32000Hz:
- return 32000;
- case TMdaAudioDataSettings::ESampleRate44100Hz:
- return 44100;
- case TMdaAudioDataSettings::ESampleRate48000Hz:
- return 48000;
- case TMdaAudioDataSettings::EChannelsMono:
- return 1;
- case TMdaAudioDataSettings::EChannelsStereo:
- return 2;
- default:
- return 0;
- break;
- }
- return 0;
- }
- static TMdaAudioDataSettings::TAudioCaps NumberToFlag(TInt num)
- {
- switch(num)
- {
- case 1:
- return TMdaAudioDataSettings::EChannelsMono;
- case 2:
- return TMdaAudioDataSettings::EChannelsStereo;
- case 8000:
- return TMdaAudioDataSettings::ESampleRate8000Hz;
- case 11025:
- return TMdaAudioDataSettings::ESampleRate11025Hz;
- case 16000:
- return TMdaAudioDataSettings::ESampleRate16000Hz;
- case 22050:
- return TMdaAudioDataSettings::ESampleRate22050Hz;
- case 32000:
- return TMdaAudioDataSettings::ESampleRate32000Hz;
- case 44100:
- return TMdaAudioDataSettings::ESampleRate44100Hz;
- case 48000:
- return TMdaAudioDataSettings::ESampleRate48000Hz;
- default:
- return (TMdaAudioDataSettings::TAudioCaps)0;
- break;
- }
- return (TMdaAudioDataSettings::TAudioCaps)0;
- }
- HXSymbianAudioTimeline::HXSymbianAudioTimeline()
- {
- Reset(0);
- }
- HXSymbianAudioTimeline::~HXSymbianAudioTimeline()
- {}
- void HXSymbianAudioTimeline::Reset(UINT32 ulByteRate)
- {
- m_ulByteRate = ulByteRate;
- ClearWritten();
- m_ulBaseSec = 0;
- m_ulBaseSubSecBytes = 0;
- m_ulLastGetTime = 0;
- }
- void HXSymbianAudioTimeline::OnWrite(UINT32 ulBytes)
- {
- UINT32 ulSum = m_ulSubSecBytes + ulBytes;
- UINT32 ulSec = ulSum / m_ulByteRate;
- m_ulSecWritten += ulSec;
- m_ulSubSecBytes = ulSum - (ulSec * m_ulByteRate);
- }
- UINT32 HXSymbianAudioTimeline::GetPlaybackTime()
- {
- UINT32 ulBaseMs = GetMs(m_ulBaseSec, m_ulBaseSubSecBytes);
- UINT32 ulWrittenMs = GetWrittenTime();
- UINT32 ulRet = ulBaseMs;
- UINT32 ulDeviceTimeMs = GetWallclockTime();
-
- // Only use the device time if it
- // is less than the amount of data
- // written
- if (ulWrittenMs > ulDeviceTimeMs)
- {
- ulRet += ulDeviceTimeMs;
- }
- else
- {
- ulRet += ulWrittenMs;
- }
- // Enforce monotonically increasing return values
- if (ulRet >= m_ulLastGetTime)
- {
- m_ulLastGetTime = ulRet;
- }
- else
- {
- ulRet = m_ulLastGetTime;
- }
- return ulRet;
- }
- UINT32 HXSymbianAudioTimeline::GetWrittenTime() const
- {
- return GetMs(m_ulSecWritten, m_ulSubSecBytes);
- }
- UINT32 HXSymbianAudioTimeline::GetWallclockTime() const
- {
- UINT32 ulRet = m_ulDevTimeMs;
- if (m_ulDevTimeMs)
- {
- ulRet += HX_GET_TICKCOUNT() - m_ulWallclockTime;
- }
- return ulRet;
- }
- void HXSymbianAudioTimeline::OnPlay()
- {
- ClearWritten();
- }
- void HXSymbianAudioTimeline::OnPauseOrUnderflow()
- {
- // Add the written time to the base time
- m_ulBaseSec += m_ulSecWritten;
- m_ulBaseSubSecBytes += m_ulSubSecBytes;
- // Normalize the base time values
- while (m_ulBaseSubSecBytes >= m_ulByteRate)
- {
- m_ulBaseSec++;
- m_ulBaseSubSecBytes -= m_ulByteRate;
- }
-
- // Clear the bytes written state
- ClearWritten();
- }
- BOOL HXSymbianAudioTimeline::NeedDeviceTime() const
- {
- // We only want a device time if we don't haven't
- // received a non-zero device time.
- return (m_ulDevTimeMs == 0);
- }
- void HXSymbianAudioTimeline::SetDeviceTime(UINT32 ulDeviceTimeMs)
- {
- if (NeedDeviceTime())
- {
- m_ulDevTimeMs = ulDeviceTimeMs;
- m_ulWallclockTime = HX_GET_TICKCOUNT();
- }
- }
- UINT32 HXSymbianAudioTimeline::GetMs(UINT32 ulSec, UINT32 ulSubSec) const
- {
- UINT32 ulRet = ulSec * 1000;
- if (m_ulByteRate)
- {
- ulRet += (ulSubSec * 1000) / m_ulByteRate;
- }
- return ulRet;
- }
- void HXSymbianAudioTimeline::ClearWritten()
- {
- m_ulSecWritten = 0;
- m_ulSubSecBytes = 0;
- m_ulDevTimeMs = 0;
- m_ulWallclockTime = 0;
- }
- //
- // class HXSymbianAudioSession:
- //
- //
- // HXSymbianAudioSession::ctor:
- //
- // add the session to the server
- //
- HXSymbianAudioSession::HXSymbianAudioSession(RThread& client,
- HXSymbianAudioServer* pServer)
- : CSession(client),
- m_pServer(pServer),
- m_pStream(0),
- m_sampleRate(TMdaAudioDataSettings::ESampleRate8000Hz),
- m_channels(TMdaAudioDataSettings::EChannelsMono),
- m_pData(0, 0),
- m_wantsNotify(false),
- m_reason(KErrNone),
- m_open(false),
- m_writeComplete(true),
- m_bPaused(TRUE),
- m_bWritePending(FALSE)
- {
- // add the session to the server
- m_pServer->AddSession();
- }
- //
- // HXSymbianAudioSession::dtor
- //
- HXSymbianAudioSession::~HXSymbianAudioSession()
- {
- DoCleanup();
- }
- //
- // HXSymbianAudioSession::NewL
- //
- // creates a new session
- //
- HXSymbianAudioSession* HXSymbianAudioSession::NewL(RThread& client,
- HXSymbianAudioServer* pServer)
- {
- HXSymbianAudioSession* pSession =
- new (ELeave) HXSymbianAudioSession(client, pServer);
- return pSession;
- }
- //
- // HXSymbianAudioSession::ServiceL
- //
- // services a client message
- //
- void HXSymbianAudioSession::ServiceL(const RMessage& mesg)
- {
- switch (mesg.Function())
- {
- case HXSymbianAudioServer::EAS_Init:
- Init();
- break;
- case HXSymbianAudioServer::EAS_Play:
- Play();
- break;
- case HXSymbianAudioServer::EAS_Pause:
- Pause();
- break;
- case HXSymbianAudioServer::EAS_Write:
- Write();
- break;
- case HXSymbianAudioServer::EAS_CancelWrite:
- if (!m_writeComplete)
- {
- m_writeComplete = true;
- m_writeMessage.Complete(KErrCancel);
- }
- mesg.Complete(KErrNone);
- break;
- case HXSymbianAudioServer::EAS_GetTime:
- GetTime();
- break;
- case HXSymbianAudioServer::EAS_GetBlocksBuffered:
- GetBlocksBuffered();
- break;
- case HXSymbianAudioServer::EAS_SetVolume:
- SetVolume();
- break;
- case HXSymbianAudioServer::EAS_GetVolume:
- GetVolume();
- break;
- case HXSymbianAudioServer::EAS_GetMaxVolume:
- GetMaxVolume();
- break;
- case HXSymbianAudioServer::EAS_GetMinVolume:
- GetMinVolume();
- break;
- case HXSymbianAudioServer::EAS_Stop:
- Stop();
- break;
- case HXSymbianAudioServer::EAS_RequestDeviceTakenNotification:
- RequestDeviceTakenNotification();
- break;
- case HXSymbianAudioServer::EAS_CancelDeviceTakenNotification:
- CancelDeviceTakenNotification();
- break;
- default:
- mesg.Complete(KErrNotSupported);
- break;
- }
- }
- //
- // HXSymbianAudioSession::Init
- //
- // 1. Matches input sample rate to output sample rate
- // by building a sample rate converter, if necessary.
- // 2. Opens and initializes the audio device.
- //
- void HXSymbianAudioSession::Init()
- {
- TInt err = KErrNone;
- // translate the audio props to flags needed by interface
- m_sampleRate = NumberToFlag(Message().Int0());
- m_channels = NumberToFlag(Message().Int1());
- m_timeline.Reset(GetByteRate());
- m_bPaused = TRUE;
- if (m_open)
- {
- TRAP(err, m_pStream->SetAudioPropertiesL(m_sampleRate,
- m_channels));
- Message().Complete(err);
- }
- else
- {
- TRAP(err, (m_pStream = CMdaAudioOutputStream::NewL(*this)));
- if(KErrNone == err)
- {
- // open the audio device
- m_settings.iSampleRate = m_sampleRate;
- m_settings.iChannels = m_channels;
- m_settings.iVolume = m_pStream->MaxVolume()/2;
- m_settings.iFlags = 0;
- m_pStream->Open(&m_settings);
- }
- else
- {
- Message().Complete(err);
- }
- }
- }
- void HXSymbianAudioSession::DoCleanup()
- {
- while(!m_bufferList.IsEmpty())
- {
- IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
- HX_RELEASE(pBuf);
- }
- if (m_wantsNotify)
- {
- m_notifyRequest.Complete(KErrCancel);
- m_wantsNotify = false;
- }
- if (m_pStream)
- {
- m_pStream->Stop();
- delete m_pStream;
- m_pStream = 0;
- m_open = false;
- }
- // remove session from server
- if( m_pServer)
- {
- m_pServer->DelSession();
- m_pServer = 0;
- }
- }
- //
- // HXSymbianAudioSession::Play
- //
- void HXSymbianAudioSession::Play()
- {
- if (m_reason != KErrNone)
- m_reason = KErrNone;
- // reset audio properties in case they changed on us
- TRAPD(error, m_pStream->SetAudioPropertiesL(m_sampleRate,
- m_channels));
- m_pStream->SetPriority(KClientPriority, KPriorityPref);
- m_timeline.OnPlay();
- m_bPaused = FALSE;
- if (ReadyToWrite())
- {
- error = WriteNextBuffer();
- }
- Message().Complete(error);
- }
- //
- // HXSymbianAudioSession::Pause
- //
- void HXSymbianAudioSession::Pause()
- {
- m_timeline.OnPauseOrUnderflow();
- m_bPaused = TRUE;
- if (m_pStream)
- {
- m_pStream->Stop();
- }
- Message().Complete(KErrNone);
- }
- //
- // HXSymbianAudioSession::Write
- //
- //
- void HXSymbianAudioSession::Write()
- {
- TInt result = KErrArgument;
- IHXBuffer* pAudioBuf = (IHXBuffer*)Message().Ptr0();
- if (pAudioBuf)
- {
- if (m_bufferList.AddTail(pAudioBuf))
- {
- pAudioBuf->AddRef();
- if (ReadyToWrite())
- {
- result = WriteNextBuffer();
- if (KErrNone != result)
- {
- // Remove the buffer we just appended
- // to the list
- m_bufferList.RemoveTail();
- // Release our reference to the buffer
- HX_RELEASE(pAudioBuf);
- }
- }
- else
- {
- result = KErrNone;
- }
- }
- else
- {
- result = KErrNoMemory;
- }
-
- }
- if( m_bufferList.GetCount() < WriteBufferDepth ||
- KErrNone != result )
- {
- //We have slots free and no errors so we can complete the
- //message.
- m_writeComplete = true;
- Message().Complete(result);
- }
- else
- {
- // We need to delay notifying the caller until the current
- // write completes
- m_writeComplete = false;
- m_writeMessage = Message();
- }
-
- }
- //
- // HXSymbianAudioSession::GetTime
- //
- // Return the current playback position -- converts from
- // microseconds to milliseconds
- //
- void HXSymbianAudioSession::GetTime()
- {
- Message().Complete(m_timeline.GetPlaybackTime());
- }
- //
- // HXSymbianAudioSession::GetBlocksBuffered
- //
- // Return the number of blocks buffered by this object.
- //
- void HXSymbianAudioSession::GetBlocksBuffered()
- {
- Message().Complete(m_bufferList.GetCount());
- }
- //
- // HXSymbianAudioSession::SetVolume
- //
- // set the volume -- convert from 0-100 to 0-max range
- //
- void HXSymbianAudioSession::SetVolume()
- {
- if (m_pStream)
- {
- m_pStream->SetVolume(Message().Int0());
- }
- Message().Complete(0);
- }
- //
- // HXSymbianAudioSession::GetVolume
- //
- // get the current volume normalized to 0-100 range
- //
- void HXSymbianAudioSession::GetVolume()
- {
- TInt vol = 0;
- if (m_pStream)
- {
- vol = m_pStream->Volume();
- }
- Message().Complete(vol);
- }
- //
- // HXSymbianAudioSession::GetMaxVolume
- //
- // get the maxium device volume
- //
- void HXSymbianAudioSession::GetMaxVolume()
- {
- TInt maxVol = 0;
- if (m_pStream)
- {
- maxVol = m_pStream->MaxVolume();
- }
- Message().Complete(maxVol);
- }
- //
- // HXSymbianAudioSession::GetMinVolume
- //
- // get the minimum device volume
- //
- void HXSymbianAudioSession::GetMinVolume()
- {
- Message().Complete(0);
- }
- //
- // HXSymbianAudioSession::Stop
- //
- // stop playback
- //
- void HXSymbianAudioSession::Stop()
- {
- m_bPaused = TRUE;
- if(m_pStream)
- {
- m_pStream->Stop();
- }
-
- // Cleanup any remaining buffers
- while(!m_bufferList.IsEmpty())
- {
- IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
- HX_RELEASE(pBuf);
- }
- m_timeline.Reset(GetByteRate());
- Message().Complete(KErrNone);
- }
- void
- HXSymbianAudioSession::RequestDeviceTakenNotification()
- {
- m_wantsNotify = true;
- m_notifyRequest = Message();
- }
- void
- HXSymbianAudioSession::CancelDeviceTakenNotification()
- {
- if (m_wantsNotify)
- {
- m_notifyRequest.Complete(KErrCancel);
- m_wantsNotify = false;
- }
- }
- //
- // HXSymbianAudioSession::NotifyDeviceTaken
- //
- // notify the client that the audio device has been taken if a
- // notification requrest has been made
- //
- void HXSymbianAudioSession::NotifyDeviceTaken()
- {
- if (m_wantsNotify)
- {
- m_notifyRequest.Complete(m_reason);
- m_wantsNotify = false;
- }
- }
- //
- // callbacks
- //
- void HXSymbianAudioSession::MaoscOpenComplete(TInt error)
- {
- if (error == KErrNone)
- {
- m_open = true;
- TRAP(error, m_pStream->SetAudioPropertiesL(m_sampleRate,
- m_channels));
- m_pStream->SetPriority(KClientPriority, KPriorityPref);
- }
- Message().Complete(error);
- }
- void HXSymbianAudioSession::MaoscBufferCopied(TInt error, const TDesC8& buf)
- {
- m_bWritePending = FALSE;
- // Check to see if we need a device time
- if (m_timeline.NeedDeviceTime())
- {
- m_timeline.SetDeviceTime(GetDeviceMs());
- }
- if (!m_bufferList.IsEmpty())
- {
- // We should always enter here because the
- // last buffer written is at the head of the list.
- // We want to remove this buffer from the list since
- // this call is the completion of last WriteL() call.
- IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
- HX_RELEASE(pBuf);
- }
- if (ReadyToWrite())
- {
- error = WriteNextBuffer();
- }
- if( !m_writeComplete &&
- (m_bufferList.GetCount() < WriteBufferDepth))
- {
- m_writeComplete = true;
- m_writeMessage.Complete(error);
- }
-
- }
- void HXSymbianAudioSession::MaoscPlayComplete(TInt error)
- {
- if (KErrUnderflow == error)
- {
- m_timeline.OnPauseOrUnderflow();
- }
- //If the media server is stopping for any reason make sure we
- //honor any outstanding completes.
- if( !m_writeComplete )
- {
- m_writeComplete = true;
- m_writeMessage.Complete(error);
- }
- int resetErr;
- TRAP(resetErr, m_pStream->SetAudioPropertiesL(m_sampleRate,
- m_channels));
- m_pStream->SetPriority(KClientPriority, KPriorityPref);
- if (error == KErrAbort)
- {
- m_reason = error;
- m_pServer->NotifyDeviceTaken();
- }
- }
- UINT32 HXSymbianAudioSession::GetByteRate() const
- {
- return 2 * FlagToNumber(m_sampleRate) * FlagToNumber(m_channels);
- }
- UINT32 HXSymbianAudioSession::GetDeviceMs()
- {
- UINT32 ulRet = 0;
- if (m_pStream)
- {
- TTimeIntervalMicroSeconds pos = m_pStream->Position();
- TInt64 millisecs = pos.Int64() / 1000;
-
- ulRet = millisecs.Low();
- }
- return ulRet;
- }
- BOOL HXSymbianAudioSession::ReadyToWrite() const
- {
- return !m_bWritePending && !m_bPaused && !m_bufferList.IsEmpty();
- }
- TInt HXSymbianAudioSession::WriteNextBuffer()
- {
- // Write the next buffer in the list
- IHXBuffer* pBuffer = (IHXBuffer*)m_bufferList.GetHead();
- TInt result = KErrNone;
- if (pBuffer)
- {
- if( m_pStream )
- {
- int len = pBuffer->GetSize();
- m_pData.Set((TUint8*)pBuffer->GetBuffer(), len, len);
- TRAP(result, m_pStream->WriteL(m_pData));
- }
- else
- {
- // oom earlier?
- result = KErrNotReady;
- }
- }
- if (KErrNone == result)
- {
- m_timeline.OnWrite(pBuffer->GetSize());
- m_bWritePending = TRUE;
- }
- else
- {
- m_bWritePending = FALSE;
- }
- return result;
- }