Skip to main content
October 10, 2011
Question

Multi Point Publishing Live/VOD

  • October 10, 2011
  • 1 reply
  • 5098 views

Hello,

I've got a few questions.

1) I currently have multi point publishing set up to rebroadcast a stream between several servers. I'm running into an issue where even if it's a live stream, when a client connects, it starts from the beginning and you have to seek to the very end for it to go live. What could be causing this? I've attached my main.asc file

application.onAppStart = function()

{

    trace("Application name: " + application.name);

    trace("Server: " + application.server);

    _clientId = 0;

   

    application.s = new Array();

    application.a = new Array();

    application.v = new Array();

}

application.onConnect = function(clientObj)

{

    this.acceptConnection(clientObj);

}

Stream.prototype.trace = function(msg)

{

    trace(this.type + ":" + this.name + " - " + msg);

}

application.onPublish = function(clientObj, streamObj)

{

    var newpoint = application.name;

    var newpoint = newpoint.split("/");

    var newpoint = newpoint[1];

    // a race can happen during republish. if onPublish is called

    // before onUnpublish, we need to wait for onUnpublish to

    // complete before calling onPublish for the new stream.

    if (streamObj.publishing == true)

    {

        // onUnpublish has not been called yet

        //trace("Unpublish pending...");

        streamObj.publishingClient = clientObj; // save and call onPublish later

        return;

    }

    streamObj.publishing = true;

    trace("onPublish : " + streamObj.name);

    var queryString = streamObj.publishQueryString;

    var liveEventName = streamObj.name;

    var audioStreamSrc = "";

    var audioStreamName = "";

    var videoStreamSrc = "";

    var videoStreamName = "";

    var recordMode = "append";

   

    //trace("queryString["+queryString+"] stream["+streamObj.name+"]");

    if (queryString == undefined || (queryString.localeCompare("") == 0)) {

        /* Did not find query string so use the streamname as the event id */

        trace("Query string not specified. Using StreamName["+streamObj.name+"] as eventname");

   } else {

        /* Looking for name value pair adbe-live-event in the query string. If specified, use event name based on it. Otherwise, it is a single stream so you don't need to configure Event.xml and Manifest.xml */

        var nvpairs = new LoadVars();

        nvpairs.decode(queryString);

        for (var nv in nvpairs) {

            var nval = nvpairs[nv];

            /*trace("nv["+nv+"]=val["+nval+"]");*/

            if (nv.localeCompare("adbe-live-event")==0) {

                liveEventName = nval;

                /*trace("live event set to["+liveEventName+"]");*/

            }

            else if (nv.localeCompare("adbe-audio-stream-src") == 0)

            {

                audioStreamSrc = nval;

            }

            else if (nv.localeCompare("adbe-audio-stream-name") == 0)

            {

                audioStreamName = nval;

            }

            else if (nv.localeCompare("adbe-video-stream-src") == 0)

            {

                videoStreamSrc = nval;

            }

            else if (nv.localeCompare("adbe-video-stream-name") == 0)

            {

                videoStreamName = nval;

            }

            else if (nv.localeCompare("adbe-record-mode") == 0)

            {

                recordMode = nval;

            }

        }

    }

   

    var s = Stream.get("f4f:" + streamObj.name);

    if (s == undefined )

        return;

   

    if ((s.liveEvent != undefined)&&(s.liveEvent != "")&&(s.liveEvent != liveEventName)) {

        trace("Rejecting publish from client: "+clientObj.ip +" as stream: "+streamObj.name+

              " is already assigned to event: ["+s.liveEvent +"]");

        application.disconnect(clientObj);

       

        return;

    }

    s.onStatus = function(info)

    {

        this.trace(info.code);

    }

   

    s.liveEvent = liveEventName;

    trace("Stream name is: " + streamObj.name + " and live event is: "+s.liveEvent);

    s.play(streamObj.name,-1,-1);   

    if (!s.record(recordMode))

    {

        s.trace("record failed.");

    }

       

    application.s[streamObj.name] = s;

   

    // check if audio only stream is desired

    if (audioStreamName != "")

    {

        // if no stream src specified, use this stream

        if (audioStreamSrc == "")

        {

            audioStreamSrc = streamObj.name;

        }

   

        if (audioStreamSrc == streamObj.name)

        {

            //trace("Creating audio only stream " + audioStreamName + " from " + audioStreamSrc);

            var a = Stream.get("f4f:" + audioStreamName);

            a.onStatus = function(info)

            {

                this.trace(info.code);

            }

            a.receiveAudio = true;

            a.receiveVideo = false;

            a.liveEvent = liveEventName;

            a.play(audioStreamSrc, -1, -1);

            if (!a.record(recordMode))

            {

                a.trace("record failed.");

            }

            application.a[streamObj.name] = a;

        }

    }

   

    // check if video only stream is desired

    if (videoStreamName != "")

    {

        // if no stream src specified, use this stream

        if (videoStreamSrc == "")

        {

            videoStreamSrc = streamObj.name;

        }

   

        if (videoStreamSrc == streamObj.name)

        {

            //trace("Creating video only stream " + videoStreamName + " from " + videoStreamSrc);

            var v = Stream.get("f4f:" + videoStreamName);

            v.onStatus = function(info)

            {

                this.trace(info.code);

            }

            v.receiveAudio = false;

            v.receiveVideo = true;

            v.liveEvent = liveEventName;

            v.play(videoStreamSrc, -1, -1);   

            if (!v.record(recordMode))

            {

                v.trace("record failed.");

            }

            application.v[streamObj.name] = v;

        }

    }

var nc = new Array();

var ns = new Array();

nc[0] = new NetConnection();

nc[0].connect("rtmp://xxx.xxx.xxx.xxx/publishing/"+ newpoint);

ns[0] = new NetStream(nc[0]);

ns[0].setBufferTime(2);

ns[0].attach(streamObj);

ns[0].publish(streamObj.name + "?adbe-live-event=liveevent", "livepkgr");

    ns[0].onStatus = function(info) {

    trace("Stream Status: " + info.code)

        if (info.code == "NetStream.Publish.Start") {

        trace("The stream is now publishing to server 2");

        }          

    }

nc[1] = new NetConnection();

nc[1].connect("rtmp://xxx.xxx.xxx.xxx/publishing/"+ newpoint);

ns[1] = new NetStream(nc[1]);

ns[1].setBufferTime(2);

ns[1].attach(streamObj);

ns[1].publish(streamObj.name + "?adbe-live-event=liveevent", "livepkgr");

    ns[1].onStatus = function(info) {

    trace("Stream Status: " + info.code)

        if (info.code == "NetStream.Publish.Start") {

        trace("The stream is now publishing to server 3");

        }          

    }

}

application.onUnpublish = function(clientObj, streamObj)

{

    trace("onUnpublish : " + streamObj.name);

   

    var s = application.s[streamObj.name];

    if (s && s!= undefined)

    {

        s.record(false);

        s.play(false);

        s.liveEvent = "";

        application.s[streamObj.name] = null;

    }

    // is this the source for audio only stream?

    var a = application.a[streamObj.name];

    if (a && a != undefined)

    {

        //trace("Removing audio only stream " + a.name + " : source = " + streamObj.name);

        a.record(false);

        a.play(false);

        a.liveEvent = "";

        application.a[streamObj.name] = null;

    }

    // is this the source for video only stream?

    var v = application.v[streamObj.name];

    if (v && v != undefined)

    {

        //trace("Removing video only stream " + v.name + " : source = " + streamObj.name);

        v.record(false);

        v.play(false);

        v.liveEvent = "";

        application.v[streamObj.name] = null;

    }

    streamObj.publishing = false;   

    if (streamObj.publishingClient != undefined &&

        streamObj.publishingClient != null)

    {

        // onPublish was suspended pending completion of onUnpublish

        // call it now.

        application.onPublish(streamObj.publishingClient, streamObj);

        streamObj.publishingClient = null;

    }

}

/*

* FCPublish :

* FMLE calls FCPublish with the name of the stream whenever a new stream

* is published. This notification can be used by server-side action script

* to maintain list of all streams or to force FMLE to stop publishing.

* To stop publishing, call "onFCPublish" with an info object with status

* code set to "NetStream.Publish.BadName".

*/

Client.prototype.FCPublish = function( streamname )

{

 

    // setup your stream and check if you want to allow this stream to be published

    if ( true) // do some validation here

    {      // this is optional.

        this.call("onFCPublish", null, {code:"NetStream.Publish.Start", description:streamname});

    }

    else

    {

        this.call("onFCPublish", null, {code:"NetStream.Publish.BadName", description:streamname});

    }

       

}

/*

* FCUnpublish :

* FMLE notifies the server script when a stream is unpublished.

*/

Client.prototype.FCUnpublish = function( streamname )

{

    // perform your clean  up

    this.call("onFCUnpublish", null, {code:"NetStream.Unpublish.Success", description:streamname});

}

/*

* releaseStream :

* When an FMLE connection to FMS drops during a publishing session it

* tries to republish the stream when the connection is restored. On certain

* occasions, FMS rejects the new stream because the server is still

* unaware of the connection drop, sometimes this can take a few minutes.

* FMLE calls the "releaseStream" method with the stream name and this can be

* used to forcibly clear the stream.

*/

Client.prototype.releaseStream = function(streamname)

{

    var s = Stream.get(streamname);

    if (s) {

        s.play(false);

    }

}

2) Is there any way to set up multi point publishing on Video on Demand files?

3) Say server 2 has restarted, is there anyway to force a push to that server without having to restart the feed?

Thanks for all of your help!

    This topic has been closed for replies.

    1 reply

    Nikhil_Kalyan
    Participating Frequently
    October 11, 2011

    Hi,

    Thanks for the details.

    It is visible that you are using f4f files for recording. Are you trying to simulate the HDS workflow for FMS or do you a pure VOD on RTMP ? Why this is important is that, VOD on RTMP is not officially supported for f4f files that you are trying to record. Change to f4v and try to see the behavior.

    Next, I didn't go through each line in the code above but, if you are recording, try not to use record in append mode : s.record(append), instead, just record it : s.record(). This will overwrite all the exisiting content whenever the recording is restarted/republished.

    If you are using the HDS workflow, can you please check your manifest.xml to see if there is no DVR tags set ?

    Thank you !

    October 11, 2011

    Thanks for the answer Nikhil, Yes, We are simulating the HDS workflow for FMS, Does this make a difference?

    I've changed the recording mode - Thanks.

    Where do I find the Manifest.xml, from what I know, it should be in the /events folder where Event.xml is, but I have no manifest file there. Should I create one? What should it look like?

    Thanks again for your help!

    Nikhil_Kalyan
    Participating Frequently
    October 11, 2011

    As i mentioned, for RTMP , f4f format is not supported, while for HDS it is supported and hence that point is needed to be confirmed.

    If you are using the default livepkgr application, there must be a event.xml and a manifest.xml. in the applications\livepkgr\events\_definst_\liveevent\ folder.

    append mode should not ideally create any problem, but that you can change/play around with, once we identify the problem here.

    Are you also trying to sort of convert live to vod ? If that is the case, then it is also not directly supported for f4f, but there must be a workaround