Update contrib.
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include "AudioBufferArray.h"
17 #include "BtSBCFrameParameters.h"
18 #include "A2dpCodecUtilities.h"
21 Audio Buffer Array Panics
23 enum TAudioBufferArrayPanic
25 EAudioBufferArrayIncompleteFrame, //0
26 EAudioBufferArrayMiscount, //1
27 EAudioBufferArrayNonA2dpDataType, //2
28 EAudioBufferArrayNoRTPPacketsPerAudioBuffer //3
32 static void Panic(TAudioBufferArrayPanic aPanic)
35 _LIT(KAudioBufferArrayPanicName, "A2DP Audio Buf Panic");
36 User::Panic(KAudioBufferArrayPanicName, aPanic);
41 Creates a CRtpSendPackets array of RRtpSendPackets
44 @param aNumberOfPackets this is the number of RRtpSendPackets stored in
47 CRtpSendPackets* CRtpSendPackets::NewL(RRtpSendSource& aRtpSendSource, TUint aNumberOfPackets)
49 CRtpSendPackets* self = new (ELeave) CRtpSendPackets ();
50 CleanupStack::PushL(self);
51 self->ConstructL(aRtpSendSource, aNumberOfPackets);
52 CleanupStack::Pop(self);
57 void CRtpSendPackets::ConstructL(RRtpSendSource& aRtpSendSource, TUint aNumberOfPackets)
59 // create all the RTP send packets now
61 for (TInt i=0; i<aNumberOfPackets; i++)
63 RRtpSendPacket sendPacket = aRtpSendSource.NewSendPacketL();
64 err = iRtpSendPackets.Append(sendPacket);
66 {//probably run out of memory so need to close the packets
67 CloseAndResetSendPackets();
74 CRtpSendPackets::~CRtpSendPackets()
76 CloseAndResetSendPackets();
80 void CRtpSendPackets::CloseAndResetSendPackets()
82 // destroy all the RTP send packets now
83 TUint numberOfSendPackets = iRtpSendPackets.Count();
84 for (TInt i=0; i<numberOfSendPackets; i++)
86 RRtpSendPacket& p = iRtpSendPackets[i];
89 iRtpSendPackets.Reset();
93 Creates a FIFO array of audio buffers stored as CRtpSendPackets
94 The paramers passed in are used to determine the size and number
95 of RTP packets required to store an audio buffer
96 The payload size on aRtpSendSource is set.
98 @param aRtpSendSource used to create the send packets that contain
99 the audio buffers. The payload size is set on the aRtpSendSource to
100 a value calculated from the other parameters
101 @param aNumberOfAudioBuffers this is the number of audio buffers
103 @param aAudioBufferLength this is the length of the audio buffer that needs
104 to be sent to the headset ie buffer size after SBC processing in the case of SBC
105 @param aMTULength this is the max data length allowing for the restriction imposed
106 by the underlying MTU bearer ie bluetooth and the headset.
107 @param aTotalRTPHeaderLength the RTP header length including the
108 RTP media payload header ie RTP header length + media payload header length
111 CAudioBufferArray* CAudioBufferArray::NewL(RRtpSendSource& aRtpSendSource,
112 TUint aNumberOfAudioBuffers,
113 TUint aAudioBufferLength,
115 TUint aTotalRTPHeaderLength,
118 CAudioBufferArray* self = new (ELeave) CAudioBufferArray();
119 CleanupStack::PushL(self);
120 self->ConstructL(aRtpSendSource, aNumberOfAudioBuffers, aAudioBufferLength, aMTULength, aTotalRTPHeaderLength, aFrameLength);
121 CleanupStack::Pop(self);
126 void CAudioBufferArray::ConstructL(RRtpSendSource& aRtpSendSource,
127 TUint aNumberOfAudioBuffers,
128 TUint aAudioBufferLength,
130 TUint aTotalRTPHeaderLength,
133 //the buffer should always contain an intiger number of audio frames
134 //the following ASSERT_DEBUG should be present but is commented out as the RVCT
135 //compiler generates a warning
136 //__ASSERT_DEBUG(!(aAudioBufferLength%aFrameLength),EAudioBufferArrayIncompleteFrame);
138 //calculate the number of frames in the audio buffer size and if
139 //more than 15 frames then calculate the highest common factor and use this
140 //calculate the frames length
141 iFrameLength = aFrameLength;
143 //calculate the total number of frames in the buffer
144 TUint numberOfFramesPerAudioBuffer = aAudioBufferLength/iFrameLength;
145 //for now set the number of audio frames in an RTP packet to the total
146 iNumberOfFramesPerRtpPacket = numberOfFramesPerAudioBuffer;
148 TUint lengthOfAudioDataInRtpPacket = 0;
149 TInt usableRTPPayloadLength = aMTULength-aTotalRTPHeaderLength;
151 //check whether all the audio frames will actually fit into one RTP packet
152 if ((numberOfFramesPerAudioBuffer > KMaxNumberOfSBCFramesPerRTPPacket)||((aAudioBufferLength+iFrameLength)>usableRTPPayloadLength))//+iFrameLength in case of cached frame
154 //we cannot get all the audio frames into a single RTP packet
155 //for SBC only a max of 15 SBC frames allowed per packet
156 //if the buffer size exceeds 15 frames and/or is too large
157 //for the underlying MTU size then we need to break
158 //the buffer into buffers of less then 16 frames.
159 //for non SBC the frames are generaly larger so we'll keep
160 //the 15 for now even for non SBC
161 //we need to calculate how may frames should go into
162 //each RTP packet and how many RTP packets we need to send a
163 //complete audio buffer
164 //we are going to calculate such that every RTP packet
165 //has the same number of frames
166 //note that if we are using non SBC then the frame size tends to be larger
167 //so the MTU limit is likely to be the dominant factor
168 //although in principle this code should only use the 15 frame limit for
170 iNumberOfFramesPerRtpPacket = 0;
173 //only a max of 15 SBC frames allowed per packet
174 //if the buffer size exceeds 15 frames then we need to break
175 //the buffer into buffers of less then 16 frames.
177 //-1 for cached frames ie if iNumberOfFramesPerRtpPacket
178 //was the same as KMaxNumberOfSBCFramesPerRTPPacket and we got a cached frame
179 //then we would blow the limit
180 for (TUint i=KMaxNumberOfSBCFramesPerRTPPacket-1; i; i--)
182 if (!(numberOfFramesPerAudioBuffer%i))
184 //check we don't blow the MTU size
185 if ((i*iFrameLength) <= usableRTPPayloadLength)
187 iNumberOfFramesPerRtpPacket = i;
192 if (!iNumberOfFramesPerRtpPacket)
193 {//the frame length was too big for the MTU length
194 //one frame of audio + one frame of cached audio
195 //would exceed the length supported by the underlying bearer
196 //note that the A2DP specification section 4.3.4 does allow
197 //SBC frames to be fragmented across multiple packets if
198 //less than one frame, but this ref implementation
199 //does not support this, since this should be rare.
200 //this may happen more often for non SBC eg mp3 frames
201 //but we don't support fragmented frames
202 User::Leave(KErrTooBig);
204 iNumberOfRtpPacketsPerAudioBuffer = numberOfFramesPerAudioBuffer/iNumberOfFramesPerRtpPacket;
206 //this could probably be optimized somewhat such that the
207 //iInputBytesPerRtpPacket value was such that no caching was required
210 if (!iNumberOfRtpPacketsPerAudioBuffer)//this isn't really necessary or could be ASSERT but needed supress armv5 compiler warning
212 Panic(EAudioBufferArrayNoRTPPacketsPerAudioBuffer);
215 iInputBytesPerRtpPacket = aAudioBufferLength/iNumberOfRtpPacketsPerAudioBuffer;
216 if (iInputBytesPerRtpPacket%2)
217 {//we have an odd number of bytes
218 iInputBytesPerRtpPacket++;//round up to next byte
220 lengthOfAudioDataInRtpPacket = iNumberOfFramesPerRtpPacket*iFrameLength;
221 }//if ((numberOfFramesPerAudioBuffer > KMaxNumberOfSBCFramesPerRTPPacket)||((encodedAudioBufferLength+iFrameLength)>aMaxMTULength))
223 {//we can fit the entire buffer in one RTP packet
224 iNumberOfRtpPacketsPerAudioBuffer = 1;
225 iInputBytesPerRtpPacket = aAudioBufferLength;
226 lengthOfAudioDataInRtpPacket = aAudioBufferLength;
229 TUint payloadSize = aTotalRTPHeaderLength+lengthOfAudioDataInRtpPacket+iFrameLength;//+ extra framelength for cached frames
230 aRtpSendSource.SetDefaultPayloadSize(payloadSize);
232 //now we have set the payload size we can create the audio buffers
233 //stored as CRtpSendPackets*
234 for (TInt i=0; i<aNumberOfAudioBuffers; i++)
236 CRtpSendPackets* sendPacketArray = CRtpSendPackets::NewL(aRtpSendSource, iNumberOfRtpPacketsPerAudioBuffer);
237 User::LeaveIfError(iAudioBufferArray.Append(sendPacketArray));
242 CAudioBufferArray::~CAudioBufferArray()
244 // destroy all the audio buffers now
245 TUint numberOfAudioBuffers = iAudioBufferArray.Count();
246 for (TInt i=0; i<numberOfAudioBuffers; i++)
248 CRtpSendPackets* sendPacketArray = iAudioBufferArray[i];
249 delete sendPacketArray;
251 iAudioBufferArray.Close();
256 This function is called when the current audio buffer has been filled
257 with audio and is in a state to be sent to the headset
258 The function updates the next audio buffer to fill to the next
259 available free audio buffer
261 void CAudioBufferArray::CurrentAudioBufferReadyToSend()
263 iNextAudioBufferToFill++;
264 if (iNextAudioBufferToFill >= iAudioBufferArray.Count())
266 iNextAudioBufferToFill = 0;
268 iNumberOfReadyAudioBuffers++;
269 __ASSERT_DEBUG((iNumberOfReadyAudioBuffers<=iAudioBufferArray.Count()),Panic(EAudioBufferArrayMiscount));
274 This function cancels the most recently filled audio buffer that is ready to send
275 The audio buffer corresponds to the audio buffer sent in the last CActiveRTPStreamer::Send()
276 This is used in order to cancel a Send request.
277 It effectively undoes the operation performed in CurrentAudioBufferReadyToSend()
278 so CurrentAudioBufferReadyToSend() must have been called at least once prior.
280 @param aSendInProgress set to ETrue if an audio buffer is currently being
283 void CAudioBufferArray::CancelMostRecentAudioBuffer(TBool aSendInProgress)
285 __ASSERT_DEBUG((iNumberOfReadyAudioBuffers),Panic(EAudioBufferArrayMiscount));
286 if ((iNumberOfReadyAudioBuffers == 1) && (aSendInProgress))
287 {//then we only have one ready buffer , which is being sent
288 //so we want to stop any further sending of the current buffer
289 __ASSERT_DEBUG((iAudioBufferBeingSent == iNextAudioBufferToFill),Panic(EAudioBufferArrayMiscount));
290 //now we need prevent any further send packets in the current audio buffer being sent
291 //the following line of code will force us to move onto the next audio
292 //buffer discarding any RTP packets in the current audio buffer
293 //see CurrentSendPacketSent()
294 iNextRtpPacketToSend = iNumberOfRtpPacketsPerAudioBuffer-1;
296 else if (iNumberOfReadyAudioBuffers)
298 if (!iNextAudioBufferToFill)
300 iNextAudioBufferToFill = iAudioBufferArray.Count();
304 iNextAudioBufferToFill--;
306 iNumberOfReadyAudioBuffers--;
312 This function flushes the pending send packets that are ready to send.
313 Only the current send packet is valid
315 void CAudioBufferArray::FlushPendingPackets()
317 //check that we actually have some audio buffers to flush
318 if (iNumberOfReadyAudioBuffers > 1)
320 if (iAudioBufferBeingSent >= iAudioBufferArray.Count())
322 iNextAudioBufferToFill = 0;
326 iNextAudioBufferToFill = iAudioBufferBeingSent+1;
328 iNumberOfReadyAudioBuffers = 1; //the current send packet
330 else if (iNumberOfReadyAudioBuffers == 1)
332 //now we need to flush out the send packets in the current audio buffer being sent
333 //the following line of code will force us to move onto the next audio
334 //buffer discarding any RTP packets in the current audio buffer
335 //see CurrentSendPacketSent()
336 iNextRtpPacketToSend = iNumberOfRtpPacketsPerAudioBuffer-1;
342 This function returns the current RTP packet to be sent to the headet
343 if there are no packets that are ready to be sent
344 ie iNumberOfReadyPackets = 0 then the RRtpSendPacket
346 CurrentSendPacketSent() needs to be called when a send packet has been
347 acknowledged as being sent by the RTP stack
349 RRtpSendPacket& CAudioBufferArray::CurrentSendPacket()
351 CRtpSendPackets* currentSendAudioBuffer = iAudioBufferArray[iAudioBufferBeingSent];
352 return currentSendAudioBuffer->Packet(iNextRtpPacketToSend);
357 This function is called when the RTP module has made the callback indicating that the
358 current send packet has been sent.
359 The function updates the current send packet to the next packet to be sent
361 @param aEntireAudioBufferSent this is set to true if the
362 current entire audio buffer has been sent. The RTPStreamer uses
363 this information to determine whether to complete the send request status
365 void CAudioBufferArray::CurrentSendPacketSent(TBool& aEntireAudioBufferSent)
367 aEntireAudioBufferSent = EFalse;
368 if (iNumberOfReadyAudioBuffers)//this could be 0 if the current packet sent was sent and subsequently cancelled
370 iNextRtpPacketToSend++;
371 if (iNextRtpPacketToSend >= iNumberOfRtpPacketsPerAudioBuffer)
372 {//then we have sent all the RTP packets in the current audio buffer
373 iNextRtpPacketToSend = 0;
374 iAudioBufferBeingSent++; //we've finished with this audio buffer so move onto the next one
375 //do something to show we are finished with audio buffer and complete request status
376 if (iAudioBufferBeingSent >= iAudioBufferArray.Count())
378 iAudioBufferBeingSent = 0;
380 iNumberOfReadyAudioBuffers--;
381 aEntireAudioBufferSent = ETrue;
384 //else if iNumberOfReadyAudioBuffers = 0 then the packet must have been canceled so do nothing
385 __ASSERT_DEBUG((iNumberOfReadyAudioBuffers<=iAudioBufferArray.Count()),Panic(EAudioBufferArrayMiscount));//check underflow