bluetoothengine/btaudiostreamer/src/btaudiostreamsender.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btaudiostreamer/src/btaudiostreamsender.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,538 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Contains an implementation of CBTAudioStreamSender class.
+*
+*/
+
+
+#include "btaudiostreamsender.h"
+#include "btaudiostreamsendersbc.h"
+#include "btaudiostreamerdebug.h" 
+#include <btsockaddr.h> // TBTSockAddr 
+
+// ---------------------------------------------------------------------------
+// Constructor. 
+// ---------------------------------------------------------------------------
+//
+CBTAudioStreamSender::CBTAudioStreamSender(MBTAudioStreamSenderObserver& aObserver, RRtpSession& aSession) :
+    CActive(EPriorityHigh),     
+    iObserver(aObserver), 
+    iRtpSession(aSession), 
+    iPayloadDesC(NULL,NULL), 
+    iLinkOptimiserAvailable(EFalse)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::CBTAudioStreamSender() ->")));
+    CActiveScheduler::Add(this);    
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::CBTAudioStreamSender() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// Symbian OS second phase contruction. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::ConstructL()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ConstructL() ->")));   
+
+    iSendSrc = iRtpSession.NewSendSourceL();
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t New send source created.")));
+    iSendSrc.PrivRegisterEventCallbackL(ERtpSendSucceeded, (TRtpCallbackFunction)CBTAudioStreamSender::PacketSent, this);
+    iSendSrc.PrivRegisterEventCallbackL(ERtpSendFail, (TRtpCallbackFunction)CBTAudioStreamSender::SendError, this);
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Callbacks registered.")));
+
+    iStreamerState = EStopped; 
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: EStopped")));
+
+    iThread = RThread();
+
+    iCurrentSendPacket = new (ELeave) RRtpSendPacket; 
+
+    iSpareSendPacket = new (ELeave) RRtpSendPacket; 
+
+    if(iA2DPOptimiser.Open() == KErrNone)
+        {
+        iLinkOptimiserAvailable = ETrue; 
+        }
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ConstructL() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// Static factory method. 
+// ---------------------------------------------------------------------------
+//
+CBTAudioStreamSender* CBTAudioStreamSender::NewL(MBTAudioStreamSenderObserver& aObserver, RRtpSession& aSession)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::NewL() ->")));
+    if (!aSession.IsOpen())
+        {
+        User::Leave(KErrArgument);
+        }
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::NewL() <-")));
+    return CBTAudioStreamSenderSBC::NewL(aObserver, aSession); 
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor. 
+// ---------------------------------------------------------------------------
+//
+CBTAudioStreamSender::~CBTAudioStreamSender()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::~CBTAudioStreamSender() ->")));
+    Cancel();
+    if(iCurrentSendPacket) 
+        {
+        if(iCurrentSendPacket->IsOpen() != EFalse)
+            {
+   			iCurrentSendPacket->Close();
+            }
+         delete iCurrentSendPacket; 
+         iCurrentSendPacket = NULL; 
+         }
+
+    if(iSpareSendPacket) 
+        {
+        if(iSpareSendPacket->IsOpen() != EFalse)
+            {
+            iSpareSendPacket->Close(); 
+            }
+        delete iSpareSendPacket; 
+        iSpareSendPacket = NULL; 
+        }
+    iSendSrc.Close();
+
+    if(iLinkOptimiserAvailable)
+        {
+        iA2DPOptimiser.Close();
+        }
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::~CBTAudioStreamSender() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// This is the static callback method which CBTAudioStreamSender registers with the RtpSession to be called
+// when a packet is _successfully_ sent.  It is a static method so simply calls a processing
+// method on the class pointed to be aPtr (which is the CBTAudioStreamSender which registered the cb).
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::PacketSent(CBTAudioStreamSender* aPtr, const TRtpEvent& /*aEvent*/)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::PacketSent() ->")));
+    aPtr->DoPacketSent();
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::PacketSent() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// An instance method which is called by the static callback function.  We simply notify the
+// observer if all data has been sent. If it hasn't, then we send more data. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::DoPacketSent()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::DoPacketSent() ->")));
+
+	// First check if we're Stopping. 
+    if(iStreamerState == EStopped)
+        {
+	    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t Stopping and packet sending completed.")));
+        iObserver.NotifyBufferSent(*iBuffer); // Return the buffer. 
+		return; // No need to do more here, we're stopping. 
+        }
+	else
+		{
+		iStreamerState = EBuffering; 
+    	BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: EBuffering")));
+		}
+
+    PacketSendingCompleted(iPayloadDesC); 
+ 
+    // If we're here, then there either is data in the buffer or it has been emptied completely. 
+    // Check this by calling the method again. If we consumed the buffer completely, 
+    // the method just signals the observer. 
+    if(iNonprocessedDataInBuffer != EFalse) 
+        {
+				// Check if we need to start using new sendpacket. 
+        if(iChangingFrameLength != EFalse)
+            {
+        	  SwitchToNewSendPacket(); 
+		        }
+            ConsumeBuffer(); 
+        }
+    else 
+        {
+        iObserver.NotifyBufferSent(*iBuffer); 
+        }
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::DoPacketSent() <-")));
+}
+
+// ---------------------------------------------------------------------------
+// This is the static callback method which CBTAudioStreamSender registers with the RtpSession to be called
+// when a packet sending fails.
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::SendError(CBTAudioStreamSender* aPtr, const TRtpEvent& /*aEvent*/)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SendError() ->")));
+    aPtr->DoSendError();
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SendError() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// An instance method which is called by the static callback function.  
+// We set the state to EErrorSending and handle the error next time in RunL. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::DoSendError()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::DoSendError() ->")));
+    
+    iStreamerState = EErrorSending; 
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: EErrorSending")));
+    if (!IsActive())
+        {
+        TRequestStatus *status = &iStatus;
+        iStatus = KRequestPending;
+        iThread.RequestComplete(status, KErrNone);
+        SetActive();
+        }
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::DoSendError() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// This method is for setting the sender up. 
+// ---------------------------------------------------------------------------
+//
+TInt CBTAudioStreamSender::SetNewFrameLength(TUint aOutboundMTUSize, const TUint aFrameLength, const TUint aTargetBitrate)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SetNewFrameLength() ->")));
+		TInt retVal = KErrGeneral;
+
+		// Don't proceed if the previous change is not completed yet. 
+		if(iChangingFrameLength != EFalse)
+		    {
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Previous frame length change still ongoing!")));
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SetNewFrameLength() <-")));
+		    return KErrInUse; 
+		    }
+
+    if(iSpareSendPacket) 
+        {
+        __ASSERT_DEBUG(!iSpareSendPacket->IsOpen(),User::Invariant());
+        }
+
+    TInt requiredPacketLength = CalculatePacketLength(aOutboundMTUSize, aFrameLength); 
+
+    if(requiredPacketLength > 0) 
+        {
+		    iNewFrameLength = aFrameLength; 
+
+    		BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Creating new sendpacket.")));
+			__ASSERT_DEBUG(iSpareSendPacket, User::Invariant());
+    		TRAPD(ret, *iSpareSendPacket = iSendSrc.NewSendPacketL(requiredPacketLength));
+        	if( ret )
+        		{
+        		BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t ERROR! Creating new sendpacket failed.")));
+        		return KErrGeneral;
+        		}
+        	iChangingFrameLength = ETrue; 
+			retVal = KErrNone; 
+      }
+    else 
+        {
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t Error! Packet length must be greater than zero!")));
+        retVal = KErrArgument; 
+        }
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SetNewFrameLength() <-")));
+
+    iTargetBitrate = aTargetBitrate; 
+    return retVal; 
+    }
+
+
+// ---------------------------------------------------------------------------
+// This method is for setting the sender up. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::StartL(TUint aOutboundMTUSize, const TUint aFrameLength, const TUint aTargetBitrate)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::StartL() ->")));
+    if(iCurrentSendPacket) 
+        {
+        __ASSERT_DEBUG(!iCurrentSendPacket->IsOpen(),User::Invariant());
+        }
+    TInt requiredPacketLength = CalculatePacketLength(aOutboundMTUSize, aFrameLength); 
+
+    if(requiredPacketLength > 0) 
+        {
+		__ASSERT_DEBUG(iCurrentSendPacket, User::Invariant());
+        *iCurrentSendPacket = iSendSrc.NewSendPacketL(requiredPacketLength); 
+        iTargetBitrate = aTargetBitrate; 
+        InitSender(*iCurrentSendPacket, iPayloadDesC, iTargetBitrate); 
+        iStreamerState = EBuffering; 
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: EBuffering")));
+      }
+    else 
+        {
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t Error! Packet length must be greater than zero!")));
+        User::Leave(KErrArgument); 
+        }
+
+    // Streaming started, optimise the ACL link if optimiser service is available. 
+    if(iLinkOptimiserAvailable)
+        {
+        // The below code is to get the connected device's BT Address.
+        TBTSockAddr addr; 
+        iRtpSession.RtpSocket()->RemoteName(addr); 
+        TUint accessLatency = MaxFramesPerPacket() * CalculateFrameDuration(aFrameLength, aTargetBitrate); 
+        // Not checking the return code, because it doesn't matter if it fails. 
+        iA2DPOptimiser.OptimiseAclForAudioStreaming(addr.BTAddr(), aTargetBitrate, accessLatency);
+        }
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::StartL() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// This method is for closing the sender down. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::Stop()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::Stop() ->")));
+	// Make sure that the packet is not out at the moment. 
+	Cancel(); 
+    if(iCurrentSendPacket->IsOpen() != EFalse)
+        {
+   		iCurrentSendPacket->Close(); 
+        }
+
+    if(iSpareSendPacket->IsOpen() != EFalse)
+        {
+    	iSpareSendPacket->Close(); 
+        }
+
+    // Remove the ACL link optimisation if optimiser service is available. 
+    if(iLinkOptimiserAvailable)
+        {
+	    TBTSockAddr addr; 
+    	iRtpSession.RtpSocket()->RemoteName(addr); 
+	    // Not checking the return code, because it doesn't matter if it fails. 
+    	iA2DPOptimiser.RemoveAclOptimisation(addr.BTAddr());
+		}
+    iStreamerState = EStopped; 
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: EStopped")));
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::Stop() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// From class CBTAudioStreamSender.
+// RunL will be called when ConsumeBuffer has decided that we have enough 
+// frames for one packet, or DoSendError was called. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::RunL()
+    {        
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::RunL() ->")));
+    switch(iStreamerState)
+        {
+        case ESending: 
+            {    
+            // Set A2DP media packet header. 
+            AddHeaderToSendPacket(iPayloadDesC); 
+
+            // Use the timestamp from the first buffer. 
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Adjust and set timestamp.")));
+            iCurrentSendPacket->SetTimestamp(iAdjustedTimestamp); 
+
+            // Set the length and send the packet. 
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Set length.")));
+            iCurrentSendPacket->WritePayload().SetLength(iPayloadDesC.Length());
+
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Send.")));
+            iCurrentSendPacket->Send();
+
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Packet has transferred to RTP API.")));
+            }
+            break; 
+        case EBuffering: 
+            {
+            // Note: Here we will check that no packets were discarded while waiting for the sending to complete. 
+            // If that happens, we could inform SAC and then try to decrease the bitrate. 
+    
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Packet sent succesfully.")));
+            iPayloadDesC.Zero(); 
+            }
+            break; 
+        case EErrorSending: 
+            {
+            // Note: Inform the observer 
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Packet sending failed.")));
+            iPayloadDesC.Zero(); 
+            PacketSendingCompleted(iPayloadDesC); 
+            iStreamerState = EBuffering; 
+            
+            // Tell client that we're ready for more data. Method name is misleading, but we will request for more 
+            // until the observer tells us to stop. 
+            iObserver.NotifyBufferSent(*iBuffer); 
+
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: EBuffering")));
+            }
+            break; 
+        default: 
+            {
+          BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Error: RunL is in incorrect state!")));
+            }
+            break; 
+        }
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::RunL() <-")));
+    }
+
+// ---------------------------------------------------------------------------
+// For sending the frames. 
+// ---------------------------------------------------------------------------
+//
+TInt CBTAudioStreamSender::SendThisBuffer(const TDesC8& aBuffer, TTimeIntervalMicroSeconds aTimestamp)
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SendThisBuffer() ->")));
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Received timestamp low: %d"), I64LOW(aTimestamp.Int64()))); 
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Received timestamp high: %d"), I64HIGH(aTimestamp.Int64()))); 
+
+    // Store the buffer's address for later reference. 
+    iBuffer = &aBuffer; 
+
+		if(iChangingFrameLength != EFalse) 
+		{
+			// Check the new framelength... 
+			if(aBuffer.Length() == iNewFrameLength)  // Check if the buffer exactly of the new length. 
+			{
+						// If we have data with previous frame length in buffer, send it first. 
+            if(iNonprocessedDataInBuffer != EFalse)
+                {
+	              ProceedToPacketSending(); 
+                return KErrNone; 
+                }
+            else	// Else we can switch to new packet immediately and continue processing this buffer. 
+                {
+								SwitchToNewSendPacket(); 
+                }
+			}
+			else if(aBuffer.Length() > iNewFrameLength) // Check if it's safe to peek at index iNewFrameLength. 
+			{
+				if(aBuffer[iNewFrameLength] == 0x9c) // Check if the index iNewFrameLength the syncword. 
+				    {
+						// If we have data with previous frame length in buffer, send it first. 
+            if(iNonprocessedDataInBuffer != EFalse)
+                {
+	              ProceedToPacketSending(); 
+                return KErrNone; 
+                }
+            else	// Else we can switch to new packet immediately and continue processing this buffer. 
+                {
+								SwitchToNewSendPacket(); 
+                }
+						}
+				else 
+				{
+            BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender: Still waiting for packets of the new frame length...")));
+				}
+			}
+			else 
+			{
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender: Still waiting for packets of the new frame length...")));
+				// Encoder has not yet started to use the new frame length. 
+			}
+		}
+    else if(iStreamerState != EBuffering) 
+        {
+        // Previous sending is not yet completed or there is was an error that is not yet handled. 
+        // Just discard the incoming frame. 
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender error: Previous buffer sending hasn't completed - discarding this buffer.")));
+        iObserver.NotifyBufferSent(aBuffer); 
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SendThisBuffer() <-")));
+        return KErrOverflow; 
+        }
+
+		// Store the timestamp for later use. 
+    iTimestamp = aTimestamp.Int64(); 
+
+    iNonprocessedDataInBuffer = ETrue; 
+    ConsumeBuffer(); 
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SendThisBuffer() <-")));
+    return KErrNone; 
+    }
+
+// ---------------------------------------------------------------------------
+// From class CActive.
+// Cancellation. 
+// ---------------------------------------------------------------------------
+//
+void CBTAudioStreamSender::DoCancel()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::DoCancel() ->")));
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::DoCancel() <-")));
+    }
+
+inline void CBTAudioStreamSender::ConsumeBuffer()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ConsumeBuffer() ->")));
+    if (!IsActive())
+        {    
+        BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ConsumeBuffer() ok to send")));				
+
+        TInt spaceLeftInSendPacket = AddBufferToSendPacket(*iBuffer); 
+				iAdjustedTimestamp = iTimestamp;  // take a copy, because we want to keep the original timestamp. 
+        if(spaceLeftInSendPacket >= 0) 
+            {
+            iNonprocessedDataInBuffer = EFalse; // This indicates that there's no need to call this method after sending. 
+            }
+        ProceedToPacketSending(); 
+        }
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ConsumeBuffer() <-")));
+    }
+
+
+inline void CBTAudioStreamSender::ProceedToPacketSending()
+{
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ProceedToPacketSending() ->")));
+    iStreamerState = ESending; 
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTSTATE, FLOG(_L("[BTAudioStreamer]\t State changed to: ESending")));
+    TRequestStatus *status = &iStatus;
+    iStatus = KRequestPending;
+    iThread.RequestComplete(status, KErrNone);
+    SetActive();
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::ProceedToPacketSending() <-")));
+}
+
+inline void CBTAudioStreamSender::SwitchToNewSendPacket()
+    {
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SwitchToNewSendPacket() ->")));
+
+		// Make the iCurrentSendPacket point to the spare packet opened when the frame length change came. 
+    RRtpSendPacket* oldSendPacket; 
+    oldSendPacket = iCurrentSendPacket; 
+    iCurrentSendPacket = iSpareSendPacket; 
+		iSpareSendPacket = oldSendPacket; 
+		
+    // The previously used send packet (which has now become the spare send packet) can be closed. 
+		oldSendPacket->Close(); 
+
+		// The rest of the initializations: 
+    InitSender(*iCurrentSendPacket, iPayloadDesC, iTargetBitrate); 
+
+		iChangingFrameLength = EFalse; 
+
+    BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSender::SwitchToNewSendPacket() <-")));
+	  }