internetradio2.0/streamsourcesrc/iricyflowreader.cpp
changeset 14 896e9dbc5f19
parent 12 608f67c22514
child 15 065198191975
equal deleted inserted replaced
12:608f67c22514 14:896e9dbc5f19
     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 reader implementation
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /* ---------------------------------------------------------------------------
       
    20 *  Version history:
       
    21 *  Template version:
       
    22 *  <ccm_history>
       
    23 *
       
    24 *  Version: 2, Tue Feb 28 18:00:00 2008 by Rohit/Kranthi
       
    25 *  Ref:
       
    26 *  Setting RawDataTransferredL() into DataTransferTracker for Byte Counter Impl
       
    27 *
       
    28 *  </ccm_history>
       
    29 * ============================================================================
       
    30 */
       
    31 #include <utf.h>
       
    32 
       
    33 #include "iricyflowreader.h"
       
    34 #include "irdebug.h"
       
    35 #include "irmediaenginebuffer.h"
       
    36 #include "irmetadata.h"
       
    37 #include "irnetworkbuffer.h"
       
    38 #include "irstationconnection.h"
       
    39 #include "irstationdataobserver.h"
       
    40 #include "irstreamsourceerrors.h"
       
    41 #include "irnetworkcontroller.h"
       
    42 
       
    43 const TInt KMaxSongBufferSize = 61440;
       
    44 const TInt KNoInputBuffers = 60;
       
    45 const TInt KMaxBufferChunkSize = 1024;
       
    46 const TInt KMaxSocketBufferSize = 1024;
       
    47 const TInt KBufferPercentageInc = 1;
       
    48 const TInt KSixteen = 16;
       
    49 const TInt KThree=3;
       
    50 _LIT8( KIRStreamTitle, "StreamTitle='" );
       
    51 _LIT8( KIRStreamUrl, "StreamUrl='" );
       
    52 _LIT8( KIRMetaDataEndIdentifier, "';" );
       
    53 _LIT8( KIRSongDelimiter, " - " );
       
    54 
       
    55 // masks and prefices used in UTF-8 recognition
       
    56 const TInt KIRUtf8_2B1stByteMask = 0xE0;
       
    57 const TInt KIRUtf8_3B1stByteMask = 0xF0;
       
    58 const TInt KIRUtf8_4B1stByteMask = 0xF8;
       
    59 const TInt KIRUtf8FollowingByteMask = 0xC0;
       
    60 
       
    61 const TInt KIRUtf8_2B1stBytePrefix = 0xC0;
       
    62 const TInt KIRUtf8_3B1stBytePrefix = 0xE0;
       
    63 const TInt KIRUtf8_4B1stBytePrefix = 0xF0;
       
    64 const TInt KIRUtf8FollowingBytePrefix = 0x80;
       
    65 // ========================= MEMBER FUNCTIONS ================================
       
    66 
       
    67 
       
    68 // ---------------------------------------------------------------------------
       
    69 // CIRIcyFlowReader::NewL
       
    70 // ---------------------------------------------------------------------------
       
    71 //
       
    72 CIRIcyFlowReader* CIRIcyFlowReader::NewL( RSocket& aSocket, CIRStationConnection& aOwner,
       
    73 	               MIRStationDataObserver& aDataObserver, TChannelInfo& aChannelInfo )
       
    74     {
       
    75     CIRIcyFlowReader* self = new ( ELeave ) CIRIcyFlowReader( aSocket, aOwner,
       
    76     					 aDataObserver, aChannelInfo );
       
    77     CleanupStack::PushL( self );
       
    78     self->ConstructL();
       
    79     CleanupStack::Pop( self );
       
    80     return self;
       
    81     }
       
    82 
       
    83 // ---------------------------------------------------------------------------
       
    84 // CIRIcyFlowReader::CIRIcyFlowReader
       
    85 // ---------------------------------------------------------------------------
       
    86 //
       
    87 CIRIcyFlowReader::CIRIcyFlowReader( RSocket& aSocket, CIRStationConnection& aOwner,
       
    88 	              MIRStationDataObserver& aDataObserver, TChannelInfo& aChannelInfo )
       
    89     :CActive( EPriorityStandard ), iSocket( aSocket ), iOwner( aOwner ),
       
    90     				 iDataObserver( aDataObserver ),
       
    91       iSocketBufferPtr( NULL, 0 ), iChannelInfo( aChannelInfo )
       
    92     {
       
    93 
       
    94     }
       
    95 
       
    96 // ---------------------------------------------------------------------------
       
    97 // CIRIcyFlowReader::~CIRIcyFlowReader
       
    98 // ---------------------------------------------------------------------------
       
    99 //
       
   100 CIRIcyFlowReader::~CIRIcyFlowReader()
       
   101 	{
       
   102 	Cancel();
       
   103 	while(!iSinkQ.IsEmpty())
       
   104 		{
       
   105 		//Deleting all the entries in sink buffers queue
       
   106 		iTempBufferHolder = iSinkQ.First();
       
   107 		iSinkQ.Remove(*iTempBufferHolder);
       
   108 		delete iTempBufferHolder;
       
   109 		}
       
   110 	while(!iSourceQ.IsEmpty())
       
   111 		{
       
   112 		//deleting all the entries in source buffers queue
       
   113 		iTempBufferHolder = iSourceQ.First();
       
   114 		iSourceQ.Remove(*iTempBufferHolder);
       
   115 		delete iTempBufferHolder;
       
   116 		}
       
   117 	delete[] iSongBuffer;
       
   118 	delete iSocketBuffer;
       
   119 	delete iTempSongBuffer;
       
   120 	delete iTempMetaBuffer;
       
   121     delete iMetaData;
       
   122 	if(iNetworkControllerHandle)
       
   123 		{
       
   124 		iNetworkControllerHandle->Close();
       
   125 		}
       
   126 	}
       
   127 
       
   128 // ---------------------------------------------------------------------------
       
   129 // CIRIcyFlowReader::ConstructL()
       
   130 // ---------------------------------------------------------------------------
       
   131 //
       
   132 void CIRIcyFlowReader::ConstructL()
       
   133     {
       
   134     IRLOG_DEBUG( "CIRIcyFlowReader::ConstructL" );
       
   135     iAudioDataOffset = iChannelInfo.iAudioDataOffset;
       
   136     TInt f_off = _FOFF( CIRNetworkBuffer, iLink ); //for the buffer queue which is maintained
       
   137     iSourceQ.SetOffset( f_off ); 	// It is Queue of buffer given to socket to fill
       
   138     iSinkQ.SetOffset( f_off );  // It is Queue of buffer given to media engine
       
   139     InitializeBuffersL();
       
   140     iMetaData = CIRMetaData::NewL();
       
   141     CActiveScheduler::Add( this );
       
   142     iNetworkControllerHandle = CIRNetworkController::OpenL();
       
   143     IRLOG_DEBUG( "CIRIcyFlowReader::ConstructL - Exiting." );
       
   144     }
       
   145 
       
   146 // ---------------------------------------------------------------------------
       
   147 // CIRIcyFlowReader::HandleReceivedDataL
       
   148 // ---------------------------------------------------------------------------
       
   149 //
       
   150 void CIRIcyFlowReader::HandleReceivedDataL( const TDesC8& aData )
       
   151     {
       
   152     switch ( iParsingState )
       
   153         {
       
   154         case EIRReadingAudioData:
       
   155             {
       
   156             if ( iAudioDataOffset + aData.Length() > iChannelInfo.iMetaInterval )
       
   157                 {
       
   158                 // Part of this data contains meta data information already.
       
   159                 TInt audioDataAmount = iChannelInfo.iMetaInterval - iAudioDataOffset;
       
   160                 // Only the audio part of the data is added to the song buffer.
       
   161                 HandleReceivedAudioData( aData.Left( audioDataAmount ) );
       
   162                 iParsingState = EIRReadingMetaDataLength;
       
   163                 iAudioDataOffset = 0; // Resets the audio data offset, will start increment again after meta data is handled.
       
   164                 HandleReceivedDataL( aData.Mid( audioDataAmount ) ); // Recursive call to handle meta data mixed in with this audio data block.
       
   165                 }
       
   166             else // All of it is data is audio data.
       
   167                 {
       
   168                 HandleReceivedAudioData( aData );
       
   169                 }
       
   170             break;
       
   171             }
       
   172         case EIRReadingMetaDataLength:
       
   173             {
       
   174             // ICY protocol specifies that meta data length is the first byte of the data multiplied by 16.
       
   175             iMetaDataLength = aData[0] * KSixteen;
       
   176 
       
   177             delete iTempMetaBuffer;
       
   178             iTempMetaBuffer = NULL;
       
   179 
       
   180             if ( iMetaDataLength > 0 ) // Meta data is provided, so we have to parse it.
       
   181                 {
       
   182                 iTempMetaBuffer = HBufC8::NewL( iMetaDataLength );
       
   183                 iParsingState = EIRReadingMetaData;
       
   184                 }
       
   185             else // No meta data available, so resume reading audio data.
       
   186                 {
       
   187                 iParsingState = EIRReadingAudioData;
       
   188                 }
       
   189 
       
   190             if ( aData.Length() > 1 ) // Just to check that the data doesn't only contain the length byte.
       
   191                 {
       
   192                 HandleReceivedDataL( aData.Mid( 1 ) ); // Strips off the length byte. Recursive call as data can also contain audio data.
       
   193                 }
       
   194 
       
   195             break;
       
   196             }
       
   197         case EIRReadingMetaData:
       
   198             {
       
   199             if ( iTempMetaBuffer->Length() + aData.Length() > iMetaDataLength )
       
   200                 {
       
   201                 // All of the meta data block is now received, and part of it is continuation to the audio data.
       
   202                 TInt metaDataAmount = iMetaDataLength - iTempMetaBuffer->Length();
       
   203                 HandleReceivedMetaData( aData.Left( metaDataAmount ) );
       
   204                 ExtractMetadataL(); // Extracts the meta data from the temporary meta data buffer.
       
   205                 iParsingState = EIRReadingAudioData;
       
   206                 HandleReceivedDataL( aData.Mid( metaDataAmount ) ); // Strips off the meta data from the descriptor.
       
   207                 }
       
   208             else // All of it is meta data.
       
   209                 {
       
   210                 HandleReceivedMetaData( aData );
       
   211                 }
       
   212             break;
       
   213             }
       
   214         }
       
   215     }
       
   216 
       
   217 // ---------------------------------------------------------------------------
       
   218 // CIRIcyFlowReader::HandleReceivedAudioData
       
   219 // ---------------------------------------------------------------------------
       
   220 //
       
   221 void CIRIcyFlowReader::HandleReceivedAudioData( const TDesC8& aData )
       
   222     {
       
   223     // Check to see if we've got enough audio data to fill a buffer.
       
   224     if ( iTempSongBuffer->Length() + aData.Length() >= KMaxBufferChunkSize )
       
   225         {
       
   226 		// Data contains more audio data than the buffer can handle.
       
   227 		TInt amountToAdd = KMaxBufferChunkSize - iTempSongBuffer->Length();
       
   228 
       
   229 		// Enough audio data to fill the buffer is added.
       
   230 		iTempSongBuffer->Des().Append( aData.Left( amountToAdd ) );
       
   231 
       
   232 		AddToSinkQueue( *iTempSongBuffer );
       
   233 		
       
   234 		//while loop is written for only if left over amount in aData is 
       
   235 		//greater then 1024, then it should be again added into SinkQueue
       
   236 		while(1)
       
   237 			{
       
   238 			iTempSongBuffer->Des().Zero();
       
   239 	 		//calculates the length of the leftover amount to be added
       
   240 			TInt length = aData.Length() - amountToAdd;
       
   241 
       
   242 			if(length <= 0)
       
   243 				{
       
   244 				break;	
       
   245 				}
       
   246 			else if(length >= KMaxBufferChunkSize) //if the left over amount is >= 1024 then add to SinkQueue
       
   247 				{
       
   248 				iTempSongBuffer->Des().Append( aData.Mid( amountToAdd,KMaxBufferChunkSize ) );
       
   249 		 		// updates the amountToAdd value by 1024
       
   250 				amountToAdd += KMaxBufferChunkSize;
       
   251 
       
   252 				AddToSinkQueue( *iTempSongBuffer );
       
   253 				}
       
   254 			else //if the left over amount is < 1024 then append to tempSongBuffer & break
       
   255 				{
       
   256 				// Then the overflowing audio data part is added to the new clean buffer.
       
   257 				iTempSongBuffer->Des().Append( aData.Mid( amountToAdd ) );
       
   258 				break;	
       
   259 				}
       
   260 			}
       
   261         }
       
   262     else // There is enough room in the temporary audio buffer to hold all of the data.
       
   263         {
       
   264         iTempSongBuffer->Des().Append( aData );
       
   265         }
       
   266 
       
   267     iAudioDataOffset += aData.Length();
       
   268 
       
   269 
       
   270 
       
   271     }
       
   272 
       
   273 // ---------------------------------------------------------------------------
       
   274 // CIRIcyFlowReader::HandleReceivedMetaData
       
   275 // ---------------------------------------------------------------------------
       
   276 //
       
   277 void CIRIcyFlowReader::HandleReceivedMetaData( const TDesC8& aData )
       
   278     {
       
   279     iTempMetaBuffer->Des().Append( aData );
       
   280     }
       
   281 
       
   282 // ---------------------------------------------------------------------------
       
   283 // CIRIcyFlowReader::RunL
       
   284 // ---------------------------------------------------------------------------
       
   285 //
       
   286 void CIRIcyFlowReader::RunL()
       
   287     {
       
   288      // Active object request complete handler
       
   289     switch ( iStatus.Int() )
       
   290         {
       
   291         case KErrNone:
       
   292             {
       
   293 			// Byte Counter Impl
       
   294 			iNetworkControllerHandle->DataTransferTracker().RawDataTransferredL( 0,
       
   295 					 iSocketBufferPtr.Size(), MIRDataTransferTracker::EIRTransferCategoryAudio);
       
   296 
       
   297             HandleReceivedDataL( *iSocketBuffer );
       
   298 
       
   299             if ( !iSourceQ.IsEmpty() )
       
   300             	{
       
   301             	//issue a read on empty buffer
       
   302             	IssueRead();
       
   303             	}
       
   304             else
       
   305             	{
       
   306             	if( iReBuffering )
       
   307             		{
       
   308             		//	if rebuffering call continue using sink buffer
       
   309             		FillRemainingBuffers();
       
   310             		}
       
   311             	if( iInitialBuffering )
       
   312             		{
       
   313             		//  if first time intimate media client to fill the buffer
       
   314             		iDataObserver.AudioDataEvent( MIRStationDataObserver::EBufferFilled, KErrNone );
       
   315             		iInitialBuffering = EFalse;
       
   316             		}
       
   317             	}
       
   318 
       
   319 		 	break;
       
   320 			}
       
   321         case KErrDisconnected:
       
   322         	{
       
   323         	IRLOG_ERROR( "CIRIcyFlowReader::RunL - KErrDisconnected");
       
   324         	iOwner.ConnectionError( KIRStreamSourceDisconnected );
       
   325         	}
       
   326             break;
       
   327         case KErrEof:
       
   328         	{
       
   329         	IRLOG_INFO( "CIRIcyFlowReader::RunL - KErrEof" );
       
   330         	iOwner.ConnectionError( KIRStreamSourceNoResponse );
       
   331         	}
       
   332         	break;
       
   333         default:
       
   334         	{
       
   335         	IRLOG_ERROR2( "CIRIcyFlowReader::RunL - Error (%d)", iStatus.Int() );
       
   336             iOwner.ConnectionError( KIRStreamSourceReadError );
       
   337         	}
       
   338             break;
       
   339         }
       
   340     }
       
   341 
       
   342 // ---------------------------------------------------------------------------
       
   343 // CIRIcyFlowReader::DoCancel
       
   344 // ---------------------------------------------------------------------------
       
   345 //
       
   346 void CIRIcyFlowReader::DoCancel()
       
   347     {
       
   348     iSocket.CancelRead();
       
   349     }
       
   350 
       
   351 
       
   352 
       
   353 // ---------------------------------------------------------------------------
       
   354 // CIRIcyFlowReader::IssueRead
       
   355 // ---------------------------------------------------------------------------
       
   356 //
       
   357 void CIRIcyFlowReader::IssueRead()
       
   358     {
       
   359 	if( !IsActive() )
       
   360 		{
       
   361 	    iSocketBufferPtr.Zero();
       
   362 	    iSocket.Read( iSocketBufferPtr, iStatus );
       
   363 	    SetActive();
       
   364 		}
       
   365     }
       
   366 
       
   367 // ---------------------------------------------------------------------------
       
   368 // CIRIcyFlowReader::Start
       
   369 // ---------------------------------------------------------------------------
       
   370 //
       
   371 void CIRIcyFlowReader::Start()
       
   372     {
       
   373     IRLOG_INFO( "CIRIcyFlowReader::Start" );
       
   374     // Initiate a new read from socket into iBuffer
       
   375     iInitialBuffering = ETrue;
       
   376     iBufferCounter = 0;
       
   377     iPublishStationInfo = ETrue;
       
   378 	IssueRead();
       
   379 	IRLOG_DEBUG( "CIRIcyFlowReader::Start - Exiting." );
       
   380     }
       
   381 
       
   382 
       
   383 // ---------------------------------------------------------------------------
       
   384 // CIRIcyFlowReader::InitializeBuffersL
       
   385 // ---------------------------------------------------------------------------
       
   386 //
       
   387 void CIRIcyFlowReader::InitializeBuffersL()
       
   388 	{
       
   389 	IRLOG_DEBUG( "CIRIcyFlowReader::InitializeBuffersL" );
       
   390 	// Allocate the buffer for audio data on heap
       
   391 	iSongBuffer = new TUint8[KMaxSongBufferSize];
       
   392 	User::LeaveIfNull( iSongBuffer );
       
   393 
       
   394 	IRLOG_INFO2( "CIRIcyFlowReader::InitializeBuffersL - Reserved %d bytes of memory", KMaxSongBufferSize );
       
   395 	TUint8* bufferaddress = iSongBuffer;
       
   396 	// since sink buffers are not created initially all buffers are filled with data and appended to sink buffer
       
   397 	// Create buffers ans append to source buffer queue
       
   398 	for(TInt buffercount = 0; buffercount < KNoInputBuffers; buffercount++ )
       
   399 		{
       
   400 		iTempBufferHolder = CIRNetworkBuffer::NewL(bufferaddress,
       
   401 			KMaxBufferChunkSize);
       
   402 		iSourceQ.AddLast(*iTempBufferHolder);
       
   403 		bufferaddress += KMaxBufferChunkSize;
       
   404 		}
       
   405 	// Create a buffer for the data read from socket
       
   406 	iSocketBuffer = HBufC8::NewL( KMaxSocketBufferSize );
       
   407 	iSocketBufferPtr.Set( iSocketBuffer->Des() );
       
   408     iTempSongBuffer = HBufC8::NewL( KMaxSocketBufferSize );
       
   409 	IRLOG_DEBUG( "CIRIcyFlowReader::InitializeBuffersL - Exiting." );
       
   410 	}
       
   411 
       
   412 
       
   413 
       
   414 // ---------------------------------------------------------------------------
       
   415 // CIRIcyFlowReader::FillBuffer
       
   416 // Fills the mediaengine buffer and rebuffers if necessary
       
   417 // ---------------------------------------------------------------------------
       
   418 //
       
   419 void CIRIcyFlowReader::FillBuffer(TDes8& aInputBuffer)
       
   420 	{
       
   421 	FillMediaEngineBuffer(aInputBuffer);
       
   422 	}
       
   423 
       
   424 // ---------------------------------------------------------------------------
       
   425 // CIRIcyFlowReader::AddToSinkQueue
       
   426 // Adds the filled buffers to the sink Q so that it can be copied to media
       
   427 // engine buffer
       
   428 // ---------------------------------------------------------------------------
       
   429 //
       
   430 void CIRIcyFlowReader::AddToSinkQueue( const TDesC8& aData )
       
   431 	{
       
   432 	//call from runL
       
   433 	//removes the buffer from source queue and put in sink queue
       
   434 
       
   435 	if( !iSourceQ.IsEmpty() )
       
   436 		{
       
   437 		iTempBufferHolder = iSourceQ.First();
       
   438 		TPtr8 bufferPointer(iTempBufferHolder->Des() ,KMaxBufferChunkSize,
       
   439 			KMaxBufferChunkSize );
       
   440 		bufferPointer.Copy(aData);
       
   441 		iSourceQ.Remove(*iTempBufferHolder);
       
   442 		iSinkQ.AddLast(*iTempBufferHolder);
       
   443 		if( iInitialBuffering )
       
   444 			{
       
   445 			iBufferCounter += KBufferPercentageInc;
       
   446 			iDataObserver.AudioDataEvent( MIRStationDataObserver::EBufferPercentage, iBufferCounter );
       
   447 			}
       
   448 		}
       
   449 	}
       
   450 
       
   451 // ---------------------------------------------------------------------------
       
   452 // CIRIcyFlowReader::FillMediaEngineBuffer
       
   453 // Fills the data into media engine's buffer
       
   454 // aInputBuffer Buffer into which data is to be filled
       
   455 // ---------------------------------------------------------------------------
       
   456 //
       
   457 
       
   458 void CIRIcyFlowReader::FillMediaEngineBuffer(const TDes8& aInputBuffer)
       
   459 	{
       
   460 
       
   461 	if( !iReBuffering )
       
   462 		{
       
   463 		//Determine no of bytes of data to be filled
       
   464 		TInt copyLength = aInputBuffer.MaxLength();
       
   465 		// Calculate the no of 1K chunks
       
   466 		iNoOfChunks = copyLength/KMaxBufferChunkSize;
       
   467 		// Initiailly remaining chunks to be filled is same as total no of
       
   468 		// chunks to be filled
       
   469 		iChunksRemaining = iNoOfChunks;
       
   470 		IRLOG_DEBUG3( "CIRIcyFlowReader::FillMediaEngineBuffer - Copying %d bytes/%d chunks", copyLength, iNoOfChunks );
       
   471 		// Store the starting address of buffer into which data is to be
       
   472 		// copied
       
   473 		iBufferFillPointer = (TUint8 *)aInputBuffer.Ptr();
       
   474 		// Start filling of the empty media engine buffers
       
   475 		FillRemainingBuffers();
       
   476 		}
       
   477 	}
       
   478 
       
   479 
       
   480 // ---------------------------------------------------------------------------
       
   481 // CIRIcyFlowReader::FillRemainingBuffers
       
   482 // Fills the data into media engine's remaining buffers
       
   483 // called when the stream source runs out of buffers and
       
   484 // there is a pending request to media engine
       
   485 // ---------------------------------------------------------------------------
       
   486 //
       
   487 void CIRIcyFlowReader::FillRemainingBuffers()
       
   488 	{
       
   489 	TUint8* mediaBufferAddress = iBufferFillPointer;
       
   490 	TInt chunksFilled = iNoOfChunks - iChunksRemaining;
       
   491 	mediaBufferAddress += ( chunksFilled * KMaxBufferChunkSize );
       
   492 
       
   493 	TInt bufferNumber = iChunksRemaining;
       
   494 	while ( bufferNumber )
       
   495 		{
       
   496 		if ( !iSinkQ.IsEmpty() )
       
   497 			{
       
   498 			iTempBufferHolder = iSinkQ.First();
       
   499 			TPtr8 mediaBufferPointer(mediaBufferAddress,KMaxBufferChunkSize,
       
   500 				KMaxBufferChunkSize );
       
   501 			mediaBufferPointer.Copy( iTempBufferHolder->Des() ,
       
   502 				KMaxBufferChunkSize);
       
   503 			TPtr8 tempBufferPointer(iTempBufferHolder->Des(),
       
   504 				KMaxBufferChunkSize,KMaxBufferChunkSize );
       
   505 			tempBufferPointer.Delete(KMaxBufferChunkSize,
       
   506 				KMaxBufferChunkSize);
       
   507 			iSinkQ.Remove(*iTempBufferHolder);
       
   508 			iSourceQ.AddLast(*iTempBufferHolder);
       
   509 			iChunksRemaining--;
       
   510 			bufferNumber--;
       
   511 			iReBuffering = EFalse;
       
   512 			mediaBufferAddress += KMaxBufferChunkSize;
       
   513 			//issue  source rebuffering here if source is not empty
       
   514 			if( !iSourceQ.IsEmpty() )
       
   515 				{
       
   516 				IssueRead();
       
   517 				}
       
   518 			}
       
   519 		else
       
   520 			{
       
   521 			//rebuffer if sink buffer is empty
       
   522 			bufferNumber = 0;
       
   523 			iReBuffering = ETrue;
       
   524 			//issue  source rebuffering here if source is not empty
       
   525 			if( !iSourceQ.IsEmpty() )
       
   526 				{
       
   527 				IssueRead();
       
   528 				}
       
   529 			//break from for loop
       
   530 			}
       
   531 		}
       
   532 	iBufferCounter += (K100Percentage - KNoInputBuffers) / KIRInputBufferCount;
       
   533     if ( iBufferCounter > K100Percentage )
       
   534         {
       
   535         iBufferCounter = K100Percentage;
       
   536         }
       
   537     iDataObserver.AudioDataEvent( MIRStationDataObserver::EBufferPercentage, iBufferCounter );
       
   538 	if( !iReBuffering )
       
   539 		{
       
   540         iDataObserver.AudioDataEvent( MIRStationDataObserver::EOpenComplete, KErrNone );
       
   541 		}
       
   542 	}
       
   543 
       
   544 // ---------------------------------------------------------------------------
       
   545 // CIRIcyFlowReader::ExtractMetadataL
       
   546 // Extracts the meta data from the stream
       
   547 // ---------------------------------------------------------------------------
       
   548 //
       
   549 void CIRIcyFlowReader::ExtractMetadataL()
       
   550 	{
       
   551     IRLOG_DEBUG( "CIRIcyFlowReader::ExtractMetaDataL" );
       
   552 
       
   553     // Erases old meta data information.
       
   554     iMetaData->SetArtistL( KNullDesC );
       
   555     iMetaData->SetSongL( KNullDesC );
       
   556     iMetaData->SetStreamUrlL( KNullDesC );
       
   557 
       
   558     TPtrC8 ptr( *iTempMetaBuffer );
       
   559 
       
   560     TInt streamTitleIndex = ptr.Find( KIRStreamTitle );
       
   561     TInt streamUrlIndex = ptr.Find( KIRStreamUrl );
       
   562 
       
   563     // Extracts the "StreamTitle" part of the meta data.
       
   564     if ( streamTitleIndex >= 0 )
       
   565         {
       
   566         TPtrC8 streamTitlePtr( ptr.Mid( streamTitleIndex + KIRStreamTitle().Length() ) );
       
   567         TInt streamTitleEndIndex = streamTitlePtr.Find( KIRMetaDataEndIdentifier );
       
   568         if ( streamTitleEndIndex >= 0 )
       
   569             {
       
   570             streamTitlePtr.Set( streamTitlePtr.Left( streamTitleEndIndex ) );
       
   571 
       
   572             TPtrC8 artistPtr( KNullDesC8 );
       
   573             TPtrC8 songPtr( KNullDesC8 );
       
   574 
       
   575             TInt songDelimiterIndex = streamTitlePtr.Find( KIRSongDelimiter );
       
   576             if ( songDelimiterIndex >= 0 )
       
   577                 {
       
   578                 artistPtr.Set( streamTitlePtr.Left( songDelimiterIndex ) );
       
   579                 songPtr.Set( streamTitlePtr.Mid( songDelimiterIndex + 
       
   580                 					KIRSongDelimiter().Length() ) );
       
   581                 }
       
   582             else
       
   583                 {
       
   584                 IRLOG_WARNING( "CIRIcyFlowReader::ExtractMetaDataL - Song delimiter was not found" );
       
   585                 artistPtr.Set( streamTitlePtr );
       
   586                 }
       
   587 
       
   588             HBufC* artist = DecodeMetadataStringLC( artistPtr );
       
   589             iMetaData->SetArtistL( *artist );
       
   590             CleanupStack::PopAndDestroy( artist );
       
   591 
       
   592             HBufC* song = DecodeMetadataStringLC( songPtr );
       
   593             iMetaData->SetSongL( *song );
       
   594             CleanupStack::PopAndDestroy( song );
       
   595             }
       
   596         else
       
   597             {
       
   598             IRLOG_WARNING( "CIRIcyFlowReader::ExtractMetaDataL - \"StreamTitle\" end was not found" );
       
   599             }
       
   600         }
       
   601     else
       
   602         {
       
   603         IRLOG_WARNING( "CIRIcyFlowReader::ExtractMetaDataL - \"StreamTitle\" was not found" );
       
   604         }
       
   605 
       
   606     // Extracts the "StreamUrl" part of the meta data.
       
   607     if ( streamUrlIndex >= 0 )
       
   608         {
       
   609         TPtrC8 streamUrlPtr( ptr.Mid( streamUrlIndex + KIRStreamUrl().Length() ) );
       
   610 
       
   611         TInt streamUrlEndIndex = streamUrlPtr.Find( KIRMetaDataEndIdentifier );
       
   612         if ( streamUrlEndIndex >= 0 )
       
   613             {
       
   614             streamUrlPtr.Set( streamUrlPtr.Left( streamUrlEndIndex ) );
       
   615             HBufC* streamUrl = HBufC::NewLC( streamUrlPtr.Length() );
       
   616             streamUrl->Des().Copy( streamUrlPtr );  // 8 bit to 16 bit descriptor conversion.
       
   617             iMetaData->SetStreamUrlL( *streamUrl );
       
   618             CleanupStack::PopAndDestroy( streamUrl );
       
   619             }
       
   620         else
       
   621             {
       
   622             IRLOG_WARNING( "CIRIcyFlowReader::ExtractMetaDataL - \"StreamUrl\" end was not found" );
       
   623             }
       
   624         }
       
   625     else
       
   626         {
       
   627         IRLOG_WARNING( "CIRIcyFlowReader::ExtractMetaDataL - \"StreamUrl\" was not found" );
       
   628         }
       
   629 
       
   630     iDataObserver.MetadataReceived( *iMetaData );
       
   631 
       
   632     IRLOG_INFO4( "CIRIcyFlowReader::ExtractMetaDataL - Exit (artist=%S, song=%S, streamUrl=%S)", &iMetaData->Artist(), &iMetaData->Song(), &iMetaData->StreamUrl() );
       
   633 	}
       
   634 
       
   635 // ---------------------------------------------------------------------------
       
   636 // CIRIcyFlowReader::DecodeMetadataStringLC
       
   637 // ---------------------------------------------------------------------------
       
   638 //
       
   639 HBufC* CIRIcyFlowReader::DecodeMetadataStringLC( const TDesC8& aString ) const
       
   640     {
       
   641     IRLOG_DEBUG( "CIRIcyFlowReader::DecodeMetadataStringLC" );
       
   642     HBufC* decodedString = NULL;
       
   643     if ( IsUtf8Encoded( aString ) )
       
   644         {
       
   645         TRAPD( err, 
       
   646               IRLOG_DEBUG( "CIRIcyFlowReader::DecodeMetadataStringLC - String is UTF-8 encoded" );
       
   647               decodedString = CnvUtfConverter::ConvertToUnicodeFromUtf8L( aString );
       
   648              )
       
   649         if ( err != KErrNone )
       
   650             {
       
   651             IRLOG_ERROR2( "CIRIcyFlowReader::DecodeMetadataStringLC - UTF-8 conversion failed, err=%d", err );
       
   652             decodedString = HBufC::NewL( aString.Length() ); 
       
   653             decodedString->Des().Copy( aString ); // 8 bit to 16 bit descriptor conversion (ISO-8859-1).    
       
   654             }
       
   655         }
       
   656     else
       
   657         {
       
   658         decodedString = HBufC::NewL( aString.Length() ); 
       
   659         decodedString->Des().Copy( aString ); // 8 bit to 16 bit descriptor conversion (ISO-8859-1).    
       
   660         }
       
   661     CleanupStack::PushL( decodedString );
       
   662     IRLOG_DEBUG2( "CIRIcyFlowReader::DecodeMetadataStringLC - Returning %S", decodedString );    
       
   663     return decodedString;
       
   664     }
       
   665 
       
   666 // ---------------------------------------------------------------------------
       
   667 // CIRIcyFlowReader::IsUtf8Encoded
       
   668 // ---------------------------------------------------------------------------
       
   669 //
       
   670 TBool CIRIcyFlowReader::IsUtf8Encoded( const TDesC8& aData ) const
       
   671     {
       
   672     IRLOG_DEBUG( "CIRIcyFlowReader::IsUtf8Encoded" );    
       
   673     TBool foundUtf8( EFalse );
       
   674     
       
   675     for ( TInt i(0); i + 1 < aData.Length() && !foundUtf8; i++ )
       
   676         {
       
   677         if ( ( aData[i] & KIRUtf8_2B1stByteMask ) == KIRUtf8_2B1stBytePrefix )
       
   678             {
       
   679             // Two-byte presentation: 110yyyyy 10zzzzzz
       
   680             if ( ( aData[i + 1] & KIRUtf8FollowingByteMask ) == KIRUtf8FollowingBytePrefix )
       
   681                 {
       
   682                 foundUtf8 = ETrue;
       
   683                 }
       
   684             }
       
   685         else if ( ( aData[i] & KIRUtf8_3B1stByteMask ) == KIRUtf8_3B1stBytePrefix && 
       
   686                   i + 2 < aData.Length() )
       
   687             {
       
   688             // Three-byte presentation: 1110xxxx 10yyyyyy 10zzzzzz
       
   689             if ( ( aData[i + 1] & KIRUtf8FollowingByteMask ) == KIRUtf8FollowingBytePrefix && 
       
   690                  ( aData[i + 2] & KIRUtf8FollowingByteMask ) == KIRUtf8FollowingBytePrefix )
       
   691                 {
       
   692                 foundUtf8 = ETrue;
       
   693                 }
       
   694             }
       
   695         else if ( ( aData[i] & KIRUtf8_4B1stByteMask ) == KIRUtf8_4B1stBytePrefix &&
       
   696                 i + KThree < aData.Length() )
       
   697             {
       
   698             // Four-byte presentation: 11110www 10xxxxxx 10yyyyyy 10zzzzzz
       
   699             if ( ( aData[i + 1] & KIRUtf8FollowingByteMask ) == KIRUtf8FollowingBytePrefix && 
       
   700                  ( aData[i + 2] & KIRUtf8FollowingByteMask ) == KIRUtf8FollowingBytePrefix && 
       
   701                  ( aData[i + KThree] & KIRUtf8FollowingByteMask ) == KIRUtf8FollowingBytePrefix )
       
   702                 {
       
   703                 foundUtf8 = ETrue;
       
   704                 }
       
   705             }
       
   706         else
       
   707             {
       
   708             // NOP
       
   709             }
       
   710         }
       
   711     IRLOG_DEBUG2( "CIRIcyFlowReader::IsUtf8Encoded - Returning %d", foundUtf8 );    
       
   712     return foundUtf8;
       
   713     }
       
   714