1 /* |
|
2 * Copyright (c) 2006-2007 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: ICY flow initiator implementation |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 /* --------------------------------------------------------------------------- |
|
20 * Version history: |
|
21 * Template version: |
|
22 * <ccm_history> |
|
23 * |
|
24 * Version: 3, Tue Mar 11 20:00:00 2008 by Rohit |
|
25 * Ref: |
|
26 * Merged IRv1.0 Engine code changes |
|
27 * |
|
28 * Version: 2, Tue Feb 28 18:00:00 2008 by Rohit/Kranthi |
|
29 * Ref: |
|
30 * Setting RawDataTransferredL() into DataTransferTracker for Byte Counter Impl |
|
31 * |
|
32 * </ccm_history> |
|
33 * ============================================================================ |
|
34 */ |
|
35 |
|
36 #include <e32property.h> |
|
37 #include <es_sock.h> |
|
38 #include <in_sock.h> |
|
39 #include <uriutils.h> |
|
40 |
|
41 #include "iricyflowinitiator.h" |
|
42 #include "irdebug.h" |
|
43 #include "irnetworkcontroller.h" |
|
44 #include "irpubsubkeys.h" |
|
45 #include "irstationconnection.h" |
|
46 #include "irstreamsourceerrors.h" |
|
47 #include "irstreamsourceliterals.h" |
|
48 |
|
49 // Constants |
|
50 const TInt KIRFITimeOutValue = 10000000; |
|
51 const TInt KIRHeaderMaxSize = 256; |
|
52 _LIT8( KIRUriComponentSeparator, "/" ); |
|
53 const TInt KFour = 4; |
|
54 const TInt KSixtyFour=64; |
|
55 const TInt KTwoZeroFourEight=2048; |
|
56 // --------------------------------------------------------------------------- |
|
57 // CIRIcyFlowInitiator::NewL |
|
58 // --------------------------------------------------------------------------- |
|
59 // |
|
60 CIRIcyFlowInitiator* CIRIcyFlowInitiator::NewL( RSocket& aSocket, const TDesC& aUri, |
|
61 CIRStationConnection& aOwner, TChannelInfo& aChannelInfo ) |
|
62 { |
|
63 CIRIcyFlowInitiator* self = new ( ELeave ) CIRIcyFlowInitiator( aSocket, |
|
64 aUri, aOwner, aChannelInfo ); |
|
65 CleanupStack::PushL(self); |
|
66 self->ConstructL(); |
|
67 CleanupStack::Pop(self); |
|
68 return self; |
|
69 } |
|
70 |
|
71 // --------------------------------------------------------------------------- |
|
72 // CIRIcyFlowInitiator::CIRIcyFlowInitiator |
|
73 // --------------------------------------------------------------------------- |
|
74 // |
|
75 CIRIcyFlowInitiator::CIRIcyFlowInitiator( RSocket& aSocket, const TDesC& aUri, |
|
76 CIRStationConnection& aOwner, TChannelInfo& aChannelInfo ) : |
|
77 CActive( CActive::EPriorityStandard ), iState( EIRIdle ), |
|
78 iSocket( aSocket ), iUri( aUri ), iOwner( aOwner ), iChannelInfo( aChannelInfo ) |
|
79 { |
|
80 } |
|
81 |
|
82 // --------------------------------------------------------------------------- |
|
83 // CIRIcyFlowInitiator::ConstructL |
|
84 // --------------------------------------------------------------------------- |
|
85 // |
|
86 void CIRIcyFlowInitiator::ConstructL() |
|
87 { |
|
88 IRLOG_DEBUG( "CIRIcyFlowInitiator::ConstructL." ); |
|
89 CActiveScheduler::Add( this ); |
|
90 iSocketTimer = CIRSocketTimeOutTimer::NewL(CActive::EPriorityHigh,*this); |
|
91 |
|
92 iNetworkControllerHandle = CIRNetworkController::OpenL(); |
|
93 iUAProfString.CreateL( *iNetworkControllerHandle->GetUAProfString() ); |
|
94 |
|
95 iBuffer.CreateL( KIRHeaderMaxSize ); |
|
96 iReadBuffer.CreateL( 1 ); |
|
97 if ( !ExtractUriComponentsL() ) |
|
98 { |
|
99 User::Leave( KErrCorrupt ); |
|
100 } |
|
101 IRLOG_DEBUG( "CIRIcyFlowInitiator::ConstructL - Exiting." ); |
|
102 } |
|
103 |
|
104 // --------------------------------------------------------------------------- |
|
105 // CIRIcyFlowInitiator::~CIRIcyFlowInitiator |
|
106 // --------------------------------------------------------------------------- |
|
107 // |
|
108 CIRIcyFlowInitiator::~CIRIcyFlowInitiator() |
|
109 { |
|
110 Cancel(); |
|
111 iHost.Close(); |
|
112 iPath.Close(); |
|
113 |
|
114 iBuffer.Close(); |
|
115 iReadBuffer.Close(); |
|
116 iUAProfString.Close(); |
|
117 |
|
118 delete iSocketTimer; |
|
119 if(iNetworkControllerHandle) |
|
120 { |
|
121 iNetworkControllerHandle->Close(); |
|
122 } |
|
123 } |
|
124 |
|
125 // --------------------------------------------------------------------------- |
|
126 // CIRIcyFlowInitiator::ExtractUriComponentsL |
|
127 // --------------------------------------------------------------------------- |
|
128 // |
|
129 TBool CIRIcyFlowInitiator::ExtractUriComponentsL() |
|
130 { |
|
131 IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractUriComponentsL" ); |
|
132 |
|
133 TBool retMe = EFalse; |
|
134 |
|
135 if( !UriUtils::HasInvalidChars( iUri ) ) |
|
136 { |
|
137 TUriParser uriParser; |
|
138 uriParser.Parse( iUri ); |
|
139 |
|
140 iHost.Close(); |
|
141 iHost.CreateL( uriParser.Extract( EUriHost ).Size() ); |
|
142 iHost.Copy( uriParser.Extract( EUriHost ) ); |
|
143 iPath.Close(); |
|
144 iPath.CreateL( uriParser.Extract( EUriPath ).Size() ); |
|
145 iPath.Copy( uriParser.Extract( EUriPath ) ); |
|
146 |
|
147 if ( iPath.Length() == 0 ) |
|
148 { |
|
149 iPath.Close(); |
|
150 iPath.CreateL( KIRUriComponentSeparator ); |
|
151 } |
|
152 retMe = ETrue; |
|
153 } |
|
154 IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractUriComponentsL - Exiting." ); |
|
155 return retMe; |
|
156 } |
|
157 |
|
158 // --------------------------------------------------------------------------- |
|
159 // CIRIcyFlowInitiator::RequestFlow |
|
160 // --------------------------------------------------------------------------- |
|
161 // |
|
162 void CIRIcyFlowInitiator::RequestFlow() |
|
163 { |
|
164 IRLOG_DEBUG( "CIRIcyFlowInitiator::RequestFlow" ); |
|
165 Cancel(); |
|
166 |
|
167 iBuffer.ReAlloc(iPath.Length() + iHost.Length() + iUAProfString.Length() |
|
168 + KIcyRequest().Length()); |
|
169 iBuffer.Format( KIcyRequest, &iPath, &iHost, &iUAProfString ); |
|
170 |
|
171 // Cancel any pending timer requests |
|
172 iSocketTimer->Cancel(); |
|
173 iSocketTimer->After( KIRFITimeOutValue ); |
|
174 |
|
175 iState = EIRSending; |
|
176 |
|
177 IRDEBUGCODE( |
|
178 RBuf requestCopy; |
|
179 if ( requestCopy.Create( iBuffer.Length() ) == KErrNone ) |
|
180 { |
|
181 requestCopy.Copy( iBuffer ); |
|
182 IRLOG_DEBUG2( "CIRIcyFlowInitiator::RequestFlow - request= %S", &requestCopy ); |
|
183 requestCopy.Close(); |
|
184 } |
|
185 ) |
|
186 |
|
187 // HTTP GET METHOD sent to server |
|
188 iSocket.Send( iBuffer, 0, iStatus ); |
|
189 SetActive(); |
|
190 IRLOG_DEBUG( "CIRIcyFlowInitiator::RequestFlow - Exiting." ); |
|
191 } |
|
192 |
|
193 // --------------------------------------------------------------------------- |
|
194 // CIRIcyFlowInitiator::RunL |
|
195 // --------------------------------------------------------------------------- |
|
196 // |
|
197 void CIRIcyFlowInitiator::RunL() |
|
198 { |
|
199 IRLOG_INFO3( "CIRIcyFlowInitiator::RunL - iStatus=%d, iState=%d", iStatus.Int(), iState ); |
|
200 |
|
201 if( iStatus == KErrNone ) |
|
202 { |
|
203 switch( iState ) |
|
204 { |
|
205 case EIRSending: |
|
206 iSocketTimer->Cancel(); |
|
207 iSocketTimer->After( KIRFITimeOutValue ); |
|
208 |
|
209 // Byte Counter Impl |
|
210 iNetworkControllerHandle->DataTransferTracker().RawDataTransferredL( |
|
211 iBuffer.Size(),0, MIRDataTransferTracker::EIRTransferCategoryAudio); |
|
212 |
|
213 iBuffer.Zero(); |
|
214 iBuffer.ReAlloc( KIRHeaderMaxSize ); |
|
215 iState = EIRReceiving; |
|
216 iSocket.Read( iReadBuffer, iStatus ); |
|
217 SetActive(); |
|
218 break; |
|
219 case EIRReceiving: |
|
220 iSocketTimer->Cancel(); |
|
221 if ( iBuffer.MaxLength() <= ( iBuffer.Length() + iReadBuffer.Length() ) ) |
|
222 { |
|
223 iBuffer.ReAlloc( iBuffer.MaxLength() + KSixtyFour ); |
|
224 } |
|
225 // Byte Counter Impl |
|
226 iNetworkControllerHandle->DataTransferTracker().RawDataTransferredL( 0, |
|
227 iBuffer.Size(), MIRDataTransferTracker::EIRTransferCategoryAudio); |
|
228 iBuffer.Append(iReadBuffer); |
|
229 iReadBuffer.Zero(); |
|
230 |
|
231 // Check if we got the full header and if not, read more from the socket. |
|
232 if ( iBuffer.Find( KHeaderEnd ) == KErrNotFound ) |
|
233 { |
|
234 // if we have received 2kb's of headers, Then there is propably |
|
235 // some sort error and its time to abort |
|
236 if ( iBuffer.Length() >= KTwoZeroFourEight ) |
|
237 { |
|
238 IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - EIRReceiving. Got 2kb's of headers." ); |
|
239 // Cancel the timer if active |
|
240 iSocketTimer->Cancel(); |
|
241 iOwner.ConnectionError( KIRStreamSourceReadError ); |
|
242 iState = EIRIdle; |
|
243 break; |
|
244 } |
|
245 |
|
246 iSocket.Read( iReadBuffer, iStatus ); |
|
247 SetActive(); |
|
248 iSocketTimer->After( KIRFITimeOutValue ); |
|
249 break; |
|
250 } |
|
251 ParseChannelInfoL(); |
|
252 if ( ValidateChannelServer() ) |
|
253 { |
|
254 TInt bitRateInt(0); |
|
255 TLex8 bitvariable( iChannelInfo.iBitRate ); |
|
256 bitvariable.Val( bitRateInt ); |
|
257 RProperty::Set( KUidActiveInternetRadioApp, |
|
258 KIRPSBitrate, bitRateInt ); |
|
259 iOwner.FlowReady(); |
|
260 iState = EIRFinished; |
|
261 } |
|
262 else |
|
263 { |
|
264 IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - Invalid server" ); |
|
265 iOwner.ConnectionError( KIRStreamSourceInvalidUrl ); |
|
266 iState = EIRIdle; |
|
267 } |
|
268 |
|
269 break; |
|
270 default: |
|
271 __ASSERT_DEBUG( EFalse, User::Invariant() ); |
|
272 break; |
|
273 } |
|
274 } |
|
275 else // An error has occurred |
|
276 { |
|
277 switch( iState ) |
|
278 { |
|
279 case EIRSending: |
|
280 IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - EIRSending" ); |
|
281 // Cancel the timer if active |
|
282 iSocketTimer->Cancel(); |
|
283 // Error in sending data to channel server |
|
284 iOwner.ConnectionError( KIRStreamSourceWriteError ); |
|
285 break; |
|
286 case EIRReceiving: |
|
287 IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - EIRReceiving" ); |
|
288 // Cancel the timer if active |
|
289 iSocketTimer->Cancel(); |
|
290 //Error in response from channel server |
|
291 if( iStatus.Int() == KErrEof ) |
|
292 { |
|
293 iOwner.ConnectionError( KIRStreamSourceNoResponse ); |
|
294 } |
|
295 else |
|
296 { |
|
297 iOwner.ConnectionError( KIRStreamSourceReadError ); |
|
298 } |
|
299 break; |
|
300 default: |
|
301 IRLOG_FATAL2( "CIRIcyFlowInitiator::RunL - Error in unexpected state (%d)", iStatus.Int() ); |
|
302 __ASSERT_DEBUG( EFalse, User::Invariant() ); |
|
303 break; |
|
304 } |
|
305 } |
|
306 IRLOG_DEBUG( "CIRIcyFlowInitiator::RunL - Exiting." ); |
|
307 } |
|
308 |
|
309 // --------------------------------------------------------------------------- |
|
310 // CIRIcyFlowInitiator::RunError |
|
311 // --------------------------------------------------------------------------- |
|
312 // |
|
313 TInt CIRIcyFlowInitiator::RunError( TInt aError ) |
|
314 { |
|
315 IRLOG_ERROR2( "CIRIcyFlowInitiator::RunError - aError=%d", aError ); |
|
316 iOwner.ConnectionError( aError ); |
|
317 return KErrNone; |
|
318 } |
|
319 |
|
320 // --------------------------------------------------------------------------- |
|
321 // CIRIcyFlowInitiator::DoCancel |
|
322 // --------------------------------------------------------------------------- |
|
323 // |
|
324 void CIRIcyFlowInitiator::DoCancel() |
|
325 { |
|
326 IRLOG_DEBUG2( "CIRIcyFlowInitiator::DoCancel - iState = %d.", iState ); |
|
327 iSocket.CancelAll(); |
|
328 iSocketTimer->Cancel(); |
|
329 iState = EIRIdle; |
|
330 } |
|
331 |
|
332 // --------------------------------------------------------------------------- |
|
333 // CIRIcyFlowInitiator::TimerExpired |
|
334 // --------------------------------------------------------------------------- |
|
335 // |
|
336 void CIRIcyFlowInitiator::TimerExpired() |
|
337 { |
|
338 IRLOG_ERROR( "CIRIcyFlowInitiator::TimerExpired." ); |
|
339 Cancel(); |
|
340 iOwner.ConnectionError( KIRStreamSourceTimeOut ); |
|
341 IRLOG_DEBUG( "CIRIcyFlowInitiator::TimerExpired - Exiting." ); |
|
342 } |
|
343 |
|
344 // --------------------------------------------------------------------------- |
|
345 // CIRIcyFlowInitiator::ValidateChannelServer |
|
346 // --------------------------------------------------------------------------- |
|
347 // |
|
348 TBool CIRIcyFlowInitiator::ValidateChannelServer() |
|
349 { |
|
350 IRLOG_DEBUG( "CIRIcyFlowInitiator::ValidateChannelServer" ); |
|
351 TBool retMe = EFalse; |
|
352 |
|
353 if ( iChannelInfo.iContentType.Match(KValidContentType) != KErrNotFound ) |
|
354 { |
|
355 retMe = ETrue; |
|
356 } |
|
357 IRLOG_DEBUG2( "CIRIcyFlowInitiator::ValidateChannelServer - Exiting (%d).", retMe ); |
|
358 return retMe; |
|
359 } |
|
360 |
|
361 |
|
362 // --------------------------------------------------------------------------- |
|
363 // CIRIcyFlowInitiator::ParseChannelInfoL |
|
364 // --------------------------------------------------------------------------- |
|
365 // |
|
366 void CIRIcyFlowInitiator::ParseChannelInfoL() |
|
367 { |
|
368 IRLOG_DEBUG( "CIRIcyFlowInitiator::ParseChannelInfoL" ); |
|
369 |
|
370 TInt offsetPositionStart( 0 ); |
|
371 offsetPositionStart = iBuffer.Find( KHeaderEnd ); |
|
372 if ( offsetPositionStart == KErrNotFound ) |
|
373 { |
|
374 IRLOG_ERROR( "CIRIcyFlowInitiator::ParseChannelInfoL - Header delimiter not found." ); |
|
375 User::Leave( KIRStreamSourceApplicationProtocolError ); |
|
376 } |
|
377 offsetPositionStart += KFour; |
|
378 TPtrC8 start = iBuffer.Mid( offsetPositionStart ); |
|
379 iChannelInfo.iAudioDataOffset = start.Length(); |
|
380 // Call ExtractMetaInfo function for each Meta Field |
|
381 ExtractMetaInfoL( KIcyName, iChannelInfo.iStationName ); |
|
382 ExtractMetaInfoL( KIcyGenre, iChannelInfo.iGenre ); |
|
383 ExtractMetaInfoL( KIcyBitrate, iChannelInfo.iBitRate ); |
|
384 // Extract the Content-Type header |
|
385 ExtractMetaInfoL( KContentType, iChannelInfo.iContentType ); |
|
386 // Extract the content-type header ( invalid header name handling ) |
|
387 ExtractMetaInfoL( KContentTypeInvalid, iChannelInfo.iContentType ); |
|
388 RBuf8 metaIntervalBuf; |
|
389 metaIntervalBuf.CreateL( KMAXMETABUFLENGTH ); |
|
390 metaIntervalBuf.CleanupClosePushL(); |
|
391 |
|
392 ExtractMetaInfoL( KIcyMetaint, metaIntervalBuf ); |
|
393 |
|
394 TLex8 convert( metaIntervalBuf ); |
|
395 convert.Val( iChannelInfo.iMetaInterval ); |
|
396 |
|
397 if ( iChannelInfo.iMetaInterval <= 0 ) // Invalid meta interval specified, the stream is corrupt and cannot be played. |
|
398 { |
|
399 IRLOG_ERROR( "CIRIcyFlowInitiator::ParseChannelInfoL - Invalid metainterval." ); |
|
400 User::Leave( KIRStreamSourceApplicationProtocolError ); |
|
401 } |
|
402 CleanupStack::PopAndDestroy(); |
|
403 |
|
404 IRLOG_DEBUG( "CIRIcyFlowInitiator::ParseChannelInfoL - Exiting." ); |
|
405 } |
|
406 |
|
407 |
|
408 // --------------------------------------------------------------------------- |
|
409 // CIRIcyFlowInitiator::ExtractMetaInfoL |
|
410 // --------------------------------------------------------------------------- |
|
411 // |
|
412 TBool CIRIcyFlowInitiator::ExtractMetaInfoL(const TDesC8& aMetaField, TDes8 &aBuffer ) const |
|
413 { |
|
414 IRLOG_DEBUG2( "CIRIcyFlowInitiator::ExtractMetaInfoL - aMetaField = %S", &aMetaField ); |
|
415 // This function contains the logic for parsing the |
|
416 // buffer obtained from RecieveMetaInfo() and |
|
417 // appends the Meta info into the ChannelInfo structure |
|
418 TInt offsetPositionStart( 0 ); |
|
419 TInt offsetPositionEnd( 0 ); |
|
420 TPtr8 startPos( NULL, 0 ); |
|
421 |
|
422 offsetPositionStart = iBuffer.Find( aMetaField ); |
|
423 |
|
424 if ( offsetPositionStart < 0 ) |
|
425 { |
|
426 IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractMetaInfoL - Field not found, Exiting." ); |
|
427 return EFalse; |
|
428 } |
|
429 // Increment the offset by the length of meta field |
|
430 offsetPositionStart += aMetaField.Length(); |
|
431 |
|
432 TPtrC8 start = iBuffer.Mid( offsetPositionStart ); |
|
433 |
|
434 offsetPositionEnd = start.Find( KCarReturn ); |
|
435 |
|
436 if ( offsetPositionEnd == KErrNotFound ) |
|
437 { |
|
438 IRLOG_ERROR( "CIRIcyFlowInitiator::ExtractMetaInfoL - Field delimiter not found." ); |
|
439 User::Leave( KIRStreamSourceApplicationProtocolError ); |
|
440 } |
|
441 // Extract the actual data |
|
442 TPtrC8 data = start.Left( offsetPositionEnd ); |
|
443 |
|
444 // too large field for this implementation. |
|
445 if (data.Length() > aBuffer.MaxLength() ) |
|
446 { |
|
447 IRLOG_ERROR3( "CIRIcyFlowInitiator::ExtractMetaInfoL - Received field was too large (%d, allowed maximum = %d)", |
|
448 data.Length(), aBuffer.Length() ); |
|
449 User::Leave( KIRStreamSourceApplicationProtocolError ); |
|
450 } |
|
451 |
|
452 aBuffer.Copy( data ); |
|
453 aBuffer.TrimAll(); |
|
454 IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractMetaInfoL - Exiting." ); |
|
455 return ETrue; |
|
456 } |
|
457 |
|