|
1 /* |
|
2 * Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Contains an implementation of CBTAudioStreamSenderSBC class. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "btaudiostreamsendersbc.h" |
|
20 #include "btaudiostreamerdebug.h" |
|
21 |
|
22 const TInt KA2DPMediaPacketHeaderLength = 1; |
|
23 const TInt KA2DPMediaPacketHeaderIndex = 0; |
|
24 const TInt KRTPHeaderLength = 12; |
|
25 |
|
26 // ======== MEMBER FUNCTIONS ======== |
|
27 |
|
28 // --------------------------------------------------------------------------- |
|
29 // Constructor. |
|
30 // --------------------------------------------------------------------------- |
|
31 // |
|
32 CBTAudioStreamSenderSBC::CBTAudioStreamSenderSBC(MBTAudioStreamSenderObserver& aObserver, RRtpSession& aSession): |
|
33 CBTAudioStreamSender(aObserver, aSession) |
|
34 { |
|
35 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CBTAudioStreamSenderSBC() ->"))); |
|
36 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CBTAudioStreamSenderSBC() <-"))); |
|
37 } |
|
38 |
|
39 // --------------------------------------------------------------------------- |
|
40 // Factory method. |
|
41 // --------------------------------------------------------------------------- |
|
42 // |
|
43 /*static*/ CBTAudioStreamSenderSBC* CBTAudioStreamSenderSBC::NewL(MBTAudioStreamSenderObserver& aObserver, RRtpSession& aSession) |
|
44 { |
|
45 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::NewL() ->"))); |
|
46 |
|
47 CBTAudioStreamSenderSBC* self = new (ELeave) CBTAudioStreamSenderSBC(aObserver, aSession); |
|
48 CleanupStack::PushL(self); |
|
49 self->ConstructL(); |
|
50 CleanupStack::Pop(self); |
|
51 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::NewL() <-"))); |
|
52 return self; |
|
53 } |
|
54 |
|
55 // --------------------------------------------------------------------------- |
|
56 // Destructor. |
|
57 // --------------------------------------------------------------------------- |
|
58 // |
|
59 CBTAudioStreamSenderSBC::~CBTAudioStreamSenderSBC() |
|
60 { |
|
61 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::~CBTAudioStreamSenderSBC() ->"))); |
|
62 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::~CBTAudioStreamSenderSBC() <-"))); |
|
63 } |
|
64 |
|
65 // --------------------------------------------------------------------------- |
|
66 // From class CBTAudioStreamSender. |
|
67 // This method stores the frames to the frame buffer and |
|
68 // when we have enough frames. |
|
69 // --------------------------------------------------------------------------- |
|
70 // |
|
71 TInt CBTAudioStreamSenderSBC::AddHeaderToSendPacket(TPtr8& aPayloadDesC) |
|
72 { |
|
73 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddHeaderToSendPacket() ->"))); |
|
74 aPayloadDesC[KA2DPMediaPacketHeaderIndex] = iNumOfFramesInSendPacket; |
|
75 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddHeaderToSendPacket() <-"))); |
|
76 return KErrNone; |
|
77 } |
|
78 |
|
79 // --------------------------------------------------------------------------- |
|
80 // From class CBTAudioStreamSender. |
|
81 // This method stores the frames to the frame buffer and |
|
82 // when we have enough frames. |
|
83 // --------------------------------------------------------------------------- |
|
84 // |
|
85 TInt CBTAudioStreamSenderSBC::AddBufferToSendPacket(const TDesC8& aBuffer) |
|
86 { |
|
87 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddBufferToSendPacket() ->"))); |
|
88 // Copy data from the buffer to the outgoing packet. |
|
89 // The return code means how many frames can still fit in the SendPacket. |
|
90 // - If there's more space, the value > 0. In this case we need more data. |
|
91 // - If the buffer is full and all data was consumed, the value == 0. In this case the packet must be sent. |
|
92 // - 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. |
|
93 |
|
94 // Calculate how many frames there's left in the buffer. Note that iFrameLength must always be greater than zero. |
|
95 TInt numOfFramesLeftInBuffer = (aBuffer.Length() / iFrameLength) - iNumOfFramesAlreadyMoved ; |
|
96 |
|
97 // If the whole buffer can fit in packet, move it completely, otherwise move as many frames as can fit. |
|
98 TInt numOfFramesToMove = numOfFramesLeftInBuffer <= iMaxNumOfFrames - iNumOfFramesInSendPacket ? |
|
99 numOfFramesLeftInBuffer : |
|
100 iMaxNumOfFrames - iNumOfFramesInSendPacket; |
|
101 |
|
102 // Some traces for seeing what's going on. |
|
103 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Filling sendpacket..."))); |
|
104 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames can fit in packet."), iMaxNumOfFrames)); |
|
105 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames have already been moved from current buffer to sendpacket."), iNumOfFramesAlreadyMoved)); |
|
106 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames left to move from current buffer."), numOfFramesLeftInBuffer)); |
|
107 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames already in current packet."), iNumOfFramesInSendPacket)); |
|
108 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t => Moving %d frames."), numOfFramesToMove)); |
|
109 |
|
110 // Move the number of frames calculated above to the packet: |
|
111 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t replacing sendpacket content from %d, length is %d..."), KA2DPMediaPacketHeaderLength + iNumOfFramesInSendPacket * iFrameLength, numOfFramesToMove * iFrameLength)); |
|
112 |
|
113 // Make the ptrNextFrameInBuffer point to the first frame that hasn't been moved. |
|
114 const TUint8 * ptrNextFrameInBuffer = aBuffer.Ptr() + iNumOfFramesAlreadyMoved * iFrameLength; |
|
115 memcpy((void *)iPtrEndOfPayload, (void *)ptrNextFrameInBuffer, numOfFramesToMove * iFrameLength); |
|
116 iPtrEndOfPayload += numOfFramesToMove * iFrameLength; |
|
117 ptrNextFrameInBuffer += numOfFramesToMove * iFrameLength; |
|
118 |
|
119 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t %d frames moved from buffer to packet."), numOfFramesToMove)); |
|
120 |
|
121 // If we have now moved them all, reset the counter, otherwise update it for the next round. |
|
122 iNumOfFramesAlreadyMoved = numOfFramesLeftInBuffer == numOfFramesToMove ? 0 : iNumOfFramesAlreadyMoved + numOfFramesToMove; |
|
123 |
|
124 // update the information needed for building the header later (in sending phase): |
|
125 iNumOfFramesInSendPacket += numOfFramesToMove; |
|
126 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t iNumOfFramesInSendPacket incremented, it is now %d"), iNumOfFramesInSendPacket)); |
|
127 |
|
128 numOfFramesLeftInBuffer -= numOfFramesToMove; |
|
129 |
|
130 // return the number of frames that will still fit in the packet: |
|
131 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t returning: %d"), iMaxNumOfFrames - iNumOfFramesInSendPacket - numOfFramesLeftInBuffer)); |
|
132 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AddBufferToSendPacket() <-"))); |
|
133 return (iMaxNumOfFrames - iNumOfFramesInSendPacket - numOfFramesLeftInBuffer); |
|
134 } |
|
135 |
|
136 // --------------------------------------------------------------------------- |
|
137 // From class CBTAudioStreamSender. |
|
138 // This method stores the frames to the frame buffer and |
|
139 // when we have enough frames. |
|
140 // --------------------------------------------------------------------------- |
|
141 // |
|
142 TInt CBTAudioStreamSenderSBC::PacketSendingCompleted(TPtr8& aPayloadDesC) |
|
143 { |
|
144 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::PacketSendingCompleted() ->"))); |
|
145 iNumOfFramesInSendPacket = 0; |
|
146 iPtrEndOfPayload = aPayloadDesC.Ptr() + KA2DPMediaPacketHeaderLength; |
|
147 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::PacketSendingCompleted() <-"))); |
|
148 return KErrNone; |
|
149 } |
|
150 |
|
151 // --------------------------------------------------------------------------- |
|
152 // From class CBTAudioStreamSender. |
|
153 // This method sets up the sender and calculates the required packet |
|
154 // length according to its own implementation. |
|
155 // --------------------------------------------------------------------------- |
|
156 // |
|
157 TInt CBTAudioStreamSenderSBC::InitSender(RRtpSendPacket& aSendPacket, TPtr8& aPayloadDesC, const TUint aTargetBitrate) |
|
158 { |
|
159 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::InitSender() ->"))); |
|
160 iFrameLength = iNewFrameLength; |
|
161 iMaxNumOfFrames = iSpaceNeededForBuffer / iFrameLength; |
|
162 |
|
163 // Make the descriptor point in the beginning of the send packet. |
|
164 aPayloadDesC.Set(const_cast<TUint8*>(aSendPacket.WritePayload().Ptr()), iSpaceNeededForBuffer, iSpaceNeededForBuffer); |
|
165 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Descriptor inited, space needed: %d bytes."), iSpaceNeededForBuffer)); |
|
166 |
|
167 iPtrEndOfPayload = aPayloadDesC.Ptr() + KA2DPMediaPacketHeaderLength; |
|
168 |
|
169 iNumOfFramesInSendPacket = 0; |
|
170 |
|
171 iTimestampOfFirstFrameInSendPacket = 0; |
|
172 |
|
173 iDurationOfFrame = CalculateFrameDuration(iFrameLength, aTargetBitrate); |
|
174 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t iDurationOfFrame: %d"), iDurationOfFrame)); |
|
175 |
|
176 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::InitSender() <-"))); |
|
177 return KErrNone; |
|
178 } |
|
179 |
|
180 TInt CBTAudioStreamSenderSBC::CalculatePacketLength(TUint aOutboundMTUSize, const TUint aFrameLength) |
|
181 { |
|
182 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculatePacketLength() <-"))); |
|
183 if(aFrameLength > 0) // Must not be zero, and cannot be according to A2DP spec. |
|
184 { |
|
185 iNewFrameLength = aFrameLength; |
|
186 |
|
187 iSpaceNeededForBuffer = ((aOutboundMTUSize - KA2DPMediaPacketHeaderLength - KRTPHeaderLength) / iNewFrameLength) * iNewFrameLength + KA2DPMediaPacketHeaderLength; |
|
188 |
|
189 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculatePacketLength() <-"))); |
|
190 return iSpaceNeededForBuffer; |
|
191 } |
|
192 else |
|
193 { |
|
194 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Length parameter is zero!"))); |
|
195 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculatePacketLength() <-"))); |
|
196 return 0; |
|
197 } |
|
198 } |
|
199 |
|
200 TUint CBTAudioStreamSenderSBC::CalculateFrameDuration(const TUint aFrameLength, const TUint aTargetBitrate) |
|
201 { |
|
202 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculateFrameInterval() ->"))); |
|
203 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::CalculateFrameInterval() <-"))); |
|
204 return static_cast<TUint>(static_cast<TReal>(aFrameLength * 8) / static_cast<TReal>(aTargetBitrate) * 1000000.0); |
|
205 } |
|
206 |
|
207 TUint CBTAudioStreamSenderSBC::MaxFramesPerPacket() |
|
208 { |
|
209 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::FramesPerPacket() ->"))); |
|
210 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::FramesPerPacket() <-"))); |
|
211 return iMaxNumOfFrames; |
|
212 } |
|
213 |
|
214 void CBTAudioStreamSenderSBC::AdjustTimestamp(TInt64& aTimestamp) |
|
215 { |
|
216 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AdjustTimestamp() ->"))); |
|
217 |
|
218 // The buffer has been emptied, but there may be space for additional frames in sendpacket. |
|
219 // So keep the current timestamp until the sendpacket becomes full. |
|
220 if(iNumOfFramesAlreadyMoved == 0) |
|
221 { |
|
222 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t Buffer became empty."))); |
|
223 iTimestampChangeFlag = ETrue; |
|
224 } |
|
225 |
|
226 if(iNumOfFramesInSendPacket == iMaxNumOfFrames) // Adjust the timestamp only when the sendpacket is full. |
|
227 { |
|
228 if(iTimestampChangeFlag != EFalse) |
|
229 { |
|
230 // When the buffer been emptied earlier, take the new timestamp into use and adjust it by the amount of frames we just moved. |
|
231 iTimestampOfFirstFrameInSendPacket = aTimestamp + iDurationOfFrame * iNumOfFramesAlreadyMoved; |
|
232 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t New timestamp %d (low) is in use."), I64LOW(aTimestamp))); |
|
233 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t New timestamp %d (high) is in use."), I64HIGH(aTimestamp))); |
|
234 iTimestampChangeFlag = EFalse; |
|
235 } |
|
236 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Timestamp is %d (low)"), I64LOW(iTimestampOfFirstFrameInSendPacket))); |
|
237 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FPrint(_L("[BTAudioStreamer]\t Timestamp is %d (high)"), I64HIGH(iTimestampOfFirstFrameInSendPacket))); |
|
238 |
|
239 // Use the timestamp first and then do a normal adjustment for the next round. |
|
240 aTimestamp = iTimestampOfFirstFrameInSendPacket; |
|
241 iTimestampOfFirstFrameInSendPacket = iTimestampOfFirstFrameInSendPacket + iMaxNumOfFrames * iDurationOfFrame; |
|
242 } |
|
243 BT_AUDIO_STREAMER_TRACE_OPT( KPRINTFTRACE, FLOG(_L("[BTAudioStreamer]\t CBTAudioStreamSenderSBC::AdjustTimestamp() <-"))); |
|
244 } |