/* * \brief Play MP3 stream. * * \param stream Socket stream to read MP3 data from. */ void PlayMp3Stream(FILE *stream, u_long metaint) { size_t rbytes; u_char *mp3buf; u_char ief; int got = 0; u_long last; u_long mp3left = metaint; /* * Initialize the MP3 buffer. The NutSegBuf routines provide a global * system buffer, which works with banked and non-banked systems. */ if (NutSegBufInit(8192) == 0) { puts("Error: MP3 buffer init failed"); return; } /* * Initialize the MP3 decoder hardware. */ if (VsPlayerInit() || VsPlayerReset(0)) { puts("Error: MP3 hardware init failed"); return; } VsSetVolume(0, 0); /* * Reset the MP3 buffer. */ ief = VsPlayerInterrupts(0); NutSegBufReset(); VsPlayerInterrupts(ief); last = NutGetSeconds(); for (; ;) { if(STOP_THREAD){ STOP_THREAD = 0; return; } /* * Query number of byte available in MP3 buffer. */ ief = VsPlayerInterrupts(0); mp3buf = NutSegBufWriteRequest(&rbytes); VsPlayerInterrupts(ief); /* * If the player is not running, kick it. */ if (VsGetStatus() != VS_STATUS_RUNNING) { if (rbytes < 1024 || NutGetSeconds() - last > 4UL) { last = NutGetSeconds(); puts("Kick player"); VsPlayerKick(); } } /* * Do not read pass metadata. */ if (metaint && rbytes > mp3left) { rbytes = mp3left; } /* * Read data directly into the MP3 buffer. */ while (rbytes) { if ((got = fread(mp3buf, 1, rbytes, stream)) > 0) { ief = VsPlayerInterrupts(0); mp3buf = NutSegBufWriteCommit(got); VsPlayerInterrupts(ief); if (metaint) { mp3left -= got; if (mp3left == 0) { ProcessMetaData(stream); mp3left = metaint; } } if (got < rbytes && got < 512) { printf("%lu buffered\n", NutSegBufUsed()); NutSleep(250); } else { NutThreadYield(); } } else { break; } rbytes -= got; } if (got <= 0) { break; } NutSleep(100); } }
/*********************** * ParseData * Process incomming data **********************/ void RTMPConnection::ParseData(BYTE *data,const DWORD size) { RTMPChunkInputStreams::iterator it; int len = 0; int digesOffsetMethod = 0; //Get pointer and data size BYTE *buffer = data; DWORD bufferSize = size; DWORD digestPosServer = 0; //Increase current window curWindowSize += size; //And total size recvSize += size; //Check current window if (windowSize && curWindowSize>windowSize) { //Send SendControlMessage(RTMPMessage::Acknowledgement,RTMPAcknowledgement::Create(recvSize)); //Reset window curWindowSize = 0; } //While there is data while(bufferSize>0) { //Check connection state switch(state) { case HEADER_C0_WAIT: //Parse c0 len = c0.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (c0.IsParsed()) { //Move to next state state = HEADER_C1_WAIT; //Debug Log("Received c0 version: %d\n",c0.GetRTMPVersion()); } break; case HEADER_C1_WAIT: //Parse c1 len = c1.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (c1.IsParsed()) { Log("-Received C1 client version [%d,%d,%d,%d]\n",c1.GetVersion()[0],c1.GetVersion()[1],c1.GetVersion()[2],c1.GetVersion()[3]); //Set s0 data s01.SetRTMPVersion(3); //Set current timestamp s01.SetTime(getDifTime(&startTime)/1000); //Check which version are we using if (c1.GetVersion()[3]) { //Verify client digesOffsetMethod = VerifyC1Data(c1.GetData(),c1.GetSize()); //Set version s01.SetVersion(3,5,1,1); //Check if found diggest ofset digest = (digesOffsetMethod>0); } else { //Seet version to zero s01.SetVersion(0,0,0,0); //Do not calculate digest digest = false; } //Set random data from memory BYTE* random = s01.GetRandom(); //Fill it for (int i=0;i<s01.GetRandomSize();i++) //With random random[i] = rand(); //If we have to calculate digest if (digest) //calculate digest for s1 only, skipping s0 digestPosServer = GenerateS1Data(digesOffsetMethod,s01.GetData()+1,s01.GetSize()-1); //Send S01 data WriteData(s01.GetData(),s01.GetSize()); //Move to next state state = HEADER_C2_WAIT; //Debug Log("Sending s0 and s1 with digest %s offset method %d\n",digest?"on":"off",digesOffsetMethod); } break; case HEADER_C2_WAIT: //Parse c2 len = c2.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (c2.IsParsed()) { //Set s2 data s2.SetTime(c1.GetTime()); //Set current timestamp s2.SetTime2(getDifTime(&startTime)/1000); //Echo c1 data s2.SetRandom(c1.GetRandom(),c1.GetRandomSize()); //If we have to calculate digest if (digest) //calculate digest for s1 GenerateS2Data(digesOffsetMethod,s2.GetData(),s2.GetSize()); //Send S2 data WriteData(s2.GetData(),s2.GetSize()); //Move to next state state = CHUNK_HEADER_WAIT; //Debug Log("Received c2, sending c2. CONNECTED.\n"); } break; case CHUNK_HEADER_WAIT: //Parse c2 len = header.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (header.IsParsed()) { //Clean all buffers type0.Reset(); type1.Reset(); type2.Reset(); extts.Reset(); //Move to next state state = CHUNK_TYPE_WAIT; //Debug //Log("Received header [fmt:%d,stream:%d]\n",header.GetFmt(),header.GetStreamId()); //header.Dump(); } break; case CHUNK_TYPE_WAIT: //Get sream id chunkStreamId = header.GetStreamId(); //Find chunk stream it = chunkInputStreams.find(chunkStreamId); //Check if we have a new chunk stream or already got one if (it==chunkInputStreams.end()) { //Log //Log("Creating new chunk stream [id:%d]\n",chunkStreamId); //Create it chunkInputStream = new RTMPChunkInputStream(); //Append it chunkInputStreams[chunkStreamId] = chunkInputStream; } else //Set the stream chunkInputStream = it->second; //Switch type switch(header.GetFmt()) { case 0: //Check if the buffer type has been parsed len = type0.Parse(buffer,bufferSize); //Check if it is parsed if (type0.IsParsed()) { //Debug //Debug("Got type 0 header [timestamp:%lu,messagelength:%d,type:%d,streamId:%d]\n",type0.GetTimestamp(),type0.GetMessageLength(),type0.GetMessageTypeId(),type0.GetMessageStreamId()); //type0.Dump(); //Set data for stream chunkInputStream->SetMessageLength (type0.GetMessageLength()); chunkInputStream->SetMessageTypeId (type0.GetMessageTypeId()); chunkInputStream->SetMessageStreamId (type0.GetMessageStreamId()); //Check if we have extended timestamp if (type0.GetTimestamp()!=0xFFFFFF) { //Set timesptamp chunkInputStream->SetTimestamp(type0.GetTimestamp()); //No timestamp delta chunkInputStream->SetTimestampDelta(0); //Move to next state state = CHUNK_DATA_WAIT; } else //We have to read 4 more bytes state = CHUNK_EXT_TIMESTAMP_WAIT; //Start data reception chunkInputStream->StartChunkData(); //Reset sent bytes in buffer chunkLen = 0; } break; case 1: //Check if the buffer type has been parsed len = type1.Parse(buffer,bufferSize); //Check if it is parsed if (type1.IsParsed()) { //Debug //Debug("Got type 1 header [timestampDelta:%u,messagelength:%d,type:%d]\n",type1.GetTimestampDelta(),type1.GetMessageLength(),type1.GetMessageTypeId()); //type1.Dump(); //Set data for stream chunkInputStream->SetMessageLength(type1.GetMessageLength()); chunkInputStream->SetMessageTypeId(type1.GetMessageTypeId()); //Check if we have extended timestam if (type1.GetTimestampDelta()!=0xFFFFFF) { //Set timestamp delta chunkInputStream->SetTimestampDelta(type1.GetTimestampDelta()); //Set timestamp chunkInputStream->IncreaseTimestampWithDelta(); //Move to next state state = CHUNK_DATA_WAIT; } else //We have to read 4 more bytes state = CHUNK_EXT_TIMESTAMP_WAIT; //Start data reception chunkInputStream->StartChunkData(); //Reset sent bytes in buffer chunkLen = 0; } break; case 2: //Check if the buffer type has been parsed len = type2.Parse(buffer,bufferSize); //Check if it is parsed if (type2.IsParsed()) { //Debug //Debug("Got type 2 header [timestampDelta:%lu]\n",type2.GetTimestampDelta()); //type2.Dump(); //Check if we have extended timestam if (type2.GetTimestampDelta()!=0xFFFFFF) { //Set timestamp delta chunkInputStream->SetTimestampDelta(type2.GetTimestampDelta()); //Increase timestamp chunkInputStream->IncreaseTimestampWithDelta(); //Move to next state state = CHUNK_DATA_WAIT; } else //We have to read 4 more bytes state = CHUNK_EXT_TIMESTAMP_WAIT; //Start data reception chunkInputStream->StartChunkData(); //Reset sent bytes in buffer chunkLen = 0; } break; case 3: //Debug("Got type 3 header\n"); //No header chunck len = 0; //If it is the first chunk if (chunkInputStream->IsFirstChunk()) //Increase timestamp with previous delta chunkInputStream->IncreaseTimestampWithDelta(); //Start data reception chunkInputStream->StartChunkData(); //Move to next state state = CHUNK_DATA_WAIT; //Reset sent bytes in buffer chunkLen = 0; break; } //Move pointer buffer += len; bufferSize -= len; break; case CHUNK_EXT_TIMESTAMP_WAIT: //Parse extended timestamp len = extts.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (extts.IsParsed()) { //Check header type if (header.GetFmt()==1) { //Set the timestamp chunkInputStream->SetTimestamp(extts.GetTimestamp()); //No timestamp delta chunkInputStream->SetTimestampDelta(0); } else { //Set timestamp delta chunkInputStream->SetTimestampDelta(extts.GetTimestamp()); //Increase timestamp chunkInputStream->IncreaseTimestampWithDelta(); } //Move to next state state = CHUNK_DATA_WAIT; } break; case CHUNK_DATA_WAIT: //Check max buffer size if (maxChunkSize && chunkLen+bufferSize>maxChunkSize) //Parse only max chunk size len = maxChunkSize-chunkLen; else //parse all data len = bufferSize; //Check size if (!len) { //Debug Error("Chunk data of size zero [maxChunkSize:%d,chunkLen:%d]\n"); //Skip break; } //Parse data len = chunkInputStream->Parse(buffer,len); //Check if it has parsed a msg if (chunkInputStream->IsParsed()) { //Log("Got message [timestamp:%lu]\n",chunkInputStream->GetTimestamp()); //Get message RTMPMessage* msg = chunkInputStream->GetMessage(); //Get message stream DWORD messageStreamId = msg->GetStreamId(); //Check message type if (msg->IsControlProtocolMessage()) { //Get message type BYTE type = msg->GetType(); //Get control protocl message RTMPObject* ctrl = msg->GetControlProtocolMessage(); //Procces msg ProcessControlMessage(messageStreamId,type,ctrl); } else if (msg->IsCommandMessage()) { //Get Command message RTMPCommandMessage* cmd = msg->GetCommandMessage(); //Dump msg cmd->Dump(); //Proccess msg ProcessCommandMessage(messageStreamId,cmd); } else if (msg->IsMedia()) { //Get media frame RTMPMediaFrame* frame = msg->GetMediaFrame(); //Check if we have it if (frame) //Process message ProcessMediaData(messageStreamId,frame); } else if (msg->IsMetaData() || msg->IsSharedObject()) { //Get object RTMPMetaData *meta = msg->GetMetaData(); //Debug it meta->Dump(); //Process meta data ProcessMetaData(messageStreamId,meta); } else { //UUh?? Error("Unknown rtmp message, should never happen\n"); } //Delete msg delete(msg); //Move to next chunck state = CHUNK_HEADER_WAIT; //Clean header header.Reset(); } //Increase buffer length chunkLen += len; //Move pointer buffer += len; bufferSize -= len; //Check max chunk size if (maxChunkSize && chunkLen>=maxChunkSize) { //Wait for next buffer header state = CHUNK_HEADER_WAIT; //Clean header header.Reset(); } break; } } }