audio_session-mda.cpp
Upload User: dangjiwu
Upload Date: 2013-07-19
Package Size: 42019k
Code Size: 19k
Category:

Symbian

Development Platform:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: audio_session-mda.cpp,v 1.2.2.6 2004/07/09 02:01:29 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 <mda/common/audio.h>
  53. #include "hxcom.h"
  54. #include "hxslist.h"
  55. #include "hxausvc.h"
  56. #include "hxbuffer.h"
  57. #include "audio_session-mda.h"
  58. #include "hxtick.h"
  59. static const TInt KClientPriority = 69; //EMdaPriorityNormal;
  60. #if defined(HELIX_CONFIG_CALYPSO_AUDIO_PREF)
  61. static const TMdaPriorityPreference KPriorityPref = (TMdaPriorityPreference)KAudioPrefComposer; 
  62. #else
  63. static const TMdaPriorityPreference KPriorityPref = EMdaPriorityPreferenceTime;
  64. #endif // SERIES60_PLAYER
  65. const INT32 WriteBufferDepth = 10; // Number of buffers we allow in the queue before blocking the caller
  66. ////////////////////////////////////////////////////
  67. //
  68. static TInt FlagToNumber(TMdaAudioDataSettings::TAudioCaps flag)
  69. {
  70.     switch( flag )
  71.     {
  72.     case TMdaAudioDataSettings::ESampleRate8000Hz:
  73.         return 8000;
  74.     case TMdaAudioDataSettings::ESampleRate11025Hz:
  75.         return 11025;
  76.     case TMdaAudioDataSettings::ESampleRate16000Hz:
  77.         return 16000;
  78.     case TMdaAudioDataSettings::ESampleRate22050Hz:
  79.         return 22050;
  80.     case TMdaAudioDataSettings::ESampleRate32000Hz:
  81.         return 32000;
  82.     case TMdaAudioDataSettings::ESampleRate44100Hz:
  83.         return 44100;
  84.     case TMdaAudioDataSettings::ESampleRate48000Hz:
  85.         return 48000;
  86.     case TMdaAudioDataSettings::EChannelsMono:
  87.         return 1;
  88.     case TMdaAudioDataSettings::EChannelsStereo:
  89.         return 2;
  90.     default:
  91.         return 0;
  92.         break;
  93.     }
  94.     return 0;
  95. }
  96. static TMdaAudioDataSettings::TAudioCaps NumberToFlag(TInt num)
  97. {
  98.     switch(num)
  99.     {
  100.     case 1:
  101.         return  TMdaAudioDataSettings::EChannelsMono;
  102.     case 2:
  103.         return  TMdaAudioDataSettings::EChannelsStereo;
  104.     case 8000:
  105.         return  TMdaAudioDataSettings::ESampleRate8000Hz;
  106.     case 11025:
  107.         return  TMdaAudioDataSettings::ESampleRate11025Hz;
  108.     case 16000:
  109.         return  TMdaAudioDataSettings::ESampleRate16000Hz;
  110.     case 22050:
  111.         return  TMdaAudioDataSettings::ESampleRate22050Hz;
  112.     case 32000:
  113.         return  TMdaAudioDataSettings::ESampleRate32000Hz;
  114.     case 44100:
  115.         return  TMdaAudioDataSettings::ESampleRate44100Hz;
  116.     case 48000:
  117.         return  TMdaAudioDataSettings::ESampleRate48000Hz;
  118.     default:
  119.         return (TMdaAudioDataSettings::TAudioCaps)0;
  120.         break;
  121.     }
  122.     return (TMdaAudioDataSettings::TAudioCaps)0;
  123. }
  124. HXSymbianAudioTimeline::HXSymbianAudioTimeline()
  125. {
  126.     Reset(0);
  127. }
  128. HXSymbianAudioTimeline::~HXSymbianAudioTimeline()
  129. {}
  130. void HXSymbianAudioTimeline::Reset(UINT32 ulByteRate)
  131. {
  132.     m_ulByteRate = ulByteRate;
  133.     ClearWritten();
  134.     m_ulBaseSec = 0;
  135.     m_ulBaseSubSecBytes = 0;
  136.     m_ulLastGetTime = 0;
  137. }
  138. void HXSymbianAudioTimeline::OnWrite(UINT32 ulBytes)
  139. {
  140.     UINT32 ulSum = m_ulSubSecBytes + ulBytes;
  141.     UINT32 ulSec = ulSum / m_ulByteRate;
  142.     m_ulSecWritten += ulSec;
  143.     m_ulSubSecBytes = ulSum - (ulSec * m_ulByteRate);
  144. }
  145. UINT32 HXSymbianAudioTimeline::GetPlaybackTime()
  146. {
  147.     UINT32 ulBaseMs = GetMs(m_ulBaseSec, m_ulBaseSubSecBytes);
  148.     UINT32 ulWrittenMs = GetWrittenTime();
  149.     UINT32 ulRet = ulBaseMs;
  150.     UINT32 ulDeviceTimeMs = GetWallclockTime();
  151.     
  152.     // Only use the device time if it
  153.     // is less than the amount of data
  154.     // written
  155.     if (ulWrittenMs > ulDeviceTimeMs)
  156.     {
  157.         ulRet += ulDeviceTimeMs;
  158.     }
  159.     else
  160.     {
  161.         ulRet += ulWrittenMs;
  162.     }
  163.     // Enforce monotonically increasing return values
  164.     if (ulRet >= m_ulLastGetTime)
  165.     {
  166.         m_ulLastGetTime = ulRet;
  167.     }
  168.     else
  169.     {
  170.         ulRet = m_ulLastGetTime;
  171.     }
  172.     return ulRet;
  173. }
  174. UINT32 HXSymbianAudioTimeline::GetWrittenTime() const
  175. {
  176.     return GetMs(m_ulSecWritten, m_ulSubSecBytes);
  177. }
  178. UINT32 HXSymbianAudioTimeline::GetWallclockTime() const
  179. {
  180.     UINT32 ulRet = m_ulDevTimeMs;
  181.     if (m_ulDevTimeMs)
  182.     {
  183.         ulRet += HX_GET_TICKCOUNT() - m_ulWallclockTime;
  184.     }
  185.     return ulRet;
  186. }
  187. void HXSymbianAudioTimeline::OnPlay()
  188. {
  189.     ClearWritten();
  190. }
  191. void HXSymbianAudioTimeline::OnPauseOrUnderflow()
  192. {
  193.     // Add the written time to the base time
  194.     m_ulBaseSec += m_ulSecWritten;
  195.     m_ulBaseSubSecBytes += m_ulSubSecBytes;
  196.     // Normalize the base time values
  197.     while (m_ulBaseSubSecBytes >= m_ulByteRate)
  198.     {
  199.         m_ulBaseSec++;
  200.         m_ulBaseSubSecBytes -= m_ulByteRate;
  201.     }
  202.     
  203.     // Clear the bytes written state
  204.     ClearWritten();
  205. }
  206. BOOL HXSymbianAudioTimeline::NeedDeviceTime() const
  207. {
  208.     // We only want a device time if we don't haven't
  209.     // received a non-zero device time.
  210.     return (m_ulDevTimeMs == 0);
  211. }
  212. void HXSymbianAudioTimeline::SetDeviceTime(UINT32 ulDeviceTimeMs)
  213. {
  214.     if (NeedDeviceTime())
  215.     {
  216.         m_ulDevTimeMs = ulDeviceTimeMs;
  217.         m_ulWallclockTime = HX_GET_TICKCOUNT();
  218.     }
  219. }
  220. UINT32 HXSymbianAudioTimeline::GetMs(UINT32 ulSec, UINT32 ulSubSec) const
  221. {
  222.     UINT32 ulRet = ulSec * 1000;
  223.     if (m_ulByteRate)
  224.     {
  225.         ulRet += (ulSubSec * 1000) / m_ulByteRate;
  226.     }
  227.     return ulRet;
  228. }
  229. void HXSymbianAudioTimeline::ClearWritten()
  230. {
  231.     m_ulSecWritten = 0;
  232.     m_ulSubSecBytes = 0;
  233.     m_ulDevTimeMs = 0;
  234.     m_ulWallclockTime = 0;
  235. }
  236. //
  237. // class HXSymbianAudioSession:
  238. //
  239. //
  240. // HXSymbianAudioSession::ctor:
  241. //
  242. // add the session to the server
  243. //
  244. HXSymbianAudioSession::HXSymbianAudioSession(RThread& client,
  245.                                              HXSymbianAudioServer* pServer)
  246.     : CSession(client),
  247.       m_pServer(pServer),
  248.       m_pStream(0),
  249.       m_sampleRate(TMdaAudioDataSettings::ESampleRate8000Hz),
  250.       m_channels(TMdaAudioDataSettings::EChannelsMono),
  251.       m_pData(0, 0),
  252.       m_wantsNotify(false),
  253.       m_reason(KErrNone),
  254.       m_open(false),
  255.       m_bPaused(TRUE),
  256.       m_bWritePending(FALSE)
  257. {
  258.     // add the session to the server
  259.     m_pServer->AddSession();
  260. }
  261. //
  262. // HXSymbianAudioSession::dtor
  263. //
  264. HXSymbianAudioSession::~HXSymbianAudioSession()
  265. {
  266.     DoCleanup();
  267. }
  268. //
  269. // HXSymbianAudioSession::NewL
  270. //
  271. // creates a new session
  272. //
  273. HXSymbianAudioSession* HXSymbianAudioSession::NewL(RThread& client,
  274.                                                    HXSymbianAudioServer* pServer)
  275. {
  276.     HXSymbianAudioSession* pSession =
  277.         new (ELeave) HXSymbianAudioSession(client, pServer);
  278.     return pSession;
  279. }
  280. //
  281. // HXSymbianAudioSession::ServiceL
  282. //
  283. // services a client message
  284. //
  285. void HXSymbianAudioSession::ServiceL(const RMessage& mesg)
  286. {
  287.     switch (mesg.Function()) 
  288.     {
  289.     case HXSymbianAudioServer::EAS_Init:
  290.         Init();
  291.         break;
  292.     case HXSymbianAudioServer::EAS_Play:
  293.         Play();
  294.         break;
  295.     case HXSymbianAudioServer::EAS_Pause:
  296.         Pause();
  297.         break;
  298.     case HXSymbianAudioServer::EAS_Write:
  299.         Write();
  300.         break;
  301.     case HXSymbianAudioServer::EAS_CancelWrite:
  302.         mesg.Complete(KErrNone);
  303.         break;
  304.     case HXSymbianAudioServer::EAS_GetTime:
  305.         GetTime();
  306.         break;
  307.     case HXSymbianAudioServer::EAS_GetBlocksBuffered:
  308.         GetBlocksBuffered();
  309.         break;
  310.     case HXSymbianAudioServer::EAS_SetVolume:
  311.         SetVolume();
  312.         break;
  313.     case HXSymbianAudioServer::EAS_GetVolume:
  314.         GetVolume();
  315.         break;
  316.     case HXSymbianAudioServer::EAS_GetMaxVolume:
  317.         GetMaxVolume();
  318.         break;
  319.     case HXSymbianAudioServer::EAS_GetMinVolume:
  320.         GetMinVolume();
  321.         break;
  322.     case HXSymbianAudioServer::EAS_Stop:
  323.         Stop();
  324.         break;
  325.     case HXSymbianAudioServer::EAS_RequestDeviceTakenNotification:
  326.         RequestDeviceTakenNotification();
  327.         break;
  328.     case HXSymbianAudioServer::EAS_CancelDeviceTakenNotification:
  329.         CancelDeviceTakenNotification();
  330.         break;
  331.     default:
  332.         mesg.Complete(KErrNotSupported);
  333.         break;
  334.     }
  335. }
  336. //
  337. // HXSymbianAudioSession::Init
  338. //
  339. // 1. Matches input sample rate to output sample rate
  340. //    by building a sample rate converter, if necessary.
  341. // 2. Opens and initializes the audio device.
  342. //
  343. void HXSymbianAudioSession::Init()
  344. {
  345.     TInt err = KErrNone;
  346.     // translate the audio props to flags needed by interface
  347.     m_sampleRate = NumberToFlag(Message().Int0());
  348.     m_channels   = NumberToFlag(Message().Int1());
  349.     m_timeline.Reset(GetByteRate());
  350.     m_bPaused = TRUE;
  351.     if (m_open)
  352.     {
  353.         TRAP(err, m_pStream->SetAudioPropertiesL(m_sampleRate,
  354.                                                  m_channels));
  355.         Message().Complete(err);
  356.     }
  357.     else 
  358.     {
  359.         TRAP(err, (m_pStream = CMdaAudioOutputStream::NewL(*this)));
  360.         if(KErrNone == err)
  361.         {
  362.             // open the audio device
  363.             m_settings.iSampleRate = m_sampleRate;
  364.             m_settings.iChannels = m_channels;
  365.             m_settings.iVolume = m_pStream->MaxVolume()/2;
  366.             m_settings.iFlags = 0;
  367.             m_pStream->Open(&m_settings);
  368.         }
  369.         else
  370.         {
  371.             Message().Complete(err);
  372.         }
  373.     }
  374. }
  375. void HXSymbianAudioSession::DoCleanup()
  376. {
  377.     while(!m_bufferList.IsEmpty())
  378.     {
  379.         IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
  380.         HX_RELEASE(pBuf);
  381.     }
  382.     if (m_wantsNotify)
  383.     {
  384.         m_notifyRequest.Complete(KErrCancel);
  385.         m_wantsNotify = false;
  386.     }
  387.     if (m_pStream)
  388.     {
  389.         m_pStream->Stop();
  390.         delete m_pStream;
  391.         m_pStream = 0;
  392.         m_open = false;
  393.     }
  394.     // remove session from server
  395.     if( m_pServer)
  396.     {
  397.         m_pServer->DelSession();
  398.         m_pServer = 0;
  399.     }
  400. }
  401. //
  402. // HXSymbianAudioSession::Play
  403. //
  404. void HXSymbianAudioSession::Play()
  405. {
  406.     if (m_reason != KErrNone)
  407.         m_reason = KErrNone;
  408.     // reset audio properties in case they changed on us
  409.     TRAPD(error, m_pStream->SetAudioPropertiesL(m_sampleRate,
  410.                                                 m_channels));
  411.     m_pStream->SetPriority(KClientPriority, KPriorityPref);
  412.     m_timeline.OnPlay();
  413.     m_bPaused = FALSE;
  414.     if (ReadyToWrite())
  415.     {
  416.         error = WriteNextBuffer();
  417.     }
  418.     Message().Complete(error);
  419. }
  420. //
  421. // HXSymbianAudioSession::Pause
  422. //
  423. void HXSymbianAudioSession::Pause()
  424. {
  425.     m_timeline.OnPauseOrUnderflow();
  426.     m_bPaused = TRUE;
  427.     if (m_pStream)
  428.     {
  429.         m_pStream->Stop();
  430.     }
  431.     Message().Complete(KErrNone);
  432. }
  433. //
  434. // HXSymbianAudioSession::Write
  435. //
  436. //
  437. void HXSymbianAudioSession::Write()
  438. {
  439.     TInt result = KErrArgument;
  440.     IHXBuffer* pAudioBuf = (IHXBuffer*)Message().Ptr0();
  441.     if (pAudioBuf)
  442.     {
  443.         if (m_bufferList.AddTail(pAudioBuf))
  444.         {
  445.             if (ReadyToWrite())
  446.             {
  447.                 result = WriteNextBuffer();
  448.                 if (KErrNone != result)
  449.                 {
  450.                     // Remove the buffer we just appended
  451.                     // to the list
  452.                     m_bufferList.RemoveTail();
  453.                     // Release our reference to the buffer
  454.                     HX_RELEASE(pAudioBuf);
  455.                 }
  456.             }
  457.             else
  458.             {
  459.                 result = KErrNone;
  460.             }
  461.         }
  462.         else
  463.         {
  464.             result = KErrNoMemory;
  465.         }
  466.         
  467.     }
  468.     Message().Complete(result);
  469. }
  470. //
  471. // HXSymbianAudioSession::GetTime
  472. //
  473. // Return the current playback position -- converts from
  474. // microseconds to milliseconds
  475. //
  476. void HXSymbianAudioSession::GetTime()
  477. {
  478.     Message().Complete(m_timeline.GetPlaybackTime());
  479. }
  480. //
  481. // HXSymbianAudioSession::GetBlocksBuffered
  482. //
  483. // Return the number of blocks buffered by this object.
  484. //
  485. void HXSymbianAudioSession::GetBlocksBuffered()
  486. {
  487.     Message().Complete(m_bufferList.GetCount());
  488. }
  489. //
  490. // HXSymbianAudioSession::SetVolume
  491. //
  492. // set the volume -- convert from 0-100 to 0-max range
  493. //
  494. void HXSymbianAudioSession::SetVolume()
  495. {
  496.     if (m_pStream)
  497.     {
  498.         m_pStream->SetVolume(Message().Int0());
  499.     }
  500.     Message().Complete(0);
  501. }
  502. //
  503. // HXSymbianAudioSession::GetVolume
  504. //
  505. // get the current volume normalized to 0-100 range
  506. //
  507. void HXSymbianAudioSession::GetVolume()
  508. {
  509.     TInt vol = 0;
  510.     if (m_pStream)
  511.     {
  512.         vol = m_pStream->Volume();
  513.     }
  514.     Message().Complete(vol);
  515. }
  516. //
  517. // HXSymbianAudioSession::GetMaxVolume
  518. //
  519. // get the maxium device volume
  520. //
  521. void HXSymbianAudioSession::GetMaxVolume()
  522. {
  523.     TInt maxVol = 0;
  524.     if (m_pStream)
  525.     {
  526.         maxVol = m_pStream->MaxVolume();
  527.     }
  528.     Message().Complete(maxVol);
  529. }
  530. //
  531. // HXSymbianAudioSession::GetMinVolume
  532. //
  533. // get the minimum device volume
  534. //
  535. void HXSymbianAudioSession::GetMinVolume()
  536. {
  537.     Message().Complete(0);
  538. }
  539. //
  540. // HXSymbianAudioSession::Stop
  541. //
  542. // stop playback
  543. //
  544. void HXSymbianAudioSession::Stop()
  545. {
  546.     m_bPaused = TRUE;
  547.     if(m_pStream)
  548.     {
  549.         m_pStream->Stop();
  550.     }
  551.     
  552.     // Cleanup any remaining buffers
  553.     while(!m_bufferList.IsEmpty())
  554.     {
  555.         IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
  556.         HX_RELEASE(pBuf);
  557.     }
  558.     m_timeline.Reset(GetByteRate());
  559.     Message().Complete(KErrNone);
  560. }
  561. void
  562. HXSymbianAudioSession::RequestDeviceTakenNotification()
  563. {
  564.     m_wantsNotify = true;
  565.     m_notifyRequest = Message();
  566. }
  567. void
  568. HXSymbianAudioSession::CancelDeviceTakenNotification()
  569. {
  570.     if (m_wantsNotify)
  571.     {
  572.         m_notifyRequest.Complete(KErrCancel);
  573.         m_wantsNotify = false;
  574.     }
  575. }
  576. //
  577. // HXSymbianAudioSession::NotifyDeviceTaken
  578. //
  579. // notify the client that the audio device has been taken if a
  580. // notification requrest has been made 
  581. //
  582. void HXSymbianAudioSession::NotifyDeviceTaken()
  583. {
  584.     if (m_wantsNotify)
  585.     {
  586.         m_notifyRequest.Complete(m_reason);
  587.         m_wantsNotify = false;
  588.     }
  589. }
  590. //
  591. // callbacks
  592. //
  593. void HXSymbianAudioSession::MaoscOpenComplete(TInt error)
  594. {
  595.     if (error == KErrNone)
  596.     {
  597.         m_open = true;
  598.         TRAP(error, m_pStream->SetAudioPropertiesL(m_sampleRate,
  599.                                                    m_channels));
  600.         m_pStream->SetPriority(KClientPriority, KPriorityPref);
  601.     }
  602.     Message().Complete(error);
  603. }
  604. void HXSymbianAudioSession::MaoscBufferCopied(TInt error, const TDesC8& buf)
  605. {
  606.     m_bWritePending = FALSE;
  607.     // Check to see if we need a device time
  608.     if (m_timeline.NeedDeviceTime())
  609.     {
  610.         m_timeline.SetDeviceTime(GetDeviceMs());
  611.     }
  612.     if (!m_bufferList.IsEmpty())
  613.     {
  614.         // We should always enter here because the
  615.         // last buffer written is at the head of the list.
  616.         // We want to remove this buffer from the list since
  617.         // this call is the completion of last WriteL() call.
  618.         IHXBuffer* pBuf = (IHXBuffer*)m_bufferList.RemoveHead();
  619.         HX_RELEASE(pBuf);
  620.     }
  621.     if (ReadyToWrite())
  622.     {
  623.         error = WriteNextBuffer();
  624.     }
  625. }
  626. void HXSymbianAudioSession::MaoscPlayComplete(TInt error)
  627. {
  628.     if (KErrUnderflow == error)
  629.     {
  630.         m_timeline.OnPauseOrUnderflow();
  631.     }
  632.     int resetErr;
  633.     TRAP(resetErr, m_pStream->SetAudioPropertiesL(m_sampleRate,
  634.                                                   m_channels));
  635.     m_pStream->SetPriority(KClientPriority, KPriorityPref);
  636.     if (error == KErrAbort)
  637.     {
  638.         m_reason = error;
  639.         m_pServer->NotifyDeviceTaken();
  640.     }
  641. }
  642. UINT32 HXSymbianAudioSession::GetByteRate() const
  643. {
  644.     return 2 * FlagToNumber(m_sampleRate) * FlagToNumber(m_channels);
  645. }
  646. UINT32 HXSymbianAudioSession::GetDeviceMs()
  647. {
  648.     UINT32 ulRet = 0;
  649.     if (m_pStream)
  650.     {
  651.         TTimeIntervalMicroSeconds pos = m_pStream->Position();
  652.         TInt64 millisecs = pos.Int64() / 1000;
  653.    
  654.         ulRet = millisecs.Low();
  655.     }
  656.     return ulRet;
  657. }
  658. BOOL HXSymbianAudioSession::ReadyToWrite() const
  659. {
  660.     return !m_bWritePending && !m_bPaused && !m_bufferList.IsEmpty();
  661. }
  662. TInt HXSymbianAudioSession::WriteNextBuffer()
  663. {
  664.     // Write the next buffer in the list
  665.     IHXBuffer* pBuffer = (IHXBuffer*)m_bufferList.GetHead();
  666.     TInt result = KErrNone;
  667.     if (pBuffer)
  668.     {
  669.         if( m_pStream )
  670.         {
  671.             int len = pBuffer->GetSize();
  672.             m_pData.Set((TUint8*)pBuffer->GetBuffer(), len, len);
  673.             TRAP(result, m_pStream->WriteL(m_pData));
  674.         }
  675.         else
  676.         {
  677.             // oom earlier?
  678.             result = KErrNotReady;
  679.         }
  680.     }
  681.     if (KErrNone == result)
  682.     {
  683.         m_timeline.OnWrite(pBuffer->GetSize());
  684.         m_bWritePending = TRUE;
  685.     }
  686.     else
  687.     {
  688.         m_bWritePending = FALSE;
  689.     }
  690.     return result;
  691. }