/******************************** * ProcessCommandMessage * ************************************/ void RTMPConnection::ProcessCommandMessage(DWORD streamId,RTMPCommandMessage* cmd) { //Get message values std::wstring name = cmd->GetName(); QWORD transId = cmd->GetTransId(); AMFData* params = cmd->GetParams(); //Log Log("-ProcessCommandMessage [streamId:%d,name:\"%ls\",transId:%ld]\n",streamId,name.c_str(),transId); //Check message Stream if (streamId) { //Check if a stream has been created with that id RTMPStreams::iterator it = streams.find(streamId); //If not found if (it==streams.end()) //Send error return SendCommandError(streamId,transId,NULL,NULL); //Get media stream RTMPStream* stream = it->second; //Check command names if (name.compare(L"play")==0) { //Get url to play std::wstring url = *(cmd->GetExtra(0)); //Set played data listener stream->SetPlayListener(this); //Play stream->Play(url); //Publish } else if (name.compare(L"publish")==0){ //Get url to play std::wstring url = *(cmd->GetExtra(0)); //Publish if (stream->Publish(url)) //OK SendCommandResponse(streamId,L"onStatus",transId,NULL,new RTMPNetStatusEvent(L"NetStream.Publish.Start",L"status",L"Playback started")); else //Not found SendCommandResponse(streamId,L"_error",transId,NULL,new RTMPNetStatusEvent(L"NetStream.Publish.Rejected",L"error",L"Stream not found")); } else if (name.compare(L"deleteStream")==0) { //Close stream just in case stream->Close(); //Delete object delete(stream); //Remove from streams streams.erase(it); //And do not send a replay return; } else if (name.compare(L"seek")==0) { //Get timestamp double time = *(cmd->GetExtra(0)); //Play stream->Seek(time); } else if (name.compare(L"closeStream")==0) { //Close stream stream->Close(); //Send response SendCommandResponse(streamId,L"onStatus",transId,NULL,new RTMPNetStatusEvent(L"NetStream.Connect.Closed",L"status",L"Netstream closed")); } else { //Debug cmd->Dump(); //Send command stream->PublishCommand(name.c_str(),cmd->GetParams()); } } else if (name.compare(L"connect")==0) { double objectEncoding = 0; //Check if we already have an active media stream if (app) //Send error return SendCommandError(streamId,transId); //Check we have params if (!params || !params->CheckType(AMFData::Object)) //Send error return SendCommandError(streamId,transId); //Get object AMFObject *obj = (AMFObject*)params; //Check if we have an app if (!obj->HasProperty(L"app")) //Send error return SendCommandError(streamId,transId); //Get url to connect appName = (std::wstring)obj->GetProperty(L"app"); //Get peer video capabilities if (obj->HasProperty(L"videoCodecs")) //Get value videoCodecs = (double)obj->GetProperty(L"videoCodecs"); //Check if we have peer audio capabilities if (obj->HasProperty(L"audioCodecs")) //Get peer audio capabilities audioCodecs = (double)obj->GetProperty(L"audioCodecs"); //Check if (obj->HasProperty(L"objectEncoding")) //Get object encoding used by client objectEncoding = (double)obj->GetProperty(L"objectEncoding"); //Call listener app = listener->OnConnect(appName); //If it is null if (!app) //Send error return SendCommandError(streamId,transId); //Send start stream SendControlMessage(RTMPMessage::UserControlMessage,RTMPUserControlMessage::CreateStreamBegin(0)); //Send window acknoledgement SendControlMessage(RTMPMessage::WindowAcknowledgementSize, RTMPWindowAcknowledgementSize::Create(512000)); //Send client bandwitdh SendControlMessage(RTMPMessage::SetPeerBandwidth, RTMPSetPeerBandWidth::Create(512000,2)); //Increase chunk size maxOutChunkSize = 1028; //Send client bandwitdh SendControlMessage(RTMPMessage::SetChunkSize, RTMPSetChunkSize::Create(maxOutChunkSize)); //Create params & extra info AMFObject* params = new AMFObject(); AMFObject* extra = new AMFObject(); AMFEcmaArray* data = new AMFEcmaArray(); objectEncoding = 3; //Add properties params->AddProperty(L"fmsVer" ,L"FMS/3,5,1,525"); params->AddProperty(L"capabilities" ,31.0); params->AddProperty(L"mode" ,1.0); extra->AddProperty(L"level" ,L"status"); extra->AddProperty(L"code" ,L"NetConnection.Connect.Success"); extra->AddProperty(L"description" ,L"Connection succeded"); extra->AddProperty(L"data" ,data); extra->AddProperty(L"objectEncoding" ,objectEncoding); data->AddProperty(L"version" ,L"3,5,1,525"); //Create SendCommandResult(streamId,transId,params,extra); } else if (name.compare(L"createStream")==0 || name.compare(L"initStream")==0) { //Check if we have an application if (!app) //Send error return SendCommandError(streamId,transId); //Assign the media string id DWORD mediaStreamId = maxStreamId++; //Call the application to create the stream RTMPStream *stream = app->CreateStream(mediaStreamId,appName,audioCodecs,videoCodecs); //Check if it was created correctly if (!stream) //Send error return SendCommandError(streamId,transId); //Add to the streams vector streams[mediaStreamId] = stream; //Create SendCommandResult(streamId,transId,new AMFNull(),new AMFNumber((double)mediaStreamId)); /* } else if (name.compare(L"FCPublish")==0) { //Check if we have an application if (!app) //Send error return SendCommandResponse(messageStreamId,new RTMPCommandError(transId,L"Not connected")); //Get url to play std::wstring url = *(cmd->GetExtra(0)); //Create return code AMFString* params = new AMFString(); //Create params & extra info AMFObject* extra = new AMFObject(); //Check publish extra->AddProperty(L"code",L"NetStream.Publish.Start"); extra->AddProperty(L"code",L"NetStream.Publish.BadName"); //Create SendCommandResponse(messageStreamId, new RTMPCommandResponse(L"onFCPublish",transId,NULL,extra)); */ } else { //Send SendCommandError(streamId,transId); } }
int FLVEncoder::StartEncoding() { Log(">Start encoding FLV [id:%d]\n",id); //Si estabamos mandando tenemos que parar if (encodingAudio || encodingVideo) //paramos StopEncoding(); //Set init time getUpdDifTime(&first); //Check if got old meta if (meta) //Delete delete(meta); //Create metadata object meta = new RTMPMetaData(0); //Set name meta->AddParam(new AMFString(L"@setDataFrame")); //Set name meta->AddParam(new AMFString(L"onMetaData")); //Create properties string AMFEcmaArray *prop = new AMFEcmaArray(); //Set audio properties switch(audioCodec) { case AudioCodec::SPEEX16: prop->AddProperty(L"audiocodecid" ,(float)RTMPAudioFrame::SPEEX ); //Number Audio codec ID used in the file (see E.4.2.1 for available SoundFormat values) prop->AddProperty(L"audiosamplerate" ,(float)16000.0 ); // Number Frequency at which the audio stream is replayed break; case AudioCodec::NELLY11: prop->AddProperty(L"audiocodecid" ,(float)RTMPAudioFrame::NELLY ); //Number Audio codec ID used in the file (see E.4.2.1 for available SoundFormat values) prop->AddProperty(L"audiosamplerate" ,(float)11025.0 ); // Number Frequency at which the audio stream is replayed break; case AudioCodec::NELLY8: prop->AddProperty(L"audiocodecid" ,(float)RTMPAudioFrame::NELLY8khz ); //Number Audio codec ID used in the file (see E.4.2.1 for available SoundFormat values) prop->AddProperty(L"audiosamplerate" ,(float)8000.0 ); // Number Frequency at which the audio stream is replayed break; } prop->AddProperty(L"stereo" ,new AMFBoolean(false) ); // Boolean Indicating stereo audio prop->AddProperty(L"audiodelay" ,0.0 ); // Number Delay introduced by the audio codec in seconds //Set video codecs if (videoCodec==VideoCodec::SORENSON) //Set number prop->AddProperty(L"videocodecid" ,(float)RTMPVideoFrame::FLV1 ); // Number Video codec ID used in the file (see E.4.3.1 for available CodecID values) else if (videoCodec==VideoCodec::H264) //AVC prop->AddProperty(L"videocodecid" ,new AMFString(L"avc1") ); // Number Video codec ID used in the file (see E.4.3.1 for available CodecID values) prop->AddProperty(L"framerate" ,(float)fps ); // Number Number of frames per second prop->AddProperty(L"height" ,(float)height ); // Number Height of the video in pixels prop->AddProperty(L"videodatarate" ,(float)bitrate ); // Number Video bit rate in kilobits per second prop->AddProperty(L"width" ,(float)width ); // Number Width of the video in pixels prop->AddProperty(L"canSeekToEnd" ,new AMFBoolean(false) ); // Boolean Indicating the last video frame is a key frame //Add param meta->AddParam(prop); //Send metadata SendMetaData(meta); //If got audio if (audioInput) { //We are enconding encodingAudio = 1; //Start thread createPriorityThread(&encodingAudioThread,startEncodingAudio,this,1); } //If got video if (videoInput) { //We are enconding encodingVideo = 1; //Start thread createPriorityThread(&encodingVideoThread,startEncodingVideo,this,1); } Log("<Stop encoding FLV [%d]\n",encodingAudio); return 1; }
bool RTMPMP4Stream::Play(std::wstring& url) { char filename[1024]; //Print it snprintf(filename,1024,"%ls",url.c_str()); //Open it and play if (!streamer.Open(filename)) { //Send error comand SendCommand(L"onStatus", new RTMPNetStatusEvent(L"NetStream.Play.StreamNotFound",L"error",L"Stream not found")); //Error return Error("Error opening mp4 file [path:\"%ls\"",filename); } //Send play comand SendCommand(L"onStatus", new RTMPNetStatusEvent(L"NetStream.Play.Reset",L"status",L"Playback reset") ); //Send play comand SendCommand(L"onStatus", new RTMPNetStatusEvent(L"NetStream.Play.Start",L"status",L"Playback started") ); //Create metadata object RTMPMetaData *meta = new RTMPMetaData(0); //Set name meta->AddParam(new AMFString(L"onMetaData")); //Create properties string AMFEcmaArray *prop = new AMFEcmaArray(); //Add default properties if (streamer.HasAudioTrack()) { switch (streamer.GetAudioCodec()) { case AudioCodec::PCMU: //Set properties prop->AddProperty(L"audiocodecid" ,(float)RTMPAudioFrame::SPEEX ); //Number Audio codec ID used in the file (see E.4.2.1 for available SoundFormat values) prop->AddProperty(L"audiodatarate" ,(float)16000 ); // Number Audio bit rate in kilobits per second //Set decoder decoder = new PCMUCodec(); //Set encode encoder = new SpeexCodec(); break; case AudioCodec::PCMA: prop->AddProperty(L"audiocodecid" ,(float)RTMPAudioFrame::SPEEX ); //Number Audio codec ID used in the file (see E.4.2.1 for available SoundFormat values) prop->AddProperty(L"audiodatarate" ,(float)16000 ); // Number Audio bit rate in kilobits per second //Set decoder decoder = new PCMACodec(); //Set encode encoder = new SpeexCodec(); break; } //prop->AddProperty(L"stereo" ,new AMFBoolean(false) ); // Boolean Indicating stereo audio prop->AddProperty(L"audiodelay" ,0.0 ); // Number Delay introduced by the audio codec in seconds prop->AddProperty(L"audiosamplerate" ,8000.0 ); // Number Frequency at which the audio stream is replayed prop->AddProperty(L"audiosamplesize" ,160.0 ); // Number Resolution of a single audio sample } //If ti has video track if (streamer.HasVideoTrack()) { switch (streamer.GetVideoCodec()) { case VideoCodec::H263_1996: case VideoCodec::H263_1998: prop->AddProperty(L"videocodecid" ,(float)RTMPVideoFrame::FLV1 ); // Number Video codec ID used in the file (see E.4.3.1 for available CodecID values) break; case VideoCodec::H264: prop->AddProperty(L"videocodecid" ,new AMFString(L"avc1") ); // Number Video codec ID used in the file (see E.4.3.1 for available CodecID values) break; } prop->AddProperty(L"framerate" ,(float)streamer.GetVideoFramerate() ); // Number Number of frames per second prop->AddProperty(L"height" ,(float)streamer.GetVideoHeight() ); // Number Height of the video in pixels prop->AddProperty(L"videodatarate" ,(float)streamer.GetVideoBitrate()/1024 ); // Number Video bit rate in kilobits per second prop->AddProperty(L"width" ,(float)streamer.GetVideoWidth() ); // Number Width of the video in pixels } prop->AddProperty(L"canSeekToEnd" ,0.0 ); // Boolean Indicating the last video frame is a key frame prop->AddProperty(L"duration" ,(float)streamer.GetDuration()); // Number Total duration of the file in seconds //Add param meta->AddParam(prop); //Send metadata PlayMetaData(meta); //Get AVC descriptor if any desc = streamer.GetAVCDescriptor(); //If we have one if (desc) { //Create the frame RTMPVideoFrame fdesc(0,desc); //Play it PlayMediaFrame(&fdesc); } //Play it if (!streamer.Play()) { //Close it streamer.Close(); //Send error comand SendCommand(L"onStatus", new RTMPNetStatusEvent(L"NetStream.Play.Error",L"error",L"Error openeing stream")); //Error return Error("Error starting playback of mp4 file [path:\"%ls\"",url.c_str()); } return true; }