1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/RTPStreamer.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,689 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <bluetoothav.h>
1.20 +#include <mmf/server/mmfcodec.h>
1.21 +#include "mmfSBCCodecImplementationUIDs.hrh"
1.22 +#include <hal.h>
1.23 +#include "A2dpCodecUtilities.h"
1.24 +#include "AudioBufferArray.h"
1.25 +#include "RTPStreamer.h"
1.26 +
1.27 +
1.28 +/**
1.29 +RTP Streamer Panics
1.30 +**/
1.31 +enum TRTPStreamerPanic
1.32 + {
1.33 + ERTPStreamerSendPacketMiscount, //0
1.34 + ERTPStreamerSendNotCompleted, //1
1.35 + ERTPStreamerEmptyBuffer, //2
1.36 + ERTPStreamerRTPEventError, //3
1.37 + ERTPStreamerIncompleteSBCFrame, //4
1.38 + ERTPStreamerUnexpectedEvent, //5
1.39 + ERTPStreamerBufferProcessingLengthMismatch, //6
1.40 + ERTPStreamerInvalidDataType, //7
1.41 + ERTPStreamerNoConfiguration //8
1.42 + };
1.43 +
1.44 +
1.45 +static void Panic(TRTPStreamerPanic aPanic)
1.46 +// Panic client
1.47 + {
1.48 + _LIT(KRTPStreamerPanicName, "RTP Streamer");
1.49 + User::Panic(KRTPStreamerPanicName, aPanic);
1.50 + }
1.51 +
1.52 +
1.53 +
1.54 +/**
1.55 +Creates CActiveRTPStreamer
1.56 +
1.57 +@param aSock RSocket that can be used to stream audio to the headset
1.58 +@param aRTPStreamObserver mixin used to inform the CA2dpBTHeadsetAudioInterface
1.59 +of asynchronous error events
1.60 +@return CActiveRTPStreamer*
1.61 +*/
1.62 +CActiveRTPStreamer* CActiveRTPStreamer::NewL(RSocket& aSock, MRTPStreamerObserver& aRTPStreamerObserver)
1.63 + {
1.64 + CActiveRTPStreamer* self = new (ELeave) CActiveRTPStreamer (aRTPStreamerObserver);
1.65 + CleanupStack::PushL(self);
1.66 + self->ConstructL(aSock);
1.67 + CleanupStack::Pop(self);
1.68 + return self;
1.69 + }
1.70 +
1.71 +
1.72 +/**
1.73 +Make priortiy high so other RunLs don't impact CTimer accuracy too much
1.74 +*/
1.75 +CActiveRTPStreamer::CActiveRTPStreamer(MRTPStreamerObserver& aRTPStreamerObserver) : CTimer(EPriorityHigh), iRTPStreamerObserver(aRTPStreamerObserver), iRtpCanSend(ETrue)
1.76 + {
1.77 + CActiveScheduler::Add(this);
1.78 + }
1.79 +
1.80 +
1.81 +CActiveRTPStreamer::~CActiveRTPStreamer()
1.82 + {
1.83 + Cancel();
1.84 + delete iAudioBufferArray;
1.85 +
1.86 + //RTP defect fix DEF57144- RRtpSendSource Cancel()
1.87 + //If the line of code below does not compile then your build is too old
1.88 + iRTPSendSource.Cancel();
1.89 +
1.90 + iRTPSendSource.Close();
1.91 + iRTPSession.Close();
1.92 + }
1.93 +
1.94 +
1.95 +void CActiveRTPStreamer::ConstructL(RSocket& aSock)
1.96 + {
1.97 + CTimer::ConstructL();
1.98 + // get the MTU length limit
1.99 + TInt mtu = 0;
1.100 + User::LeaveIfError(aSock.GetOpt(EAvdtpMediaGetMaximumPacketSize, KSolBtAVDTPMedia, mtu));
1.101 + iMaxMTULength = mtu;//the line above wont accept iMaxMTULength directly because it is unsigned
1.102 + iRTPSession.OpenL(aSock, iMaxMTULength);
1.103 + iRTPSendSource = iRTPSession.NewSendSourceL();
1.104 +
1.105 + //register callbacks - all terminal callbacks are one shot
1.106 + iRTPSession.RegisterEventCallbackL(ERtpAnyEvent,RTPCallback,this);
1.107 + iRTPSession.RegisterEventCallbackL(ERtpSessionFail,RTPCallback,this, ERtpOneShot);
1.108 + iRTPSession.RegisterEventCallbackL(ERtpBufferOverflow,RTPCallback,this);
1.109 + iRTPSession.RegisterEventCallbackL(ERtpUndersizedPacket,RTPCallback,this);
1.110 + iRTPSendSource.RegisterEventCallbackL(ERtpAnyEvent,RTPSendSourceCallback,this);
1.111 + iRTPSendSource.RegisterEventCallbackL(ERtpSendFail,RTPSendSourceCallback,this, ERtpOneShot);
1.112 + }
1.113 +
1.114 +
1.115 +/**
1.116 +Function called by the CA2dpBTHeadsetAudioInterface to set the codec and the codec
1.117 +settings used by the CActiveRTPStreamer.
1.118 +Calling this function forces a recalculation of all the timings the next
1.119 +time Send() is called
1.120 +
1.121 +@param aCodec the codec to be used. If this is set to NULL then no codec is used
1.122 +only the CSBCCodec can be used here
1.123 +@param aConfigType a Uid to identify the aConfigData used to configure the settings
1.124 +only KMmfUidSBCConfigure is currently defined. In future other types may be defined
1.125 +for mp3, AAC and ATRAC3
1.126 +@param aConfigData The configuration data
1.127 +@return standard SymbianOS error code
1.128 +*/
1.129 +void CActiveRTPStreamer::SetCodec(CMMFCodec& aCodec)
1.130 + {
1.131 + //if there is a codec then it must be SBC else codec must be on the headset
1.132 + iCodec = &aCodec;
1.133 + }
1.134 +
1.135 +
1.136 +void CActiveRTPStreamer::SetAudioConfiguration(const CA2dpAudioCodecConfiguration& aAudioCodecConfiguration)
1.137 + {
1.138 + iA2dpAudioCodecConfiguration = const_cast<CA2dpAudioCodecConfiguration*>(&aAudioCodecConfiguration);
1.139 + //if there is a new codec configuration then cannot assume the buffer
1.140 + //length will be the same so reset
1.141 + iBufferLength = 0;
1.142 + iBufferParamsInitialized = EFalse;//will result in a call to InitializeForSendL
1.143 + iTimeStampIncrement = 0;
1.144 + iNumberOfInputBytesToMakeRTPPacket = 0;
1.145 + }
1.146 +
1.147 +/**
1.148 +Internal function to perform frame size related initialization
1.149 +ie creation and setting of the RTPSendPacket audio buffer array.
1.150 +Assumes all buffers are the same size (except for the last buffer)
1.151 +
1.152 +@param The length of the audio buffer sent in Send()
1.153 +*/
1.154 +void CActiveRTPStreamer::InitializeForSendL(const TDesC8& aData)
1.155 + {
1.156 + iSendBufferSize = aData.Size(); //store buffer length - this shouldn't change till the last buffer
1.157 + __ASSERT_DEBUG(iSendBufferSize,Panic(ERTPStreamerEmptyBuffer));
1.158 + __ASSERT_DEBUG(iA2dpAudioCodecConfiguration,Panic(ERTPStreamerNoConfiguration));
1.159 + TUint encodedBufferSize = iSendBufferSize;
1.160 +
1.161 + if (iCodec)
1.162 + {
1.163 + iCodec->ResetL(); //clear out any cached data from previous settings
1.164 + //if we are using a local codec - ie SBC then we get the frame length
1.165 + //and bit rate from the local codec settings
1.166 + //since aData will contain pcm16
1.167 + iFrameLength = iA2dpAudioCodecConfiguration->LocalSBCCodecConfiguration().CalcFrameLength();
1.168 + iBitRate = iA2dpAudioCodecConfiguration->LocalSBCCodecConfiguration().CalcBitRate(iFrameLength)*1000;//*1000 as bitrate is in KHz
1.169 + //if we are putting data through the local SBC codec then
1.170 + //the encoded buffer size sent to the headset in not the same as the aData buffer in Send()
1.171 + encodedBufferSize = iA2dpAudioCodecConfiguration->CalculateSBCBufferLength(iSendBufferSize);
1.172 + }
1.173 + else
1.174 + {
1.175 + //if we don't use a local codec then we get the frame legth and bit rate
1.176 + //direct from the header
1.177 + CA2dpCodecFrameHeaderParser* headerParser = CA2dpCodecFrameHeaderParser::NewL(iA2dpAudioCodecConfiguration->HeadsetCodecDataType(), aData);
1.178 + iFrameLength = headerParser->FrameLength();
1.179 + iBitRate = headerParser->BitRate();
1.180 + delete headerParser;
1.181 + }
1.182 + iPayloadType = TRTPa2dpCodecSpecificUtils::PayloadType(iA2dpAudioCodecConfiguration->HeadsetCodecDataType());
1.183 +
1.184 + //if the settings have changed then any existing buffered audio buffers
1.185 + // will have the old settings so we need to delete the buffer array
1.186 + //and recreate from new with the new settings.
1.187 + //we also need to cancel in case we are waiting on a RTPSendSourceCallback
1.188 + //from a previous send packet
1.189 + //RTP defect fix DEF57144- RRtpSendSource Cancel() not in MCL
1.190 + //decomment this out when the Cancel method is on the MCL
1.191 + //iRTPSendSource.Cancel();
1.192 +
1.193 + delete iAudioBufferArray;
1.194 + iAudioBufferArray = NULL;
1.195 + //calculate the size of the RTP header
1.196 + TUint mediaPayloadHeaderLength = TRTPa2dpCodecSpecificUtils::MediaPayloadHeaderLength(iA2dpAudioCodecConfiguration->HeadsetCodecDataType());
1.197 + TUint rtpHeaderLength = KRTPHeaderSize + mediaPayloadHeaderLength;
1.198 + iAudioBufferArray = CAudioBufferArray::NewL(iRTPSendSource, KSendBucketSize, encodedBufferSize, iMaxMTULength, rtpHeaderLength, iFrameLength);
1.199 +
1.200 + //determine the payload header
1.201 + switch(const_cast<TFourCC&>(iA2dpAudioCodecConfiguration->HeadsetCodecDataType()).FourCC())
1.202 + {
1.203 + case KMMFFourCCCodeSBC:
1.204 + iMediaPayloadHeader.Append(iAudioBufferArray->NumberOfFramesPerRtpPacket());
1.205 + break;
1.206 + case KMMFFourCCCodeMP3:
1.207 + //RFC2250-section 3.5 MBZ+Frag_Offset
1.208 + //= 4 bytes all set to 0
1.209 + iMediaPayloadHeader.FillZ(4); //0000
1.210 + break;
1.211 + case KMMFFourCCCodeAAC:
1.212 + break;
1.213 + case KMMFFourCCCodeATRAC3:
1.214 + break;
1.215 + default:
1.216 + //the datatype is a non A2DP datatype
1.217 + //which is not supported so panic
1.218 + Panic(ERTPStreamerInvalidDataType);
1.219 + break;
1.220 + }
1.221 +
1.222 + //get the number of bytes of data sent that was sent to the RTP streamer
1.223 + //that make up one RTP packet
1.224 + //in the case of a codec this is the value pre codec processing
1.225 + if (iCodec)
1.226 + {
1.227 + iNumberOfInputBytesToMakeRTPPacket = iSendBufferSize/iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer();
1.228 + if (iNumberOfInputBytesToMakeRTPPacket%2)
1.229 + {//we have an odd number of bytes
1.230 + iNumberOfInputBytesToMakeRTPPacket++;//round up to next byte
1.231 + }
1.232 + }
1.233 + else
1.234 + {
1.235 + iNumberOfInputBytesToMakeRTPPacket = iAudioBufferArray->InputBytesPerRTPPacket();
1.236 + }
1.237 + //else other codecs not supported
1.238 +
1.239 + //we set the iFrameDuration which is used to trigger the timer
1.240 + //this means that RunL should be called every iFrameDuration and
1.241 + //if an RTP packet is ready to sent then it shall be sent
1.242 + //since there is no control channel back from the headset, the best
1.243 + //we can hope for is to send the data at approx the rate the headset
1.244 + //would expect it and hope that the headset provides it's own approriate
1.245 + //internal buffering
1.246 + //Note that dues to other AOs running the timing is not accurate and
1.247 + //usually slower than the specified time - what is really needed
1.248 + //here is a feedback loop where the initial time interval is somewhat
1.249 + //faster than the calculated time interval and is adjusted against the
1.250 + //system clock and bit rate throughput acordingly so the throughput always
1.251 + //matches the bit rate.
1.252 + iRTPPacketDuration = TTimeIntervalMicroSeconds32(TFrameTimingUtils::FrameDuration(iFrameLength,iBitRate).Int() * iAudioBufferArray->NumberOfFramesPerRtpPacket());
1.253 + RDebug::Printf("RTP Packet Duration = %d mS", iRTPPacketDuration.Int());
1.254 + TInt fastCounterFrequency;
1.255 + HAL::Get(HALData::EFastCounterFrequency,fastCounterFrequency);
1.256 + RDebug::Printf("sys clock timing frequency = %d Hz", fastCounterFrequency);
1.257 + iTimeStampIncrement = TFrameTimingUtils::TimeStampIncrementPerFrame(iA2dpAudioCodecConfiguration->HeadsetCodecDataType(), iFrameLength, iBitRate, iA2dpAudioCodecConfiguration->SampleRate())
1.258 + * iAudioBufferArray->NumberOfFramesPerRtpPacket();
1.259 + RDebug::Printf("Calculated RTP packet time stamp increment = %d",iTimeStampIncrement);
1.260 + RDebug::Printf("FrameLength = %d", iFrameLength);
1.261 + RDebug::Printf("Calculated bitRate = %d", iBitRate);
1.262 + RDebug::Printf("Number of frames per RTP packet = %d", iAudioBufferArray->NumberOfFramesPerRtpPacket());
1.263 + RDebug::Printf("Number of RTP packets per audio buffer = %d", iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer());
1.264 + RDebug::Printf("Sample rate = %d", iA2dpAudioCodecConfiguration->SampleRate());
1.265 + }
1.266 +
1.267 +
1.268 +/**
1.269 +Internal function to pass the pcm16 audio data in aData and use the codec
1.270 +to process the data back in aPayload
1.271 +
1.272 +@return the number of source bytes processed
1.273 +*/
1.274 +TUint CActiveRTPStreamer::CodecProcessPayloadL(const TDesC8& aData,TDes8& aPayload)
1.275 + {
1.276 + TPtr8 srcBufferPtr(const_cast<TUint8*>(aData.Ptr()),aData.Length());
1.277 + srcBufferPtr.SetLength(aData.Length());
1.278 + //+1 -1 to skip SBC media payload header
1.279 + TPtr8 dstBufferPtr(const_cast<TUint8*>(aPayload.Ptr()+1),aPayload.MaxLength()-1);
1.280 + CMMFPtrBuffer* srcBuffer = CMMFPtrBuffer::NewL(srcBufferPtr);
1.281 + CleanupStack::PushL(srcBuffer);
1.282 + CMMFPtrBuffer* dstBuffer = CMMFPtrBuffer::NewL(dstBufferPtr);
1.283 + CleanupStack::PushL(dstBuffer);
1.284 + TCodecProcessResult result = iCodec->ProcessL(*srcBuffer,*dstBuffer);
1.285 + if (result == TCodecProcessResult::EProcessIncomplete)
1.286 + {
1.287 + User::Leave(KErrArgument);
1.288 + }
1.289 + aPayload.Append(dstBuffer->Data());
1.290 + CleanupStack::PopAndDestroy(dstBuffer);
1.291 + CleanupStack::PopAndDestroy(srcBuffer);
1.292 + return result.iSrcBytesProcessed;
1.293 + }
1.294 +
1.295 +
1.296 +/**
1.297 +This is the main function for CActiveRTPStreamer in that it is the
1.298 +function used to send data to the headset over RTP.
1.299 +The function is asynchronous to the RunL which does the actual sending.
1.300 +The data is stored in the CRtpSendPackets FIFO and will be sent at the
1.301 +next RunL provided the RTP can accept the data. If not it just stays
1.302 +buffered in the CRtpSendPackets FIFO until it can be sent.
1.303 +The request status is completed when the buffer is stored, not when it is sent
1.304 +this is to more closely mimic the behaviour of the sound driver.
1.305 +If adding the buffer to the CRtpSendPackets FIFO causes it to be full
1.306 +then the request status won't be completed until there is space in the FIFO
1.307 +which won't be until a callback from the RTP stack has been received
1.308 +indicating that the CRtpSendPackets FIFO can now discard that entry.
1.309 +Only one Send at a time is accepted ie the request status
1.310 +of the previous send must be completed before Send can be called again.
1.311 +To simplify the software and improve performance, fixed sized buffers are assumed.ie
1.312 +the buffer length is only calculated once on the first frame and when the settings
1.313 +change.
1.314 +
1.315 +@param aData The data to be sent to the headset. This may go via
1.316 +a codec eg if the data is pcm16 or sent directly to the headset if the data is SBC,mp3,AAC,ATRAC3
1.317 +It is the responsibility of the client ie CA2dpBTHeadsetAudioInterface to
1.318 +call SetCodecConfiguration first.
1.319 +
1.320 +@param aStatus
1.321 +*/
1.322 +void CActiveRTPStreamer::Send(const TDesC8& aData, TRequestStatus& aStatus)
1.323 + {
1.324 + if (iSendStatus)
1.325 + {
1.326 + __ASSERT_DEBUG((*iSendStatus != KRequestPending),Panic(ERTPStreamerSendNotCompleted));
1.327 + }
1.328 + iSendStatus = &aStatus;
1.329 + *iSendStatus = KRequestPending;
1.330 +
1.331 + if (iUnrecoverableError)
1.332 + {
1.333 + User::RequestComplete(iSendStatus,iUnrecoverableError);
1.334 + return;
1.335 + }
1.336 +
1.337 + if (!iBufferParamsInitialized)
1.338 + {
1.339 + TRAPD(err,InitializeForSendL(aData));
1.340 + if (err)
1.341 + {
1.342 + User::RequestComplete(iSendStatus,err);
1.343 + return;
1.344 + }
1.345 + iBufferParamsInitialized = ETrue;
1.346 + }
1.347 +
1.348 + TUint numberOfRtpPacketsPerAudioBuffer = iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer();
1.349 +
1.350 + if (aData.Size() != iSendBufferSize)
1.351 + {
1.352 + //then we are on the last buffer
1.353 + //in which case we need to recalculate the number of Rtp packets
1.354 + //required to make up the audio frame since the last buffer
1.355 + //is smaller.
1.356 + TUint lastBufferLength = aData.Size();
1.357 + if (iCodec)
1.358 + {
1.359 + lastBufferLength = iA2dpAudioCodecConfiguration->CalculateSBCBufferLength(aData.Size());
1.360 + }
1.361 + //we keep the same number of RTP packets per audio buffer as before
1.362 + TUint numberOfSBCFramesInLastBuffer = lastBufferLength/iFrameLength;
1.363 + TUint numberOfFramesPerRtpPacket = iAudioBufferArray->NumberOfFramesPerRtpPacket();
1.364 +
1.365 + //the devisor below may not always devide without a remainder
1.366 + //which means the last Rtp packet sent will not be full
1.367 + //if we have a remainder then we need another Rtp packet
1.368 + numberOfRtpPacketsPerAudioBuffer = numberOfSBCFramesInLastBuffer/numberOfFramesPerRtpPacket;
1.369 + if (numberOfSBCFramesInLastBuffer%numberOfFramesPerRtpPacket)
1.370 + {
1.371 + numberOfRtpPacketsPerAudioBuffer++;
1.372 + }
1.373 + }
1.374 +
1.375 +
1.376 + CRtpSendPackets* sendPackets = iAudioBufferArray->CurrentAudioBufferRtpSendPackets();
1.377 + TUint srcBytesProcessed = 0;
1.378 + for (TUint i=0; i<numberOfRtpPacketsPerAudioBuffer;i++)
1.379 + {
1.380 + RDebug::Printf("NewRTPPacketReceived %d",User::FastCounter());
1.381 + RRtpSendPacket& sendPacket = sendPackets->Packet(i);
1.382 + sendPacket.SetPayloadType(iPayloadType);
1.383 + sendPacket.SetTimestamp(iTimeStamp);
1.384 + iTimeStamp += iTimeStampIncrement;
1.385 + TDes8& payload = sendPacket.WritePayload();
1.386 + payload.Zero();
1.387 + payload.Append(iMediaPayloadHeader);
1.388 +
1.389 + //aData may have to be sent as multiple packets
1.390 + TUint8* sourceDataOffset = const_cast<TUint8*>(aData.Ptr())+srcBytesProcessed;
1.391 + TPtr8 srcBufferPtr(sourceDataOffset,iNumberOfInputBytesToMakeRTPPacket);
1.392 + TUint srcBytesStillRemaining = aData.Size() - srcBytesProcessed;
1.393 + TUint lengthOfsrcBuffer = iNumberOfInputBytesToMakeRTPPacket;
1.394 + if (srcBytesStillRemaining < lengthOfsrcBuffer )
1.395 + {//probably a last buffer condition or modulo 2 pcm16 rounding condition
1.396 + lengthOfsrcBuffer = srcBytesStillRemaining;
1.397 + }
1.398 + srcBufferPtr.SetLength(lengthOfsrcBuffer);
1.399 +
1.400 + //sanity check - the following should always be true
1.401 + __ASSERT_DEBUG((srcBytesProcessed == iNumberOfInputBytesToMakeRTPPacket*i),Panic(ERTPStreamerBufferProcessingLengthMismatch));
1.402 +
1.403 + if (iCodec)
1.404 + {
1.405 + TRAPD(err,srcBytesProcessed += CodecProcessPayloadL(srcBufferPtr,payload));
1.406 + if (err)
1.407 + {
1.408 + //something has gone wrong so abort streaming
1.409 + User::RequestComplete(iSendStatus,err);
1.410 + return;
1.411 + }
1.412 + }
1.413 + else //no need to process via codec - aData can go straight to the headset
1.414 + {
1.415 + srcBytesProcessed +=lengthOfsrcBuffer;
1.416 + payload.Append(srcBufferPtr);
1.417 + }
1.418 + }// for (TUint i=0; i<iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer();i++)
1.419 + iAudioBufferArray->CurrentAudioBufferReadyToSend();
1.420 + //else we have no more send packets so cannot complete request status
1.421 + //until one of the send packets has been sent and acknowledged.
1.422 +
1.423 +
1.424 + //we'll send an event to ourselves and either send the packet if we can
1.425 + //we could complete the iSendStatus TRequestStatus here before returing
1.426 + //from the Send but we won't in order to more closely mimic the existing
1.427 + // sound driver PlayData behaviour
1.428 + //if there is already a request active then it will be the timer
1.429 + //ie this will effectively kick things off if the timer is not running
1.430 + TRequestStatus* stat = &iStatus;
1.431 + if (!IsActive())
1.432 + {
1.433 + User::RequestComplete(stat, KErrNone);
1.434 + SetActive();
1.435 + }
1.436 + }
1.437 +
1.438 +
1.439 +/**
1.440 +Function to stop further internally buffered packets being sent to the headset
1.441 +*/
1.442 +void CActiveRTPStreamer::Pause()
1.443 + {
1.444 + iPaused = ETrue;
1.445 + Cancel();
1.446 + }
1.447 +
1.448 +
1.449 +/**
1.450 +Function called after pause to resume sending buffers to the headset
1.451 +*/
1.452 +void CActiveRTPStreamer::Resume()
1.453 + {
1.454 + if (iPaused)
1.455 + {
1.456 + iPaused = EFalse;
1.457 + TRequestStatus* stat = &iStatus;
1.458 + if (!IsActive())
1.459 + {
1.460 + User::RequestComplete(stat, KErrNone);
1.461 + SetActive();
1.462 + }
1.463 + }
1.464 + }
1.465 +
1.466 +
1.467 +/**
1.468 +Function called from CA2dpBTHeadsetAudioInterface::CancelPlayData()
1.469 +Used to cancel an outstanding status request for a Send()
1.470 +*/
1.471 +void CActiveRTPStreamer::CancelLastSendBuffer()
1.472 + {
1.473 + if (iSendStatus)
1.474 + {
1.475 + if (*iSendStatus == KRequestPending)//make sure there is a pending request to cancel
1.476 + {
1.477 + iAudioBufferArray->CancelMostRecentAudioBuffer(!iRtpCanSend);
1.478 + User::RequestComplete(iSendStatus, KErrCancel);
1.479 + }
1.480 + }
1.481 + }
1.482 +
1.483 +
1.484 +/**
1.485 +Function to flush out the bufferes stored in CRtpSenPackets
1.486 +*/
1.487 +void CActiveRTPStreamer::FlushPendingSendBuffers()
1.488 + {
1.489 + iAudioBufferArray->FlushPendingPackets();
1.490 +
1.491 + if(iCodec)
1.492 + {//flush out codec cache
1.493 + TRAP_IGNORE(iCodec->ResetL());
1.494 + }
1.495 + }
1.496 +
1.497 +
1.498 +/**
1.499 +Function to return total number of bytes sent prior to codec processing
1.500 +ie bytes of pcm16 not SBC
1.501 +Note this the number of bytes sent is only updated when the packet
1.502 +has been acknowledged as being sent correctly by the RTP stack
1.503 +ie this value will always be slightly less than the bytes sent in Send()
1.504 +*/
1.505 +TUint CActiveRTPStreamer::BytesSent() const
1.506 + {
1.507 + return iBytesSent;
1.508 + }
1.509 +
1.510 +
1.511 +/**
1.512 +Function to reset the number of bytes sent
1.513 +*/
1.514 +void CActiveRTPStreamer::ResetBytesSent()
1.515 + {
1.516 + iBytesSent = 0;
1.517 + }
1.518 +
1.519 +
1.520 +/**
1.521 +The RunL is called every frame duration interval.
1.522 +It checks to see if there are any packets to be sent to the headset
1.523 +and if so send it.
1.524 +One issue to be resolved at integration testing is if there are no packets
1.525 +to send then this is analogous to a KErrUnderflow condition on the
1.526 +sound driver. Do we need to mimic this behaviour for the a2dp interface?
1.527 +
1.528 +The Send request status is completed if there is room in the CRtpSendPackets
1.529 +for another buffer.
1.530 +*/
1.531 +void CActiveRTPStreamer::RunL()
1.532 + {
1.533 + if ((iPaused)||(!iAudioBufferArray))
1.534 + {
1.535 + return;
1.536 + }
1.537 +
1.538 + if(iRtpCanSend && iAudioBufferArray->NumberOfAudioBuffersReadyToSend())
1.539 + {
1.540 + RRtpSendPacket& sendPacket = iAudioBufferArray->CurrentSendPacket();
1.541 + sendPacket.Send();
1.542 + iRtpCanSend = EFalse; //have to wait for callback before we can send again
1.543 + }
1.544 +
1.545 + if (iSendStatus)
1.546 + {
1.547 + if ((iAudioBufferArray->NumberOfAudioBuffersReadyToSend() < KSendBucketSize)
1.548 + &&(*iSendStatus == KRequestPending))
1.549 + {//still some free packets to fill so complete request status
1.550 + User::RequestComplete(iSendStatus, KErrNone);
1.551 + iSendStatus = NULL;
1.552 + }
1.553 + //else if the iRtpSendPackets FIFO is full then we can't complete
1.554 + //the request status until we've had an ERtpSendSucceeded event
1.555 + }
1.556 + //are there any more buffers that are ready to send?
1.557 + //if so then send the next packet after a time delay
1.558 + //keep calling this RunL every frame duration till as long as we have packets to send
1.559 + //if there are no packets ready to send then we need to wait
1.560 + //for another call to Send();
1.561 + if (iAudioBufferArray->NumberOfAudioBuffersReadyToSend())
1.562 + {//there are packets ready to send so fire off next RunL after one RTP packet duration
1.563 + RDebug::Printf("RTPPacket Sent %d",User::FastCounter());
1.564 + After(iRTPPacketDuration);
1.565 + }
1.566 + }
1.567 +
1.568 +
1.569 +/**
1.570 +Cancel
1.571 +*/
1.572 +void CActiveRTPStreamer::DoCancel()
1.573 + {
1.574 + CTimer::DoCancel();
1.575 + CompleteSendRequestStatus(KErrCancel);
1.576 + }
1.577 +
1.578 +
1.579 +/**
1.580 +Utility function to complete Send TRequestStatus with aError
1.581 +*/
1.582 +void CActiveRTPStreamer::CompleteSendRequestStatus(TInt aError)
1.583 + {
1.584 + if (iSendStatus)
1.585 + {
1.586 + if (*iSendStatus == KRequestPending)
1.587 + {
1.588 + User::RequestComplete(iSendStatus, aError);
1.589 + }
1.590 + }
1.591 + }
1.592 +
1.593 +
1.594 +/**
1.595 +Called by RTP stack when a packet has been sent
1.596 +If the packet was sent ok then complete the iSendStatus if it is pending
1.597 +and update the number of bytes sent
1.598 +If the packet was not sent ok then the error is regarded as unrecoverable
1.599 +since this should not happen. If it does happen then the CA2dpBTHeadsetAudioInterface
1.600 +is informed. If there is an outstanding Send TRequestStatus then this is
1.601 +completed with KErrCommsFrame. Not sure if this is the most appropriate error code?
1.602 +*/
1.603 +void CActiveRTPStreamer::PacketSent(TRtpEventType aEvent)
1.604 + {
1.605 + if (aEvent == ERtpSendSucceeded)
1.606 + {
1.607 + RDebug::Printf("Sent RTPPacket Acknowledged %d",User::FastCounter());
1.608 + TBool entireAudioBufferSent = EFalse;
1.609 + iAudioBufferArray->CurrentSendPacketSent(entireAudioBufferSent);
1.610 + //check if there is an outstanding send request status
1.611 + //we can only complete the send request status if all the
1.612 + //RTP packets in the audio buffer have been sent.
1.613 + if (entireAudioBufferSent)
1.614 + {
1.615 + CompleteSendRequestStatus(KErrNone);
1.616 + }
1.617 + iRtpCanSend = ETrue;
1.618 + iBytesSent += iNumberOfInputBytesToMakeRTPPacket;
1.619 + }
1.620 + else if (aEvent == ERtpSendFail)
1.621 + {
1.622 + //if we fail to send the packet then chances are something
1.623 + //has gone wrong that may not be recoverable
1.624 + //so we will complete the request status and halt further streaming
1.625 + //some testing may be required to see if it is possible to
1.626 + //recover in which case the packet could be sent again
1.627 + iUnrecoverableError = KErrCommsFrame;//probably the nearest error code
1.628 + CompleteSendRequestStatus(iUnrecoverableError);
1.629 + //inform iRTPStreamerObserver ie the CA2dpBTHeadsetAudioInterface
1.630 + //this will initiate a GAVDP state machine reset which will destroy the CActiveRTPStreamer
1.631 + iRTPStreamerObserver.RTPStreamerEvent(iUnrecoverableError);
1.632 + }
1.633 + else
1.634 + {//we've not registered for any other events so this shouldn't happen
1.635 + Panic(ERTPStreamerUnexpectedEvent);
1.636 + }
1.637 + }
1.638 +
1.639 +
1.640 +/**
1.641 +Called by RTP stack when some sort of general error has occured
1.642 +eg switching off the headset, or the headset going out of range
1.643 +The CA2dpBTHeadsetAudioInterface is informed.
1.644 +*/
1.645 +void CActiveRTPStreamer::RTPSessionEvent(const TRtpEvent& aEvent)
1.646 + {
1.647 + switch(aEvent.Type())
1.648 + {
1.649 + case ERtpSessionFail:
1.650 + iUnrecoverableError = KErrDisconnected;
1.651 + break;
1.652 + case ERtpBufferOverflow:
1.653 + iUnrecoverableError = KErrOverflow;
1.654 + break;
1.655 + case ERtpUndersizedPacket:
1.656 + iUnrecoverableError = KErrCommsFrame;
1.657 + break;
1.658 + default:
1.659 + Panic(ERTPStreamerRTPEventError); //we haven't registered for anything else
1.660 + break;
1.661 + }
1.662 +
1.663 + //complete outstanding Send (CA2dpBTHeadsetAudioInterface::PlayData) request status
1.664 + CompleteSendRequestStatus(iUnrecoverableError);
1.665 + //inform CA2dpBTHeadsetAudioInterface
1.666 + iRTPStreamerObserver.RTPStreamerEvent(iUnrecoverableError);
1.667 + }
1.668 +
1.669 +
1.670 +/**
1.671 +Static callback from RTP stack
1.672 +*/
1.673 +void CActiveRTPStreamer::RTPSendSourceCallback(CActiveRTPStreamer* aStreamer, const TRtpEvent& aEvent)
1.674 + {
1.675 + __ASSERT_DEBUG((aEvent.IsSendSourceEvent()),Panic(ERTPStreamerRTPEventError));
1.676 + __ASSERT_DEBUG((aEvent.SendSource() == aStreamer->iRTPSendSource),Panic(ERTPStreamerRTPEventError));
1.677 + // for now assume it was sending complete
1.678 + // do next bit
1.679 + aStreamer->PacketSent(aEvent.Type());
1.680 + }
1.681 +
1.682 +
1.683 +/**
1.684 +Static callback from RTP stack
1.685 +*/
1.686 +void CActiveRTPStreamer::RTPCallback(CActiveRTPStreamer* aStreamer, const TRtpEvent& aEvent)
1.687 + {
1.688 + __ASSERT_DEBUG((aEvent.IsSessionEvent()),Panic(ERTPStreamerRTPEventError));
1.689 + __ASSERT_DEBUG((aEvent.Session() == aStreamer->iRTPSession),Panic(ERTPStreamerRTPEventError));
1.690 +
1.691 + aStreamer->RTPSessionEvent(aEvent);
1.692 + }