bluetoothengine/btaudiostreamer/src/btaudiostreamsender.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 23 Jun 2010 18:23:52 +0300
changeset 40 997690c3397a
parent 0 f63038272f30
permissions -rw-r--r--
Revision: 201023 Kit: 2010125

/*
* 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() <-")));
	  }