os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/AudioBufferArray.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include "AudioBufferArray.h"
sl@0
    17
#include "BtSBCFrameParameters.h"
sl@0
    18
#include "A2dpCodecUtilities.h"
sl@0
    19
sl@0
    20
/**
sl@0
    21
Audio Buffer Array Panics
sl@0
    22
**/
sl@0
    23
enum TAudioBufferArrayPanic
sl@0
    24
	{
sl@0
    25
	EAudioBufferArrayIncompleteFrame, //0
sl@0
    26
	EAudioBufferArrayMiscount, //1
sl@0
    27
	EAudioBufferArrayNonA2dpDataType, //2
sl@0
    28
	EAudioBufferArrayNoRTPPacketsPerAudioBuffer //3
sl@0
    29
	};
sl@0
    30
sl@0
    31
sl@0
    32
static void Panic(TAudioBufferArrayPanic aPanic)
sl@0
    33
// Panic client
sl@0
    34
	{
sl@0
    35
	_LIT(KAudioBufferArrayPanicName, "A2DP Audio Buf Panic");
sl@0
    36
	User::Panic(KAudioBufferArrayPanicName, aPanic);
sl@0
    37
	}
sl@0
    38
	
sl@0
    39
sl@0
    40
/**
sl@0
    41
Creates a CRtpSendPackets array of RRtpSendPackets
sl@0
    42
sl@0
    43
@param aRtpSendSource
sl@0
    44
@param aNumberOfPackets this is the number of RRtpSendPackets stored in
sl@0
    45
the array
sl@0
    46
*/	
sl@0
    47
CRtpSendPackets* CRtpSendPackets::NewL(RRtpSendSource& aRtpSendSource, TUint aNumberOfPackets)
sl@0
    48
	{
sl@0
    49
	CRtpSendPackets* self = new (ELeave) CRtpSendPackets ();
sl@0
    50
	CleanupStack::PushL(self);
sl@0
    51
	self->ConstructL(aRtpSendSource, aNumberOfPackets);
sl@0
    52
	CleanupStack::Pop(self);
sl@0
    53
	return self;
sl@0
    54
	}
sl@0
    55
sl@0
    56
	
sl@0
    57
void CRtpSendPackets::ConstructL(RRtpSendSource& aRtpSendSource, TUint aNumberOfPackets)
sl@0
    58
	{
sl@0
    59
	// create all the RTP send packets now	
sl@0
    60
	TInt err = KErrNone;
sl@0
    61
	for (TInt i=0; i<aNumberOfPackets; i++)
sl@0
    62
		{
sl@0
    63
		RRtpSendPacket sendPacket = aRtpSendSource.NewSendPacketL();
sl@0
    64
		err = iRtpSendPackets.Append(sendPacket);
sl@0
    65
		if (err)
sl@0
    66
			{//probably run out of memory so need to close the packets
sl@0
    67
			CloseAndResetSendPackets();
sl@0
    68
			User::Leave(err);
sl@0
    69
			}
sl@0
    70
		}
sl@0
    71
	}
sl@0
    72
sl@0
    73
	
sl@0
    74
CRtpSendPackets::~CRtpSendPackets()
sl@0
    75
	{
sl@0
    76
	CloseAndResetSendPackets();
sl@0
    77
	}
sl@0
    78
sl@0
    79
sl@0
    80
void CRtpSendPackets::CloseAndResetSendPackets()
sl@0
    81
	{
sl@0
    82
	// destroy all the RTP send packets now
sl@0
    83
	TUint numberOfSendPackets = iRtpSendPackets.Count();
sl@0
    84
	for (TInt i=0; i<numberOfSendPackets; i++)
sl@0
    85
		{
sl@0
    86
		RRtpSendPacket& p = iRtpSendPackets[i];
sl@0
    87
		p.Close();
sl@0
    88
		}
sl@0
    89
	iRtpSendPackets.Reset();
sl@0
    90
	}
sl@0
    91
sl@0
    92
/**
sl@0
    93
Creates  a FIFO array of audio buffers stored as CRtpSendPackets
sl@0
    94
The paramers passed in are used to determine the size and number
sl@0
    95
of RTP packets required to store an audio buffer
sl@0
    96
The payload size on aRtpSendSource is set.
sl@0
    97
sl@0
    98
@param aRtpSendSource used to create the send packets that contain
sl@0
    99
the audio buffers.  The payload size is set on the aRtpSendSource to
sl@0
   100
a value calculated from the other parameters
sl@0
   101
@param aNumberOfAudioBuffers this is the number of audio buffers
sl@0
   102
stored in the FIFO
sl@0
   103
@param aAudioBufferLength this is the length of the audio buffer that needs
sl@0
   104
to be sent to the headset ie buffer size after SBC processing in the case of SBC
sl@0
   105
@param aMTULength this is the max data length allowing for the restriction imposed
sl@0
   106
by the underlying MTU bearer ie bluetooth and the headset.
sl@0
   107
@param aTotalRTPHeaderLength the RTP header length including the 
sl@0
   108
RTP media payload header ie RTP header length + media payload header length
sl@0
   109
@param aFrameLength 
sl@0
   110
*/	
sl@0
   111
CAudioBufferArray* CAudioBufferArray::NewL(RRtpSendSource& aRtpSendSource, 
sl@0
   112
									TUint aNumberOfAudioBuffers, 
sl@0
   113
									TUint aAudioBufferLength, 
sl@0
   114
									TUint aMTULength, 
sl@0
   115
								    TUint aTotalRTPHeaderLength,
sl@0
   116
									TUint aFrameLength)
sl@0
   117
	{
sl@0
   118
	CAudioBufferArray* self = new (ELeave) CAudioBufferArray();
sl@0
   119
	CleanupStack::PushL(self);
sl@0
   120
	self->ConstructL(aRtpSendSource, aNumberOfAudioBuffers, aAudioBufferLength, aMTULength, aTotalRTPHeaderLength, aFrameLength);
sl@0
   121
	CleanupStack::Pop(self);
sl@0
   122
	return self;
sl@0
   123
	}
sl@0
   124
sl@0
   125
sl@0
   126
void CAudioBufferArray::ConstructL(RRtpSendSource& aRtpSendSource,
sl@0
   127
						TUint aNumberOfAudioBuffers,
sl@0
   128
						TUint aAudioBufferLength,
sl@0
   129
						TUint aMTULength,
sl@0
   130
						TUint aTotalRTPHeaderLength,
sl@0
   131
						TUint aFrameLength)
sl@0
   132
	{
sl@0
   133
	//the buffer should always contain an intiger number of audio frames
sl@0
   134
	//the following ASSERT_DEBUG should be present but is commented out as the RVCT 
sl@0
   135
	//compiler generates a warning
sl@0
   136
	//__ASSERT_DEBUG(!(aAudioBufferLength%aFrameLength),EAudioBufferArrayIncompleteFrame);
sl@0
   137
	
sl@0
   138
	//calculate the number of frames in the audio buffer size and if 
sl@0
   139
	//more than 15 frames then calculate the highest common factor and use this 
sl@0
   140
	//calculate the frames length
sl@0
   141
	iFrameLength = aFrameLength;
sl@0
   142
sl@0
   143
	//calculate the total number of frames in the buffer
sl@0
   144
	TUint numberOfFramesPerAudioBuffer = aAudioBufferLength/iFrameLength;
sl@0
   145
	//for now set the number of audio frames in an RTP packet to the total
sl@0
   146
	iNumberOfFramesPerRtpPacket = numberOfFramesPerAudioBuffer;
sl@0
   147
	
sl@0
   148
	TUint lengthOfAudioDataInRtpPacket = 0;
sl@0
   149
	TInt usableRTPPayloadLength = aMTULength-aTotalRTPHeaderLength;
sl@0
   150
	
sl@0
   151
	//check whether all the audio frames will actually fit into one RTP packet
sl@0
   152
	if ((numberOfFramesPerAudioBuffer > KMaxNumberOfSBCFramesPerRTPPacket)||((aAudioBufferLength+iFrameLength)>usableRTPPayloadLength))//+iFrameLength in case of cached frame
sl@0
   153
		{
sl@0
   154
		//we cannot get all the audio frames into a single RTP packet
sl@0
   155
		//for SBC only a max of 15 SBC frames allowed per packet
sl@0
   156
		//if the buffer size exceeds 15 frames and/or is too large
sl@0
   157
		//for the underlying MTU size then we need to break
sl@0
   158
		//the buffer into buffers of less then 16 frames.
sl@0
   159
		//for non SBC the frames are generaly larger so we'll keep
sl@0
   160
		//the 15 for now even for non SBC
sl@0
   161
		//we need to calculate how may frames should go into
sl@0
   162
		//each RTP packet and how many RTP packets we need to send a
sl@0
   163
		//complete audio buffer
sl@0
   164
		//we are going to calculate such that every RTP packet
sl@0
   165
		//has the same number of frames
sl@0
   166
		//note that if we are using non SBC then the frame size tends to be larger
sl@0
   167
		//so the MTU limit is likely to be the dominant factor
sl@0
   168
		//although in principle this code should only use the 15 frame limit for
sl@0
   169
		//for SBC
sl@0
   170
		iNumberOfFramesPerRtpPacket = 0; 
sl@0
   171
		
sl@0
   172
		
sl@0
   173
		//only a max of 15 SBC frames allowed per packet
sl@0
   174
		//if the buffer size exceeds 15 frames then we need to break
sl@0
   175
		//the buffer into buffers of less then 16 frames.
sl@0
   176
		//so find HCF 
sl@0
   177
		//-1 for cached frames ie if iNumberOfFramesPerRtpPacket
sl@0
   178
		//was the same as KMaxNumberOfSBCFramesPerRTPPacket and we got a cached frame
sl@0
   179
		//then we would blow the limit
sl@0
   180
		for (TUint i=KMaxNumberOfSBCFramesPerRTPPacket-1; i; i--)
sl@0
   181
			{
sl@0
   182
			if (!(numberOfFramesPerAudioBuffer%i))
sl@0
   183
				{
sl@0
   184
				//check we don't blow the MTU size
sl@0
   185
				if ((i*iFrameLength) <= usableRTPPayloadLength)
sl@0
   186
					{
sl@0
   187
					iNumberOfFramesPerRtpPacket = i;
sl@0
   188
					break;
sl@0
   189
					}
sl@0
   190
				}
sl@0
   191
			}
sl@0
   192
		if (!iNumberOfFramesPerRtpPacket)
sl@0
   193
			{//the frame length was too big for the MTU length
sl@0
   194
			//one frame of audio + one frame of cached audio
sl@0
   195
			//would exceed the length supported by the underlying bearer
sl@0
   196
			//note that the A2DP specification section 4.3.4 does allow
sl@0
   197
			//SBC frames to be fragmented across multiple packets if
sl@0
   198
			//less than one frame, but this ref implementation
sl@0
   199
			//does not support this, since this should be rare.
sl@0
   200
			//this may happen more often for non SBC eg mp3 frames
sl@0
   201
			//but we don't support fragmented frames
sl@0
   202
			User::Leave(KErrTooBig);
sl@0
   203
			}
sl@0
   204
		iNumberOfRtpPacketsPerAudioBuffer = numberOfFramesPerAudioBuffer/iNumberOfFramesPerRtpPacket;
sl@0
   205
		
sl@0
   206
		//this could probably be optimized somewhat such that the
sl@0
   207
		//iInputBytesPerRtpPacket value was such that no caching was required 
sl@0
   208
		//in the codec
sl@0
   209
		
sl@0
   210
		if (!iNumberOfRtpPacketsPerAudioBuffer)//this isn't really necessary or could be ASSERT but needed supress armv5 compiler warning
sl@0
   211
			{
sl@0
   212
			Panic(EAudioBufferArrayNoRTPPacketsPerAudioBuffer);
sl@0
   213
			}
sl@0
   214
			
sl@0
   215
		iInputBytesPerRtpPacket = aAudioBufferLength/iNumberOfRtpPacketsPerAudioBuffer;
sl@0
   216
		if (iInputBytesPerRtpPacket%2)
sl@0
   217
			{//we have an odd number of bytes
sl@0
   218
			iInputBytesPerRtpPacket++;//round up to next byte
sl@0
   219
			}
sl@0
   220
		lengthOfAudioDataInRtpPacket = iNumberOfFramesPerRtpPacket*iFrameLength;
sl@0
   221
		}//if ((numberOfFramesPerAudioBuffer > KMaxNumberOfSBCFramesPerRTPPacket)||((encodedAudioBufferLength+iFrameLength)>aMaxMTULength))
sl@0
   222
	else
sl@0
   223
		{//we can fit the entire buffer in one RTP packet
sl@0
   224
		iNumberOfRtpPacketsPerAudioBuffer = 1;
sl@0
   225
		iInputBytesPerRtpPacket = aAudioBufferLength;
sl@0
   226
		lengthOfAudioDataInRtpPacket = aAudioBufferLength;
sl@0
   227
		}
sl@0
   228
sl@0
   229
	TUint payloadSize = aTotalRTPHeaderLength+lengthOfAudioDataInRtpPacket+iFrameLength;//+ extra framelength for cached frames
sl@0
   230
	aRtpSendSource.SetDefaultPayloadSize(payloadSize);
sl@0
   231
	
sl@0
   232
	//now we have set the payload size we can create the audio buffers
sl@0
   233
	//stored as CRtpSendPackets* 
sl@0
   234
	for (TInt i=0; i<aNumberOfAudioBuffers; i++)
sl@0
   235
		{
sl@0
   236
		CRtpSendPackets* sendPacketArray = CRtpSendPackets::NewL(aRtpSendSource, iNumberOfRtpPacketsPerAudioBuffer);
sl@0
   237
		User::LeaveIfError(iAudioBufferArray.Append(sendPacketArray));
sl@0
   238
		}
sl@0
   239
	}
sl@0
   240
sl@0
   241
	
sl@0
   242
CAudioBufferArray::~CAudioBufferArray()
sl@0
   243
	{
sl@0
   244
	// destroy all the audio buffers now
sl@0
   245
	TUint numberOfAudioBuffers = iAudioBufferArray.Count();
sl@0
   246
	for (TInt i=0; i<numberOfAudioBuffers; i++)
sl@0
   247
		{
sl@0
   248
		CRtpSendPackets* sendPacketArray = iAudioBufferArray[i];
sl@0
   249
		delete sendPacketArray;
sl@0
   250
		}
sl@0
   251
	iAudioBufferArray.Close();
sl@0
   252
	}
sl@0
   253
sl@0
   254
sl@0
   255
/**
sl@0
   256
This function is called when the current audio buffer has been filled
sl@0
   257
with audio and is in a state to be sent to the headset
sl@0
   258
The function updates the next audio buffer to fill to the next 
sl@0
   259
available free audio buffer
sl@0
   260
*/
sl@0
   261
void CAudioBufferArray::CurrentAudioBufferReadyToSend()
sl@0
   262
	{
sl@0
   263
	iNextAudioBufferToFill++;
sl@0
   264
	if (iNextAudioBufferToFill >= iAudioBufferArray.Count())
sl@0
   265
		{
sl@0
   266
		iNextAudioBufferToFill = 0;
sl@0
   267
		}
sl@0
   268
	iNumberOfReadyAudioBuffers++;
sl@0
   269
	__ASSERT_DEBUG((iNumberOfReadyAudioBuffers<=iAudioBufferArray.Count()),Panic(EAudioBufferArrayMiscount));
sl@0
   270
	}
sl@0
   271
sl@0
   272
sl@0
   273
/**
sl@0
   274
This function cancels the most recently filled audio buffer that is ready to send
sl@0
   275
The audio buffer corresponds to the audio buffer sent in the last CActiveRTPStreamer::Send()
sl@0
   276
This is used in order to cancel a Send request.
sl@0
   277
It effectively undoes the operation performed in CurrentAudioBufferReadyToSend()
sl@0
   278
so CurrentAudioBufferReadyToSend() must have been called at least once prior.
sl@0
   279
sl@0
   280
@param aSendInProgress set to ETrue if an audio buffer is currently being
sl@0
   281
sent
sl@0
   282
*/
sl@0
   283
void CAudioBufferArray::CancelMostRecentAudioBuffer(TBool aSendInProgress)
sl@0
   284
	{
sl@0
   285
	__ASSERT_DEBUG((iNumberOfReadyAudioBuffers),Panic(EAudioBufferArrayMiscount));
sl@0
   286
	if ((iNumberOfReadyAudioBuffers == 1) && (aSendInProgress))
sl@0
   287
		{//then we only have one ready buffer , which is being sent
sl@0
   288
		//so we want to stop any further sending of the current buffer
sl@0
   289
		__ASSERT_DEBUG((iAudioBufferBeingSent == iNextAudioBufferToFill),Panic(EAudioBufferArrayMiscount));
sl@0
   290
		//now we need prevent any further send packets in the current audio buffer being sent
sl@0
   291
		//the following line of code will force us to move onto the next audio 
sl@0
   292
		//buffer discarding any RTP packets in the current audio buffer
sl@0
   293
		//see CurrentSendPacketSent()
sl@0
   294
		iNextRtpPacketToSend = iNumberOfRtpPacketsPerAudioBuffer-1;
sl@0
   295
		}
sl@0
   296
	else if (iNumberOfReadyAudioBuffers)
sl@0
   297
		{
sl@0
   298
		if (!iNextAudioBufferToFill)
sl@0
   299
			{
sl@0
   300
			iNextAudioBufferToFill = iAudioBufferArray.Count();
sl@0
   301
			}
sl@0
   302
		else
sl@0
   303
			{
sl@0
   304
			iNextAudioBufferToFill--;
sl@0
   305
			}
sl@0
   306
		iNumberOfReadyAudioBuffers--;
sl@0
   307
		}	
sl@0
   308
	}
sl@0
   309
	
sl@0
   310
sl@0
   311
/**
sl@0
   312
This function flushes the pending send packets that are ready to send.
sl@0
   313
Only the current send packet is valid
sl@0
   314
*/
sl@0
   315
void CAudioBufferArray::FlushPendingPackets()	
sl@0
   316
	{
sl@0
   317
	//check that we actually have some audio buffers to flush
sl@0
   318
	if (iNumberOfReadyAudioBuffers > 1)
sl@0
   319
		{
sl@0
   320
		if (iAudioBufferBeingSent >= iAudioBufferArray.Count())
sl@0
   321
			{
sl@0
   322
			iNextAudioBufferToFill = 0;
sl@0
   323
			}
sl@0
   324
		else
sl@0
   325
			{
sl@0
   326
			iNextAudioBufferToFill = iAudioBufferBeingSent+1;
sl@0
   327
			}
sl@0
   328
		iNumberOfReadyAudioBuffers = 1; //the current send packet
sl@0
   329
		}
sl@0
   330
	else if (iNumberOfReadyAudioBuffers == 1)
sl@0
   331
		{
sl@0
   332
		//now we need to flush out the send packets in the current audio buffer being sent
sl@0
   333
		//the following line of code will force us to move onto the next audio 
sl@0
   334
		//buffer discarding any RTP packets in the current audio buffer
sl@0
   335
		//see CurrentSendPacketSent()
sl@0
   336
		iNextRtpPacketToSend = iNumberOfRtpPacketsPerAudioBuffer-1;
sl@0
   337
		}
sl@0
   338
	}
sl@0
   339
sl@0
   340
	
sl@0
   341
/*
sl@0
   342
This function returns the current RTP packet to be sent to the headet
sl@0
   343
if there are no packets that are ready to be sent
sl@0
   344
ie iNumberOfReadyPackets = 0 then the RRtpSendPacket
sl@0
   345
will be invalid.
sl@0
   346
CurrentSendPacketSent() needs to be called when a send packet has been
sl@0
   347
acknowledged as being sent by the RTP stack
sl@0
   348
*/	
sl@0
   349
RRtpSendPacket& CAudioBufferArray::CurrentSendPacket()
sl@0
   350
	{
sl@0
   351
	CRtpSendPackets* currentSendAudioBuffer = iAudioBufferArray[iAudioBufferBeingSent];
sl@0
   352
	return currentSendAudioBuffer->Packet(iNextRtpPacketToSend);
sl@0
   353
	}	
sl@0
   354
sl@0
   355
sl@0
   356
/*
sl@0
   357
This function is called when the RTP module has made the callback indicating that the 
sl@0
   358
current send packet has been sent.
sl@0
   359
The function updates the current send packet to the next packet to be sent
sl@0
   360
sl@0
   361
@param aEntireAudioBufferSent this is set to true if the 
sl@0
   362
current entire audio buffer has been sent.  The RTPStreamer uses
sl@0
   363
this information to determine whether to complete the send request status
sl@0
   364
*/	
sl@0
   365
void CAudioBufferArray::CurrentSendPacketSent(TBool& aEntireAudioBufferSent)
sl@0
   366
	{
sl@0
   367
	aEntireAudioBufferSent = EFalse;
sl@0
   368
	if (iNumberOfReadyAudioBuffers)//this could be 0 if the current packet sent was sent and subsequently cancelled
sl@0
   369
		{
sl@0
   370
		iNextRtpPacketToSend++;
sl@0
   371
		if (iNextRtpPacketToSend >= iNumberOfRtpPacketsPerAudioBuffer)
sl@0
   372
			{//then we have sent all the RTP packets in the current audio buffer
sl@0
   373
			iNextRtpPacketToSend = 0;
sl@0
   374
			iAudioBufferBeingSent++; //we've finished with this audio buffer so move onto the next one
sl@0
   375
			//do something to show we are finished with audio buffer and complete request status
sl@0
   376
			if (iAudioBufferBeingSent >= iAudioBufferArray.Count())
sl@0
   377
				{
sl@0
   378
				iAudioBufferBeingSent = 0;
sl@0
   379
				}
sl@0
   380
			iNumberOfReadyAudioBuffers--;
sl@0
   381
			aEntireAudioBufferSent = ETrue;	
sl@0
   382
			}		
sl@0
   383
		}
sl@0
   384
	//else if iNumberOfReadyAudioBuffers = 0 then the packet must have been canceled so do nothing
sl@0
   385
	__ASSERT_DEBUG((iNumberOfReadyAudioBuffers<=iAudioBufferArray.Count()),Panic(EAudioBufferArrayMiscount));//check underflow
sl@0
   386
	}
sl@0
   387
	
sl@0
   388
sl@0
   389
sl@0
   390
sl@0
   391
sl@0
   392
sl@0
   393
sl@0
   394
	
sl@0
   395
sl@0
   396
sl@0
   397
sl@0
   398
sl@0
   399
sl@0
   400
sl@0
   401
	
sl@0
   402