--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btaudiostreamer/src/btaudiostreamsendersbc.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,244 @@
+/*
+* 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 CBTAudioStreamSenderSBC class.
+*
+*/
+
+
+#include "btaudiostreamsendersbc.h"
+#include "btaudiostreamerdebug.h"
+
+const TInt KA2DPMediaPacketHeaderLength = 1;
+const TInt KA2DPMediaPacketHeaderIndex = 0;
+const TInt KRTPHeaderLength = 12;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//
+CBTAudioStreamSenderSBC::CBTAudioStreamSenderSBC(MBTAudioStreamSenderObserver& aObserver, RRtpSession& aSession):
+ CBTAudioStreamSender(aObserver, aSession)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CBTAudioStreamSenderSBC() ->")));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CBTAudioStreamSenderSBC() <-")));
+ }
+
+// ---------------------------------------------------------------------------
+// Factory method.
+// ---------------------------------------------------------------------------
+//
+/*static*/ CBTAudioStreamSenderSBC* CBTAudioStreamSenderSBC::NewL(MBTAudioStreamSenderObserver& aObserver, RRtpSession& aSession)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::NewL() ->")));
+
+ CBTAudioStreamSenderSBC* self = new (ELeave) CBTAudioStreamSenderSBC(aObserver, aSession);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::NewL() <-")));
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CBTAudioStreamSenderSBC::~CBTAudioStreamSenderSBC()
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::~CBTAudioStreamSenderSBC() ->")));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::~CBTAudioStreamSenderSBC() <-")));
+ }
+
+// ---------------------------------------------------------------------------
+// From class CBTAudioStreamSender.
+// This method stores the frames to the frame buffer and
+// when we have enough frames.
+// ---------------------------------------------------------------------------
+//
+TInt CBTAudioStreamSenderSBC::AddHeaderToSendPacket(TPtr8& aPayloadDesC)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddHeaderToSendPacket() ->")));
+ aPayloadDesC[KA2DPMediaPacketHeaderIndex] = iNumOfFramesInSendPacket;
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddHeaderToSendPacket() <-")));
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// From class CBTAudioStreamSender.
+// This method stores the frames to the frame buffer and
+// when we have enough frames.
+// ---------------------------------------------------------------------------
+//
+TInt CBTAudioStreamSenderSBC::AddBufferToSendPacket(const TDesC8& aBuffer)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddBufferToSendPacket() ->")));
+ // Copy data from the buffer to the outgoing packet.
+ // The return code means how many frames can still fit in the SendPacket.
+ // - If there's more space, the value > 0. In this case we need more data.
+ // - If the buffer is full and all data was consumed, the value == 0. In this case the packet must be sent.
+ // - If the buffer is full and all data didn't fit in it, the value < 0. The packet must be sent and this method called again with the same frame.
+
+ // Calculate how many frames there's left in the buffer. Note that iFrameLength must always be greater than zero.
+ TInt numOfFramesLeftInBuffer = (aBuffer.Length() / iFrameLength) - iNumOfFramesAlreadyMoved ;
+
+ // If the whole buffer can fit in packet, move it completely, otherwise move as many frames as can fit.
+ TInt numOfFramesToMove = numOfFramesLeftInBuffer <= iMaxNumOfFrames - iNumOfFramesInSendPacket ?
+ numOfFramesLeftInBuffer :
+ iMaxNumOfFrames - iNumOfFramesInSendPacket;
+
+ // Some traces for seeing what's going on.
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Filling sendpacket...")));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames can fit in packet."), iMaxNumOfFrames));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames have already been moved from current buffer to sendpacket."), iNumOfFramesAlreadyMoved));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames left to move from current buffer."), numOfFramesLeftInBuffer));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames already in current packet."), iNumOfFramesInSendPacket));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t => Moving %d frames."), numOfFramesToMove));
+
+ // Move the number of frames calculated above to the packet:
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t replacing sendpacket content from %d, length is %d..."), KA2DPMediaPacketHeaderLength + iNumOfFramesInSendPacket * iFrameLength, numOfFramesToMove * iFrameLength));
+
+ // Make the ptrNextFrameInBuffer point to the first frame that hasn't been moved.
+ const TUint8 * ptrNextFrameInBuffer = aBuffer.Ptr() + iNumOfFramesAlreadyMoved * iFrameLength;
+ memcpy((void *)iPtrEndOfPayload, (void *)ptrNextFrameInBuffer, numOfFramesToMove * iFrameLength);
+ iPtrEndOfPayload += numOfFramesToMove * iFrameLength;
+ ptrNextFrameInBuffer += numOfFramesToMove * iFrameLength;
+
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames moved from buffer to packet."), numOfFramesToMove));
+
+ // If we have now moved them all, reset the counter, otherwise update it for the next round.
+ iNumOfFramesAlreadyMoved = numOfFramesLeftInBuffer == numOfFramesToMove ? 0 : iNumOfFramesAlreadyMoved + numOfFramesToMove;
+
+ // update the information needed for building the header later (in sending phase):
+ iNumOfFramesInSendPacket += numOfFramesToMove;
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t iNumOfFramesInSendPacket incremented, it is now %d"), iNumOfFramesInSendPacket));
+
+ numOfFramesLeftInBuffer -= numOfFramesToMove;
+
+ // return the number of frames that will still fit in the packet:
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t returning: %d"), iMaxNumOfFrames - iNumOfFramesInSendPacket - numOfFramesLeftInBuffer));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddBufferToSendPacket() <-")));
+ return (iMaxNumOfFrames - iNumOfFramesInSendPacket - numOfFramesLeftInBuffer);
+ }
+
+// ---------------------------------------------------------------------------
+// From class CBTAudioStreamSender.
+// This method stores the frames to the frame buffer and
+// when we have enough frames.
+// ---------------------------------------------------------------------------
+//
+TInt CBTAudioStreamSenderSBC::PacketSendingCompleted(TPtr8& aPayloadDesC)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::PacketSendingCompleted() ->")));
+ iNumOfFramesInSendPacket = 0;
+ iPtrEndOfPayload = aPayloadDesC.Ptr() + KA2DPMediaPacketHeaderLength;
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::PacketSendingCompleted() <-")));
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// From class CBTAudioStreamSender.
+// This method sets up the sender and calculates the required packet
+// length according to its own implementation.
+// ---------------------------------------------------------------------------
+//
+TInt CBTAudioStreamSenderSBC::InitSender(RRtpSendPacket& aSendPacket, TPtr8& aPayloadDesC, const TUint aTargetBitrate)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::InitSender() ->")));
+ iFrameLength = iNewFrameLength;
+ iMaxNumOfFrames = iSpaceNeededForBuffer / iFrameLength;
+
+ // Make the descriptor point in the beginning of the send packet.
+ aPayloadDesC.Set(const_cast<TUint8*>(aSendPacket.WritePayload().Ptr()), iSpaceNeededForBuffer, iSpaceNeededForBuffer);
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Descriptor inited, space needed: %d bytes."), iSpaceNeededForBuffer));
+
+ iPtrEndOfPayload = aPayloadDesC.Ptr() + KA2DPMediaPacketHeaderLength;
+
+ iNumOfFramesInSendPacket = 0;
+
+ iTimestampOfFirstFrameInSendPacket = 0;
+
+ iDurationOfFrame = CalculateFrameDuration(iFrameLength, aTargetBitrate);
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t iDurationOfFrame: %d"), iDurationOfFrame));
+
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::InitSender() <-")));
+ return KErrNone;
+ }
+
+TInt CBTAudioStreamSenderSBC::CalculatePacketLength(TUint aOutboundMTUSize, const TUint aFrameLength)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculatePacketLength() <-")));
+ if(aFrameLength > 0) // Must not be zero, and cannot be according to A2DP spec.
+ {
+ iNewFrameLength = aFrameLength;
+
+ iSpaceNeededForBuffer = ((aOutboundMTUSize - KA2DPMediaPacketHeaderLength - KRTPHeaderLength) / iNewFrameLength) * iNewFrameLength + KA2DPMediaPacketHeaderLength;
+
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculatePacketLength() <-")));
+ return iSpaceNeededForBuffer;
+ }
+ else
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Length parameter is zero!")));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculatePacketLength() <-")));
+ return 0;
+ }
+ }
+
+TUint CBTAudioStreamSenderSBC::CalculateFrameDuration(const TUint aFrameLength, const TUint aTargetBitrate)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculateFrameInterval() ->")));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculateFrameInterval() <-")));
+ return static_cast<TUint>(static_cast<TReal>(aFrameLength * 8) / static_cast<TReal>(aTargetBitrate) * 1000000.0);
+ }
+
+TUint CBTAudioStreamSenderSBC::MaxFramesPerPacket()
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::FramesPerPacket() ->")));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::FramesPerPacket() <-")));
+ return iMaxNumOfFrames;
+ }
+
+void CBTAudioStreamSenderSBC::AdjustTimestamp(TInt64& aTimestamp)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AdjustTimestamp() ->")));
+
+ // The buffer has been emptied, but there may be space for additional frames in sendpacket.
+ // So keep the current timestamp until the sendpacket becomes full.
+ if(iNumOfFramesAlreadyMoved == 0)
+ {
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Buffer became empty.")));
+ iTimestampChangeFlag = ETrue;
+ }
+
+ if(iNumOfFramesInSendPacket == iMaxNumOfFrames) // Adjust the timestamp only when the sendpacket is full.
+ {
+ if(iTimestampChangeFlag != EFalse)
+ {
+ // When the buffer been emptied earlier, take the new timestamp into use and adjust it by the amount of frames we just moved.
+ iTimestampOfFirstFrameInSendPacket = aTimestamp + iDurationOfFrame * iNumOfFramesAlreadyMoved;
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t New timestamp %d (low) is in use."), I64LOW(aTimestamp)));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t New timestamp %d (high) is in use."), I64HIGH(aTimestamp)));
+ iTimestampChangeFlag = EFalse;
+ }
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Timestamp is %d (low)"), I64LOW(iTimestampOfFirstFrameInSendPacket)));
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Timestamp is %d (high)"), I64HIGH(iTimestampOfFirstFrameInSendPacket)));
+
+ // Use the timestamp first and then do a normal adjustment for the next round.
+ aTimestamp = iTimestampOfFirstFrameInSendPacket;
+ iTimestampOfFirstFrameInSendPacket = iTimestampOfFirstFrameInSendPacket + iMaxNumOfFrames * iDurationOfFrame;
+ }
+ BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AdjustTimestamp() <-")));
+ }