⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shoutcaststream.cpp

📁 这是一个使用 ShortCast的IP网络流式播放的symbian的软件源码.里面有ShortCast短播协议的实现以及AAC音频,MP3音频流式播放的实现.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// Pauses the playback but the engine continues to receive data from the
// network. The stream output is stopped.
// -----------------------------------------------------------------------------
//
void CShoutcastStream::Pause()
	{
	iStreamOutput->Stop();
	LOG("PauseL, OK");
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::Stop
// Stops the playback. The engine stops receiving data from the
// network. The stream output is stopped.
// -----------------------------------------------------------------------------
//
void CShoutcastStream::Stop()
	{
	LOG("StopL");
	if ( iState == EData )
		{
		iStreamOutput->Stop();
		}
	//we have to undo all that the PrimeL function did
	Cancel();//make sure we do not have any request pending
	CloseAndClean();
	//we expect that Prime & Play to be called in order to play again
	LOG("StopL OK");
	}


// -----------------------------------------------------------------------------
// CShoutcastStream::DoCancel
// Cancels any outstanding requests
// -----------------------------------------------------------------------------
//
void CShoutcastStream::DoCancel()
	{
	LOG("DoCancel was called!!!");
	iSock.CancelAll();
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::RunL
// Invoked when one of these requests completes.
// -----------------------------------------------------------------------------
//
void CShoutcastStream::RunL()
	{
	switch ( iState )
		{
		case EConnecting:
			SendRequestToServerL();
			break;
		case ESendingRequest:
			ReceiveResponseFromServerL();
			break;
		case EReceivingResponse:
			ParseResponseFromServerL();
			break;
		case EData:
			{
			if ( iStatus != KErrNone )
				{
				CloseAndClean();
				Disconnect(iStatus.Int());
				return;
				}
			if ( ReadRequestHelperDone() != KErrNone )
				{
				CloseAndClean();
				Disconnect(iStatus.Int());
				return;
				}
			};
			break;
		default:
			ASSERT(0);
		}
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::RunError
// Called when the RunL leaves.
// If we are here, it means that we failed to connect somehow!
// -----------------------------------------------------------------------------
//
TInt CShoutcastStream::RunError(
	TInt aError )
	{
	//send the error as an event to the client
	iDispatcher->SendEvent(TUid::Uid(KShoutcastStreamUid), aError);
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::GetNumberOfMetaDataEntries
// Get number of metadata entries
// -----------------------------------------------------------------------------
//
TInt CShoutcastStream::GetNumberOfMetaDataEntries()
	{
	return NR_METADATA_FIELDS;
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::GetNumberOfMetaDataEntries
// Get a particular metadata entry.
// -----------------------------------------------------------------------------
//
CMetaDataEntry* CShoutcastStream::GetMetaDataEntryL(
	TInt aIndex )
	{
	//check if this is "special" metadata

	//LOG("GetMetaDataEntryL");

	if( aIndex == KShoutcastMetaData_URL )
		{
		CMetaDataEntry *mmfMetadata;
		iTempMetadata.Copy(iURL);
		mmfMetadata = CMetaDataEntry::NewL(KSCMetaServer, iTempMetadata);
		return mmfMetadata;
		};

	//this is normal metadata
	if ( aIndex >= iMetadata.Count() )
		{
		return NULL;
		}
	else
		{
		CMetaDataEntry* md = iMetadata[aIndex];
		md = CMetaDataEntry::NewL(*md);
		return md;
		}
	}


// -----------------------------------------------------------------------------
// CShoutcastStream::ReadRequest
// The read request is done when all the requested data has been read.
// The read request is made intelligently:
// 		-first, we read until the metadata count byte.
//		-if we have metadata, then we read metadata (in a separate buffer),
//		-then we read what is left
// -----------------------------------------------------------------------------
//
void CShoutcastStream::ReadRequest()
{
	TInt data2read = DATA2READ;
	TUint8 *buffer2read = NULL;

	if ( iReadData == -1)
		{
		//case 1: the buffer is partially filled (data is in the middle)
		//we have to read from iBuffer2Decode+iPosBuffer2Decode+iLenBuffer2Decode
		//... 8k (DATA2READ)
		//... or until the end of the buffer
		if ( data2read > BUFFER2DECODE_SIZE-iPosBuffer2Decode-iLenBuffer2Decode )
			{
			data2read = BUFFER2DECODE_SIZE-iPosBuffer2Decode-iLenBuffer2Decode;
			}
		//check for transition to case 2
		if ( data2read < READ_EPSILON && iPosBuffer2Decode>iMaxFrameSize )
			{
			//go to case 2
			iReadData = 0;
			//LOG2("RR transition case 1->case 2 (pos=%d, len=%d)",iPosBuffer2Decode,iLenBuffer2Decode);
			ReadRequest();
			return;
			}
		else
			{
			//stick to case 1
			buffer2read = iBuffer2Decode+iPosBuffer2Decode+iLenBuffer2Decode;
			//LOG1("RR case 1: have to read %d bytes",data2read);
			}
		}
	else
		{
		//case 2: we fill the buffer from the beginning (or from the middle)
		//we have to read from iBuffer2Decode+iMaxFrameSize+iReadData
		//... 8k (DATA2READ)
		//... or until the data (iPosBuffer2Decode)
		ASSERT(iReadData >= 0);
		ASSERT(iMaxFrameSize >= 0);
		ASSERT(iMaxFrameSize < 3000);
		ASSERT(iPosBuffer2Decode >= iMaxFrameSize);
		ASSERT(iMaxFrameSize + iReadData <= iPosBuffer2Decode);
		if ( iMaxFrameSize+iReadData+data2read > iPosBuffer2Decode )
			{
			data2read = iPosBuffer2Decode-iMaxFrameSize-iReadData;
			}
		buffer2read = iBuffer2Decode+iMaxFrameSize+iReadData;
		//LOG1("RR case 2: have to read %d bytes",data2read);
		}

	if ( data2read < READ_EPSILON )
		{
		//the buffer looks completely full!
		// suspend the read
		iReadingActive = EFalse;
		//LOG("RR OK (buffer full, no reading)");

		if ( iPausedForBuffering ) // in case we have paused playback for buffering...
			{
			TRAPD(err, PlayL());
			if ( err )
				{
				iDispatcher->SendEvent(TUid::Uid(KShoutcastStreamUid), err);
				}
			else
				{
				// send buffering complete event!!
				iDispatcher->SendEvent(TUid::Uid(KShoutcastStreamUid),KShoutcastEvent_BufferingComplete);
				}
			}
		}
	else
		{
		//we need to read data!
		ASSERT(data2read > 0);
		iPtrBuffer2Decode.Set(buffer2read,0,data2read);
		iReadingActive = ETrue;
		iRRreq = data2read;
		iRRread = 0;
		//LOG1("RR OK (will read %d bytes)",data2read);
		ReadRequestHelper();
		}
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::ReadRequestHelper
// Read the requested amount of data from the socket. When the asynchronous read
// completes, our RunL will be called.
// -----------------------------------------------------------------------------
//
void CShoutcastStream::ReadRequestHelper()
	{
	//read from the socket
	iSock.Read(iPtrBuffer2Decode,iStatus);
	SetActive();
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::ReadRequestHelperDone
// The read request is completed. Extract metadata from the buffer if there's
// any and request additional reads if the buffer wasn't full.
// -----------------------------------------------------------------------------
//
TInt CShoutcastStream::ReadRequestHelperDone()
	{
	TInt readSize = iPtrBuffer2Decode.Size();
	TInt maxSize = iPtrBuffer2Decode.MaxSize();
	//LOG2("RRHD read %d (status: %d)",readSize,iStatus.Int());

	GetAndRemoveMetadata(const_cast<TUint8*>(iPtrBuffer2Decode.Ptr()),readSize);

	iRRread+=readSize;

	//check if we have read the full length
	if ( maxSize-readSize<5 || (readSize==0 && iStatus.Int()==0) )
		{
		//this reading is done!
		return ReadRequestDone(iRRreq,iRRread);
		}

	//LOG2("RRHD: Partial read of %d, requesting again %d bytes",readSize,maxSize-readSize);
	iPtrBuffer2Decode.Set(const_cast<TUint8*>(iPtrBuffer2Decode.Ptr())+readSize,0,maxSize-readSize);
	ReadRequestHelper();

	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::ReadRequestDone
// The entire read request buffer is full. Now process the contents and re-new
// the read request.
// -----------------------------------------------------------------------------
//
TInt CShoutcastStream::ReadRequestDone(
	TInt aRequested,
	TInt aRead )
	{
	TInt bufferFill;
	TInt avgBitrate = 0;
	TInt metadataInd = 0;

	//if we are here, it means that we read normal data
	//LOG2("RRD: We have read normal data (req=%d, read=%d)",aRequested,aRead);
	iTotalBytesReceived += aRead;

	// 100kb: 1024*100 = 102400 (decimal)
	// 1MB: 1048576 binary bytes
	// In order to get exactly 0.1 MB, and for easy calculation, the constant 104857 is used here.

	//every 100kB we signal metadata modifications
	if( (iNrHKB+1) * K100kBFactor < iTotalBytesReceived )
		{
		iNrHKB++;
		//some more metadata
		iTempMetadata.Format(KSCDataRcvdFormat, iTotalBytesReceived/K1MBFactor);
		// It's ok if we can't set the value.
		TRAPD(err,
			{
			iMetadata[4]->SetValueL(iTempMetadata);
			iTempMetadata.Format(KSCMetaPriceFormat, iTotalBytesReceived/K1MBFactor * PRICE_PER_MB);
		    iMetadata[5]->SetValueL(iTempMetadata);
			});

		if ( !err )
			{
			// Indicate which metadata was updated
			metadataInd = 0x0130;
			}
		}

	//do something with the data we just read!
	if( iReadData == -1)
		{
		//case 1: we should increase the data length
		iLenBuffer2Decode+=aRead;
		bufferFill=(TInt)(100.0*iLenBuffer2Decode/(BUFFER2DECODE_SIZE-iMaxFrameSize));
		}
	else
		{
		//case 2: we need to increase the iReadData
		iReadData += aRead;
		bufferFill = (TInt)(100.0*(iLenBuffer2Decode+iReadData)/(BUFFER2DECODE_SIZE-iMaxFrameSize));
		}

	//compute bitrate
	if( iLastReading.Int64() == 0)
		{
		iLastReading.UniversalTime();
		}
	else
		{
		TInt i,tbits;
		TTime now;
		TInt64 avg;
		now.UniversalTime();
		TInt64 diff=now.Int64()-iLastReading.Int64();
		TInt bits=(TInt)(aRead*7812.5);//7812.5=8*1000*1000/1024 (8=bits, 1024=kbits, 100000 from microseconds)
		if(diff>0) //this is to avoid division by zero on EKA1 kernels
                {

#ifdef __SERIES60_3X__
                  iInstantBitrate=(TInt)(bits/diff);
#else //2.x
		  iInstantBitrate=bits/diff.GetTInt();
#endif
                };//if diff is zero, we keep the old value
		//compute now the averaged bitrate
                iBitsRead.Append(bits);
		iTimeIntervals.Append(diff);
		ASSERT(iBitsRead.Count()==iTimeIntervals.Count());
		tbits=iBitsRead[0];
		avg=iTimeIntervals[0];
		for( i = 1; i < iBitsRead.Count(); i++)
			{
			tbits += iBitsRead[i];
			avg += iTimeIntervals[i];
			};

#ifdef __SERIES60_3X__
        avgBitrate=(TInt)(tbits/avg);
#else //2.x
		avgBitrate=tbits/avg.GetTInt();
#endif
		if( iBitsRead.Count() > BITRATE_SAVE_COUNT )
			{
			iBitsRead.Remove(0);
			iTimeIntervals.Remove(0);
			}
		iLastReading=now;
		}

	//fill buffering metadata
	if ( bufferFill > 100)
		{
		bufferFill=100;//this can happen when a part of iMaxFrameSize is also filled
		}

	TRAPD(err,
		{
		iTempMetadata.Format(KSCBufFormat, bufferFill);
		iMetadata[6]->SetValueL(iTempMetadata);
		iTempMetadata.Format(KSCMetaBitrateFormat, avgBitrate, iInstantBitrate);
		iMetadata[7]->SetValueL(iTempMetadata);
		});

	if ( !err )
		{
		// Indicate which metadata was updated
		metadataInd = metadataInd | 0x01C0;
		}

	// Send metadata update event to client
	iDispatcher->SendEvent(TUid::Uid(KShoutcastStreamUid), metadataInd);

	//if we are here, it means that we have finished reading our data!!
	//LOG1("RRD: Done reading %d bytes",aRead);

	//Read again!
	ReadRequest();

	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::RemoveMetadata
// Remove metadata from the buffer
// -----------------------------------------------------------------------------
//
void CShoutcastStream::RemoveMetadata(
	TDes8& ptrMetadata )
	{
	ASSERT(iMetaint > 0);//we have metadata

	TInt pos1,pos2;
	pos1 = ptrMetadata.Find(KSCStreamTitle);
	pos2 = ptrMetadata.Find(_L8("';"));

	if ( pos1 != KErrNotFound && pos2 != KErrNotFound )
		{
		//use pos2 as length
		pos2 = pos2-pos1-13;//13 is the number of characters in "StreamTitle='"
		if ( pos2 > iTempMetadata.MaxLength() )
			{
			pos2=iTempMetadata.MaxLength();
			}
		iTempMetadata.Copy(ptrMetadata.Mid(pos1+13,pos2));
		TRAPD(err, iMetadata[3]->SetValueL(iTempMetadata));
		//LOG2("MD: Metadata(%d):(%S)", pos2, &iTempMetadata);
		// Send metadata event to the client
		if ( !err )
			{
			iDispatcher->SendEvent(TUid::Uid(KShoutcastStreamUid),0x0108);
			}
		}
	else
		{
		//LOG("MD: Metadata found but Title NOT FOUND !!! ");
		}
	}

// -----------------------------------------------------------------------------
// CShoutcastStream::GetAndRemoveMetadata
// Get the metadata and remove it from the data stream
// -----------------------------------------------------------------------------
//
void CShoutcastStream::GetAndRemoveMetadata(
	TUint8 *aBuf,
	TInt &aLength )
	{
	if ( iMetaint == 0 )
		{
		return; //we do not have metadata!
		}

	TInt dataLength = aLength;
	TInt pos = 0;

	while ( iCnt < dataLength )
		{
		dataLength -= iCnt;
		pos += iCnt;
		//we have metadata here!
		iDataSeen = 16 * aBuf[pos];
		//LOG1("MD: Found Metadata %d bytes",iDataSeen);
		if ( iDataSeen )
			if ( iDataSeen < METADATA_BUFFER_SIZE )
				{
				//we really have metadata!
				TPtr8 ptrMetadata(aBuf+pos+1,iDataSeen,iDataSeen);
				RemoveMetadata(ptrMetadata);
				}
			else
				{
				//we lost the sync
				ASSERT(0);
				}
		//remove the metadata
		iDataSeen++;
		//LOG2("Removing metadata: pos=%d, removed=%d",pos,iDataSeen);
		memmove(aBuf+pos,aBuf+pos+iDataSeen,aLength-pos-iDataSeen);
		iCnt = iMetaint;
		aLength -= iDataSeen;
		dataLength -= iDataSeen;
		//LOG1("After memmove: aLength=%d",aLength);
		}
	iCnt -= dataLength;
	//LOG2("MD: we exit with %d bytes (cnt is %d)",aLength,iCnt);
	}


// -----------------------------------------------------------------------------
// CShoutcastStream::ScanHeader
// -----------------------------------------------------------------------------
//
TInt CShoutcastStream::ScanHeader(
	TUint8 *aBuf,
	TInt aLength )
	{

	TInt length = 0;
    TInt readLen = aLength;
    TInt seekLen;
    const TUint8* seekPtr;
    TInt seekOffset;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -