audio_session-mmf.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:16k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: audio_session-mmf.cpp,v 1.1.2.2 2004/07/09 02:01:33 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #if defined (HELIX_CONFIG_CALYPSO_AUDIO_PREF)
  50. #include <calypso/audiopreference.h>
  51. #endif
  52. #include "hxcom.h"
  53. #include "hxslist.h"
  54. #include "hxausvc.h"
  55. #include "hxbuffer.h"
  56. #include "audio_session-mmf.h"
  57. #include "hxtick.h"
  58. #include <e32std.h>
  59. static const TInt KClientPriority = 69;
  60. #if defined(HELIX_CONFIG_CALYPSO_AUDIO_PREF)
  61. static const TMdaPriorityPreference KPriorityPref = (TMdaPriorityPreference)KAudioPrefComposer; 
  62. #else
  63. static const TMdaPriorityPreference KPriorityPref = (TMdaPriorityPreference)80; //EMdaPriorityPreferenceTime;
  64. #endif // SERIES60_PLAYER
  65. const INT32 WriteBufferDepth = 10; // Number of buffers we allow in the queue before blocking the caller
  66. static TInt FlagToNumber(TMMFSampleRate flag)
  67. {
  68.     switch( flag )
  69.     {
  70.     case EMMFSampleRate8000Hz:
  71.         return 8000;
  72.     case EMMFSampleRate11025Hz:
  73.         return 11025;
  74.     case EMMFSampleRate16000Hz:
  75.         return 16000;
  76.     case EMMFSampleRate22050Hz:
  77.         return 22050;
  78.     case EMMFSampleRate32000Hz:
  79.         return 32000;
  80.     case EMMFSampleRate44100Hz:
  81.         return 44100;
  82.     case EMMFSampleRate48000Hz:
  83.         return 48000;
  84.     default:
  85.         return 0;
  86.         break;
  87.     }
  88.     return 0;
  89. }
  90. static TMMFSampleRate NumberToFlag(TInt num)
  91. {
  92.     switch(num)
  93.     {
  94.     case 8000:
  95.         return  EMMFSampleRate8000Hz;
  96.     case 11025:
  97.         return  EMMFSampleRate11025Hz;
  98.     case 16000:
  99.         return  EMMFSampleRate16000Hz;
  100.     case 22050:
  101.         return  EMMFSampleRate22050Hz;
  102.     case 32000:
  103.         return  EMMFSampleRate32000Hz;
  104.     case 44100:
  105.         return  EMMFSampleRate44100Hz;
  106.     case 48000:
  107.         return  EMMFSampleRate48000Hz;
  108.     default:
  109.         HX_ASSERT(NULL=="Invalid sample rate flag");
  110.         break;
  111.     }
  112.     return EMMFSampleRate16000Hz;
  113. }
  114. HXSymbianAudioSession::HXSymbianAudioSession(RThread& client,
  115.                                              HXSymbianAudioServer* pServer)
  116.     : CSession(client),
  117.       m_pServer(pServer),
  118.       m_wantsNotify(false),
  119.       m_reason(KErrNone),
  120.       m_open(false),
  121.       m_bPaused(FALSE),
  122.       m_pStream(NULL),
  123.       m_pData(NULL),
  124.       m_bBufferNeedsFilling(false),
  125.       m_bPlayInited(FALSE),
  126.       m_uSampleRate(0),
  127.       m_ulPauseTime(0),
  128.       m_ulStartTime(0),
  129.       m_nLastSampleCount(0),
  130.       m_nUnderflowSampleCount(0)
  131. {
  132.     // add the session to the server
  133.     m_pServer->AddSession();
  134.     memset(&m_Settings, 0, sizeof( m_Settings) );
  135. }
  136. //
  137. // HXSymbianAudioSession::dtor
  138. //
  139. HXSymbianAudioSession::~HXSymbianAudioSession()
  140. {
  141.     DoCleanup();
  142. }
  143. //
  144. // HXSymbianAudioSession::NewL
  145. //
  146. // creates a new session
  147. //
  148. HXSymbianAudioSession* HXSymbianAudioSession::NewL(RThread& client,
  149.                                                    HXSymbianAudioServer* pServer)
  150. {
  151.     HXSymbianAudioSession* pSession =
  152.         new (ELeave) HXSymbianAudioSession(client, pServer);
  153.     
  154.     return pSession;
  155. }
  156. //
  157. // HXSymbianAudioSession::ServiceL
  158. //
  159. // services a client message
  160. //
  161. void HXSymbianAudioSession::ServiceL(const RMessage& mesg)
  162. {
  163.     switch (mesg.Function()) 
  164.     {
  165.     case HXSymbianAudioServer::EAS_Init:
  166.         Init();
  167.         break;
  168.     case HXSymbianAudioServer::EAS_Play:
  169.         Play();
  170.         break;
  171.     case HXSymbianAudioServer::EAS_Pause:
  172.         Pause();
  173.         break;
  174.     case HXSymbianAudioServer::EAS_Write:
  175.         Write();
  176.         break;
  177.     case HXSymbianAudioServer::EAS_CancelWrite:
  178.         mesg.Complete(KErrNone);
  179.         break;
  180.     case HXSymbianAudioServer::EAS_GetTime:
  181.         GetTime();
  182.         break;
  183.     case HXSymbianAudioServer::EAS_GetBlocksBuffered:
  184.         GetBlocksBuffered();
  185.         break;
  186.     case HXSymbianAudioServer::EAS_SetVolume:
  187.         SetVolume();
  188.         break;
  189.     case HXSymbianAudioServer::EAS_GetVolume:
  190.         GetVolume();
  191.         break;
  192.     case HXSymbianAudioServer::EAS_GetMaxVolume:
  193.         GetMaxVolume();
  194.         break;
  195.     case HXSymbianAudioServer::EAS_GetMinVolume:
  196.         GetMinVolume();
  197.         break;
  198.     case HXSymbianAudioServer::EAS_Stop:
  199.         Stop();
  200.         break;
  201.     case HXSymbianAudioServer::EAS_RequestDeviceTakenNotification:
  202.         RequestDeviceTakenNotification();
  203.         break;
  204.     case HXSymbianAudioServer::EAS_CancelDeviceTakenNotification:
  205.         CancelDeviceTakenNotification();
  206.         break;
  207.     default:
  208.         mesg.Complete(KErrNotSupported);
  209.         break;
  210.     }
  211. }
  212. //
  213. // HXSymbianAudioSession::Init
  214. //
  215. // 1. Matches input sample rate to output sample rate
  216. //    by building a sample rate converter, if necessary.
  217. // 2. Opens and initializes the audio device.
  218. //
  219. void HXSymbianAudioSession::Init()
  220. {
  221.     TInt err = KErrNone;
  222.     // translate the audio props to flags needed by interface
  223.     m_Settings.iRate     = NumberToFlag(Message().Int0());
  224.     m_Settings.iChannels = Message().Int1();
  225.     m_Settings.iEncoding = EMMFSoundEncoding16BitPCM; //We always do 16bit.
  226.     m_uSampleRate        = Message().Int0();
  227.     
  228.     if (m_open)
  229.     {
  230.         TRAP(err, (m_pStream->CMMFDevSound::SetConfigL(m_Settings)));
  231.         Message().Complete(err);
  232.     }
  233.     else 
  234.     {
  235.         TRAP(err, (m_pStream = CMMFDevSound::NewL()));
  236.         if(KErrNone == err)
  237.         {
  238.             m_InitMessage = Message();
  239.             TRAP(err, (m_pStream->InitializeL(*this, EMMFStatePlaying)));
  240.         }
  241.         if( KErrNone != err )
  242.         {
  243.             Message().Complete(err);
  244.         }
  245.     }
  246.     m_bPlayInited = FALSE;
  247. }
  248. void HXSymbianAudioSession::DoCleanup()
  249. {
  250.     while(!m_bufferList.IsEmpty())
  251.     {
  252.         IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
  253.         HX_RELEASE(pBuf);
  254.     }
  255.     if (m_wantsNotify)
  256.     {
  257.         m_notifyRequest.Complete(KErrCancel);
  258.         m_wantsNotify = false;
  259.     }
  260.     if (m_pStream)
  261.     {
  262.         m_pStream->Stop();
  263.         delete m_pStream;
  264.         m_pStream = 0;
  265.         m_open = false;
  266.         m_pData= NULL;
  267.     }
  268.     // remove session from server
  269.     if( m_pServer)
  270.     {
  271.         m_pServer->DelSession();
  272.         m_pServer = 0;
  273.     }
  274. }
  275. //
  276. // HXSymbianAudioSession::Play
  277. //
  278. void HXSymbianAudioSession::Play()
  279. {
  280.     TInt err = KErrNone;
  281.     m_reason = KErrNone;
  282.     m_ulStartTime = HX_GET_TICKCOUNT();
  283.     if( m_pData )
  284.     {
  285.         m_pStream->PlayData();
  286.     }
  287.     if(!m_bPlayInited)
  288.     {
  289.         //Set priority.
  290.         TMMFPrioritySettings prioritySettings;
  291.         prioritySettings.iPref     = KPriorityPref;
  292.         prioritySettings.iPriority = KClientPriority;
  293.         
  294.         m_pStream->SetPrioritySettings(prioritySettings);
  295.         TRAP(err, m_pStream->PlayInitL());
  296.         m_bPlayInited = TRUE;
  297.     }
  298.     m_bPaused = FALSE;
  299.     Message().Complete(err);
  300. }
  301. //
  302. // HXSymbianAudioSession::Pause
  303. //
  304. void HXSymbianAudioSession::Pause()
  305. {
  306.     m_bPaused = TRUE;
  307.     if( m_ulStartTime )
  308.         m_ulPauseTime += HX_GET_TICKCOUNT()-m_ulStartTime;
  309.     m_ulStartTime = 0;
  310.     //Only pause the stream if we have actually started to play.
  311.     if (m_pStream && m_pData)
  312.     {
  313.         m_pStream->Pause();
  314.     }
  315.     Message().Complete(KErrNone);
  316. }
  317. //
  318. // HXSymbianAudioSession::Write
  319. //
  320. //
  321. void HXSymbianAudioSession::Write()
  322. {
  323.     TInt result = KErrArgument;
  324.     TInt err = KErrNone;
  325.     IHXBuffer* pAudioBuf = (IHXBuffer*)Message().Ptr0();
  326.     if (pAudioBuf)
  327.     {
  328.         if (m_bufferList.AddTail(pAudioBuf))
  329.         {
  330.             result = KErrNone;
  331.         }
  332.         else
  333.         {
  334.             result = KErrNoMemory;
  335.         }
  336.     }
  337.     Message().Complete(result);
  338.     
  339.     if( m_bBufferNeedsFilling && m_pData )
  340.     {
  341.         BufferToBeFilled(m_pData);
  342.         m_bBufferNeedsFilling = false;
  343.     }
  344. }
  345. //
  346. // HXSymbianAudioSession::GetTime
  347. //
  348. // Return the current playback position -- converts from
  349. // microseconds to milliseconds
  350. //
  351. void HXSymbianAudioSession::GetTime()
  352. {
  353.     TInt nMSTime = 0;
  354.     TInt nSamples = m_pStream->SamplesPlayed();
  355.     
  356.     nMSTime = (nSamples+m_nUnderflowSampleCount)*1000/m_uSampleRate;
  357. //     if(m_ulStartTime)
  358. //         nMSTime = HX_GET_TICKCOUNT()-m_ulStartTime;
  359.     
  360. //     nMSTime += m_ulPauseTime;
  361.     Message().Complete(nMSTime);
  362. }
  363. //
  364. // HXSymbianAudioSession::GetBlocksBuffered
  365. //
  366. // Return the number of blocks buffered by this object.
  367. //
  368. void HXSymbianAudioSession::GetBlocksBuffered()
  369. {
  370.     TInt nTmp = m_bufferList.GetCount();
  371.     Message().Complete(nTmp);
  372. }
  373. //
  374. // HXSymbianAudioSession::SetVolume
  375. //
  376. // set the volume -- convert from 0-100 to 0-max range
  377. //
  378. void HXSymbianAudioSession::SetVolume()
  379. {
  380.     if (m_pStream)
  381.     {
  382.         m_pStream->SetVolume(Message().Int0());
  383.     }
  384.     Message().Complete(0);
  385. }
  386. //
  387. // HXSymbianAudioSession::GetVolume
  388. //
  389. // get the current volume normalized to 0-100 range
  390. //
  391. void HXSymbianAudioSession::GetVolume()
  392. {
  393.     TInt vol = 0;
  394.     if (m_pStream)
  395.     {
  396.         vol = m_pStream->Volume();
  397.     }
  398.     Message().Complete(vol);
  399. }
  400. //
  401. // HXSymbianAudioSession::GetMaxVolume
  402. //
  403. // get the maxium device volume
  404. //
  405. void HXSymbianAudioSession::GetMaxVolume()
  406. {
  407.     TInt maxVol = 0;
  408.     if (m_pStream)
  409.     {
  410.         maxVol = m_pStream->MaxVolume();
  411.     }
  412.     Message().Complete(maxVol);
  413. }
  414. //
  415. // HXSymbianAudioSession::GetMinVolume
  416. //
  417. // get the minimum device volume
  418. //
  419. void HXSymbianAudioSession::GetMinVolume()
  420. {
  421.     Message().Complete(0);
  422. }
  423. //
  424. // HXSymbianAudioSession::Stop
  425. //
  426. // stop playback
  427. //
  428. void HXSymbianAudioSession::Stop()
  429. {
  430.     m_bPlayInited           = FALSE;
  431.     m_ulStartTime           = 0;
  432.     m_ulPauseTime           = 0;
  433.     m_nUnderflowSampleCount = 0;
  434.     m_nLastSampleCount      = 0;
  435.     if(m_pStream)
  436.     {
  437.         m_pStream->Stop();
  438.         m_pData = NULL;
  439.     }
  440.     
  441.     // Cleanup any remaining buffers
  442.     while(!m_bufferList.IsEmpty())
  443.     {
  444.         IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
  445.         HX_RELEASE(pBuf);
  446.     }
  447.     Message().Complete(KErrNone);
  448. }
  449. void
  450. HXSymbianAudioSession::RequestDeviceTakenNotification()
  451. {
  452.     m_wantsNotify = true;
  453.     m_notifyRequest = Message();
  454. }
  455. void
  456. HXSymbianAudioSession::CancelDeviceTakenNotification()
  457. {
  458.     if (m_wantsNotify)
  459.     {
  460.         m_notifyRequest.Complete(KErrCancel);
  461.         m_wantsNotify = false;
  462.     }
  463. }
  464. //
  465. // HXSymbianAudioSession::NotifyDeviceTaken
  466. //
  467. // notify the client that the audio device has been taken if a
  468. // notification requrest has been made 
  469. //
  470. void HXSymbianAudioSession::NotifyDeviceTaken()
  471. {
  472.     if (m_wantsNotify)
  473.     {
  474.         m_notifyRequest.Complete(m_reason);
  475.         m_wantsNotify = false;
  476.     }
  477. }
  478. //
  479. // callbacks
  480. //
  481. //MDevSoundObserver callbacks
  482. void HXSymbianAudioSession::InitializeComplete(TInt aError)
  483. {
  484.     TInt err = KErrNone;
  485.     TRAP(err, (m_pStream->CMMFDevSound::SetConfigL(m_Settings)));
  486.     
  487.     if( KErrNone == err )
  488.     {
  489.         m_open = true;
  490.     }
  491.     m_InitMessage.Complete(err);
  492. }
  493. void HXSymbianAudioSession::BufferToBeFilled(CMMFBuffer* aBuffer)
  494. {
  495.     TInt err = KErrUnderflow;
  496.     m_pData = aBuffer;
  497.     m_nLastSampleCount = m_pStream->SamplesPlayed();
  498.     if( aBuffer )
  499.     {
  500.         //Called whenever the media server needs more data to play.
  501.         if( !m_bufferList.IsEmpty())
  502.         {
  503.             TDes8&  dataDesc  = ((CMMFDataBuffer*)aBuffer)->Data();
  504.             int nRequestSize  = aBuffer->RequestSize();
  505.             int nTotalWritten = 0;
  506.             //Clear out the descriptor.
  507.             dataDesc = TPtrC8(NULL, 0 );
  508.             while( !m_bufferList.IsEmpty() )
  509.             {
  510.                 //Fill up as much as we can.
  511.                 IHXBuffer* pBuffer = (IHXBuffer*)m_bufferList.GetHead();
  512.                 int len = pBuffer->GetSize();
  513.                 if( nTotalWritten+len < nRequestSize )
  514.                 {
  515.                     TPtrC8 desc((TUint8*)pBuffer->GetBuffer(), len);
  516.                     dataDesc.Append(desc);
  517.                     IHXBuffer* pTmp = (IHXBuffer*)m_bufferList.RemoveHead();
  518.                     HX_RELEASE(pTmp);
  519.                 }
  520.                 else
  521.                 {
  522.                     break;
  523.                 }
  524.                 nTotalWritten += len;
  525.                 //XXXGfw break here is intentional. I don't want to do
  526.                 //combined writes right now.
  527.                 break;
  528.             }
  529.             m_pStream->PlayData();
  530.             
  531.         }
  532.         else
  533.         {
  534.             m_bBufferNeedsFilling = true;
  535.         }
  536.     }
  537. }
  538. void HXSymbianAudioSession::PlayError(TInt aError)
  539. {
  540.     TInt err = KErrNone;
  541.     m_reason = aError;
  542.     m_pData  = NULL;
  543.     switch(aError)
  544.     {
  545.        case KErrUnderflow:
  546.            //HX_ASSERT(NULL=="Underflow.");
  547.            TMMFPrioritySettings prioritySettings;
  548.            
  549.            prioritySettings.iPref     = KPriorityPref;
  550.            prioritySettings.iPriority = KClientPriority;
  551.            
  552.            m_pStream->SetPrioritySettings(prioritySettings);
  553.            TRAP(err, m_pStream->PlayInitL());
  554.            m_bPlayInited = TRUE;
  555.            m_nUnderflowSampleCount += m_nLastSampleCount;
  556.            break;
  557.        case KErrAccessDenied: 
  558.            NotifyDeviceTaken();
  559.            break;
  560.        case KErrCancel:
  561.            HX_ASSERT(NULL=="PlayError -- KErrCancel");
  562.            break;
  563.        case KErrInUse:
  564.            NotifyDeviceTaken();
  565.            break;
  566.        default:
  567.            HX_ASSERT(NULL=="unknown error");
  568.            break;
  569.     }
  570. }
  571. //These are never used in PCM playback, just recording or converting.
  572. void HXSymbianAudioSession::ToneFinished(TInt aError) {}
  573. void HXSymbianAudioSession::RecordError(TInt aError)  {}
  574. void HXSymbianAudioSession::ConvertError(TInt aError) {}
  575. void HXSymbianAudioSession::BufferToBeEmptied(CMMFBuffer* aBuffer) {}
  576. void HXSymbianAudioSession::DeviceMessage(TUid aMessageType, const TDesC8& aMsg) {}
  577. void HXSymbianAudioSession::SendEventToClient(const TMMFEvent& aEvent) {}