Skip to main content
Inspiring
October 5, 2010
Answered

Relay application

  • October 5, 2010
  • 1 reply
  • 1824 views

Hi,

Is there any application which can relay another application on Flash Media server?

For exmaple I have a "live" application on the server. I want another application, "liverelay" which can basically relay what is coming on the "live" application.

Is it possible? If so how can I implement it?

Looking forward to a response.

Thanks

    This topic has been closed for replies.
    Correct answer SE_0208

    Thanks for your reply!

    I have managed to get it working though not exactly what I wanted.

    Reading your answer in this post: http://forums.adobe.com/message/3079910#3079910

    I created two new application as per your instructions - app_1 & app_2 - both on the same servers - stream to app_1 and app_2 automatically relayed what was coming on app_1 - which is great and 50% answers my problem!

    What I want to do is edit the existing !main application that I have, namely "live" and edit the main.asc in there which will then allow me to relay to app_2

    Here is the current code in main.asc in "live" application

    Where do I insert the code of app_1 in this code so that it allows app_2 to relay?

    ===================================================

    /*

    * application.onConnect:

    * Implementation of the onConnect interface function (optional).

    *  it is invoked whenever a client connection request connection. Live app uses this

    *  function to authenticate the domain of connection and authorizes only

    *  for a subscriber request.

    */

    application.onConnect = function( p_client, p_autoSenseBW )

    {

    // Check if pageUrl is from a domain we know.

    // Check pageurl

    // A request from Flash Media Encoder is not checked for authentication

    if( (p_client.agent.indexOf("FME")==-1) && (p_client.agent.indexOf("FMLE")==-1))

    {

    // Authenticating HTML file's domain for the request :

    // Don't call validate() when the request is from localhost

    // or HTML Domains Authentication is off.

    if ((p_client.ip != "127.0.0.1") && application.HTMLDomainsAuth

    &&  !this.validate( p_client.pageUrl, this.allowedHTMLDomains ) )

    {

    trace("Authentication failed for pageurl: " + p_client.pageUrl + ", rejecting connection from "+p_client.ip);

    return false;

    }

    // Authenticating the SWF file's domain for the request :

    // Don't call validate() when the request is from localhost

    // or SWF Domains Authentication is off.

    if ((p_client.ip != "127.0.0.1") && application.SWFDomainsAuth

    &&  !this.validate( p_client.referrer, this.allowedSWFDomains ) )

    {

    trace("Authentication failed for referrer: " + p_client.referrer + ", rejecting connection from "+p_client.ip);

    return false;

    }

    // Logging

    trace("Accepted a connection from IP:"+ p_client.ip

    + ", referrer: "+ p_client.referrer

    + ", pageurl: "+ p_client.pageUrl);

    }else{

    // Logging

    trace("Adobe Flash Media Encoder connected from "+p_client.ip);

    }

    // As default, all clients are disabled to access raw audio and video and data bytes in a stream

    // through the use of BitmapData.draw() and SoundMixer.computeSpectrum()., Please refer

    // Stream Data Access doccumentations to know flash player version requirement to support this restriction

    // Access permissions can be allowed for all by uncommenting the following statements

    //p_client.audioSampleAccess = "/";

    //p_client.videoSampleAccess = "/";

    this.acceptConnection(p_client);

    // A connection from Flash 8 & 9 FLV Playback component based client

    // requires the following code.

    if (p_autoSenseBW)

    p_client.checkBandwidth();

    else

    p_client.call("onBWDone");

    }

    /*

    * Client.prototype.getPageUrl

    * Public API to return URL of the HTML page.

    *

    */

    Client.prototype.getPageUrl = function() {

    return this.pageUrl;

    }

    /*

    * Client.prototype.getReferrer

    * Public API to return Domain URL of the client SWF file.

    *

    */

    Client.prototype.getReferrer = function() {

    return this.referrer;

    }

    /*

    * FCPublish :

    * FME 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 also to force FME 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 :

    * FME notifies 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 FME connection to FMS drops during a publishing session it will

    * try and republish the stream when connection is restored. On certain

    * occasions FMS will reject the new stream because server is still

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

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

    * used to forcibly clear the stream.

    */

    Client.prototype.releaseStream = function(streamname)

    {

    s = Stream.get(streamname);

    s.play(false);

    }

    /*

    * application.readValidDomains

    * Function to read Allowed domain file

    * Parameters:

    * fileName:

    * name of the file in the application directory

    * which contains one valid domain name per line. This file can contain

    * comments followed by a '#' as the very first charector in that line.

    * a non-comment entry with a space is considered as an error case.

    * returns

    * an array in which each entry contains a domain name

    * listed in the file.

    */

    application.readValidDomains = function( fileName , domainsType )

    {

    var domainFile = new File(fileName);

    var domainsArray = new Array();

    var index = 0;

    var lineCount = 0;

    var tempLine;

    domainFile.open("text", "read");

    // Read the file line-by-line and fill the domainsArray

    // with valid entries

    while (domainFile.isOpen && ! domainFile.eof() )

    {

    tempLine = domainFile.readln();

    lineCount++;

    if( !tempLine  || tempLine.indexOf("#") == 0)

    {

    continue;

    }

    tempLine = tempLine.trim();

    if(tempLine.indexOf(" ")!=-1)

    {

    trace("undesired <space>, domain entry ignored. "+fileName+":"+(lineCount+1));

    }

    else

    {

    domainsArray[index] =  tempLine.toLowerCase();

    index++;

    if(tempLine == "*")

    {

    switch (domainsType){

    case "HTMLDomains":

    trace ("Found wildcard (*) entry: disabling authentication for HTML file domains ") ;

    application.HTMLDomainsAuth = false;

    break;

    case "SWFDomains":

    trace ("Found wildcard (*) entry: disabling authentication for SWF file domains ") ;

    this.SWFDomainsAuth = false;

    break;

    default:

    // Do nothing

    break;

    }

    }

    }

    } // End while

    // Something is wrong! the domains file must be accessible.

    if( !domainFile.isOpen){

    trace("Error: could not open '"+fileName+"', rejecting all clients except localhost. ");

    }

    else

    {

    domainFile.close();

    }

    return domainsArray;

    }

    /**

    * String.prototype.trim:

    * Function to trim spaces in start an end of an input string.

    * returns:

    * a trimmed string without any leading & ending spaces.

    *

    */

    String.prototype.trim = function () {

    return this.replace(/^\s*/, "").replace(/\s*$/, "");

    }

    ===================================================


    Basically you can fit in my code anywhere in above "live" application code - i do not think it should conflict - something like below

    NetConnection.prototype.connectTimer;

    NetConnection.prototype.url;

    NetConnection.prototype.onStatus = function( info )

    {

    trace ("##### nc: " + info.code + " #####");

        if (info.code == "NetConnection.Connect.Failed" ||  info.code == "NetConnection.Connect.Closed")

        {

           if(  this.connectTimer )

           {

                clearInterval(this.connectTimer);

                this.connectTimer = null;

           }

            trace("setting up reconnect timer for " + this.url);

            this.connectTimer = setInterval(reconnect,30000, this);

        }else{

            if(info.code == "NetConnection.Connect.Success" )

            {

                trace("************************** connection to " + this.url + " successful ");

                if( this.connectTimer ){

                    clearInterval(this.connectTimer);

                }

            }

        }

    }

    reconnect = function ( nc )

    {

      if(nc.connectTimer)

      {

       clearInterval(nc.connectTimer);

       nc.connectTimer = null;

      }

      nc.connect(nc.url);

    }

    application.onAppStart = function()

    {

    nc = new NetConnection();

    nc.url = "rtmp://localhost/app_2";

    nc.connect(nc.url);

    }

    application.onPublish = function(client, stream)

    {

        trace("##### Publish: " + stream.name + " #####");

        client.ns = new NetStream(nc);

        client.ns.onStatus = function( info )

        {

            trace("ns: " + info.code);

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

            {

                client.ns.attach(stream);

            }

        }

        if (client.ns)

        {

            client.ns.publish(stream.name);

        }

        return true;

    }

    application.onUnpublish = function(client, stream)

    {

    trace("##### Unpublish: " + stream.name + " #####");

    client.ns.attach(false);

        client.ns.publish(false);

    }

    /*

    * application.onConnect:

    * Implementation of the onConnect interface function (optional).

    *  it is invoked whenever a client connection request connection. Live app uses this

    *  function to authenticate the domain of connection and authorizes only

    *  for a subscriber request.

    */

    application.onConnect = function( p_client, p_autoSenseBW )

    {

    // Check if pageUrl is from a domain we know.

    // Check pageurl

    // A request from Flash Media Encoder is not checked for authentication

    if( (p_client.agent.indexOf("FME")==-1) && (p_client.agent.indexOf("FMLE")==-1))

    {

    // Authenticating HTML file's domain for the request :

    // Don't call validate() when the request is from localhost

    // or HTML Domains Authentication is off.

    if ((p_client.ip != "127.0.0.1") && application.HTMLDomainsAuth

    &&  !this.validate( p_client.pageUrl, this.allowedHTMLDomains ) )

    {

    trace("Authentication failed for pageurl: " + p_client.pageUrl + ", rejecting connection from "+p_client.ip);

    return false;

    }

    // Authenticating the SWF file's domain for the request :

    // Don't call validate() when the request is from localhost

    // or SWF Domains Authentication is off.

    if ((p_client.ip != "127.0.0.1") && application.SWFDomainsAuth

    &&  !this.validate( p_client.referrer, this.allowedSWFDomains ) )

    {

    trace("Authentication failed for referrer: " + p_client.referrer + ", rejecting connection from "+p_client.ip);

    return false;

    }

    // Logging

    trace("Accepted a connection from IP:"+ p_client.ip

    + ", referrer: "+ p_client.referrer

    + ", pageurl: "+ p_client.pageUrl);

    }else{

    // Logging

    trace("Adobe Flash Media Encoder connected from "+p_client.ip);

    }

    // As default, all clients are disabled to access raw audio and video and data bytes in a stream

    // through the use of BitmapData.draw() and SoundMixer.computeSpectrum()., Please refer

    // Stream Data Access doccumentations to know flash player version requirement to support this restriction

    // Access permissions can be allowed for all by uncommenting the following statements

    //p_client.audioSampleAccess = "/";

    //p_client.videoSampleAccess = "/";

    this.acceptConnection(p_client);

    // A connection from Flash 8 & 9 FLV Playback component based client

    // requires the following code.

    if (p_autoSenseBW)

    p_client.checkBandwidth();

    else

    p_client.call("onBWDone");

    }

    /*

    * Client.prototype.getPageUrl

    * Public API to return URL of the HTML page.

    *

    */

    Client.prototype.getPageUrl = function() {

    return this.pageUrl;

    }

    /*

    * Client.prototype.getReferrer

    * Public API to return Domain URL of the client SWF file.

    *

    */

    Client.prototype.getReferrer = function() {

    return this.referrer;

    }

    /*

    * FCPublish :

    * FME 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 also to force FME 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 :

    * FME notifies 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 FME connection to FMS drops during a publishing session it will

    * try and republish the stream when connection is restored. On certain

    * occasions FMS will reject the new stream because server is still

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

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

    * used to forcibly clear the stream.

    */

    Client.prototype.releaseStream = function(streamname)

    {

    s = Stream.get(streamname);

    s.play(false);

    }

    /*

    * application.readValidDomains

    * Function to read Allowed domain file

    * Parameters:

    * fileName:

    * name of the file in the application directory

    * which contains one valid domain name per line. This file can contain

    * comments followed by a '#' as the very first charector in that line.

    * a non-comment entry with a space is considered as an error case.

    *

    * returns

    * an array in which each entry contains a domain name

    * listed in the file.

    */

    application.readValidDomains = function( fileName , domainsType )

    {

    var domainFile = new File(fileName);

    var domainsArray = new Array();

    var index = 0;

    var lineCount = 0;

    var tempLine;

    domainFile.open("text", "read");

    // Read the file line-by-line and fill the domainsArray

    // with valid entries

    while (domainFile.isOpen && ! domainFile.eof() )

    {

    tempLine = domainFile.readln();

    lineCount++;

    if( !tempLine  || tempLine.indexOf("#") == 0)

    {

    continue;

    }

    tempLine = tempLine.trim();

    if(tempLine.indexOf(" ")!=-1)

    {

    trace("undesired <space>, domain entry ignored. "+fileName+":"+(lineCount+1));

    }

    else

    {

    domainsArray[index] =  tempLine.toLowerCase();

    index++;

    if(tempLine == "*")

    {

    switch (domainsType){

    case "HTMLDomains":

    trace ("Found wildcard (*) entry: disabling authentication for HTML file domains ") ;

    application.HTMLDomainsAuth = false;

    break;

    case "SWFDomains":

    trace ("Found wildcard (*) entry: disabling authentication for SWF file domains ") ;

    this.SWFDomainsAuth = false;

    break;

    default:

    // Do nothing

    break;

    }

    }

    }

    } // End while

    // Something is wrong! the domains file must be accessible.

    if( !domainFile.isOpen){

    trace("Error: could not open '"+fileName+"', rejecting all clients except localhost. ");

    }

    else

    {

    domainFile.close();

    }

    return domainsArray;

    }

    /**

    * String.prototype.trim:

    * Function to trim spaces in start an end of an input string.

    * returns:

    * a trimmed string without any leading & ending spaces.

    *

    */

    String.prototype.trim = function () {

    return this.replace(/^\s*/, "").replace(/\s*$/, "");

    }

    ===================================================

    Try it out and see if its working - if you run into issues LMK

    1 reply

    Participating Frequently
    October 6, 2010

    Yes you can very well do that. You can use feature call Multi-point publish to relay streams coming to one application to another application.

    You will have to use Server side class NetStream and application class handles onPublish and onUnpublish.

    Basically you will have to write piece of code which would do this functionality - you can read more about this here

    NetStream :- http://help.adobe.com/en_US/flashmediaserver/ssaslr/WS5b3ccc516d4fbf351e63e3d11a11aff5ba-7d13.html

    application.onPublish: http://help.adobe.com/en_US/flashmediaserver/ssaslr/WS5b3ccc516d4fbf351e63e3d11a11afc95e-7edf.html#WS5b3ccc516d4fbf351e63e3d11a11afc95e-7fdd

    application.onUnpublish: http://help.adobe.com/en_US/flashmediaserver/ssaslr/WS5b3ccc516d4fbf351e63e3d11a11afc95e-7edf.html#WS5b3ccc516d4fbf351e63e3d11a11afc95e-7fdb

    Publishing from server to server: http://help.adobe.com/en_US/flashmediaserver/devguide/WS5b3ccc516d4fbf351e63e3d11a0773d56e-7ffb.html

    Don't get confused with last doc as it says from server to server - if you application of same server you can do that as well - you just need to use "localhost" or "ip of same server" when you make netconnections

    Let me know if you have any queries

    kaka2koolAuthor
    Inspiring
    October 6, 2010

    Thank you very much for your response.

    I am a complete noob at this and I'm still testing the flash media server.

    I'm not sure I can write such a code, is it possible for you to write an example code to get me started.

    Also is it possible to to have the same domain / swf protection in place as the original "live" application has?

    I'd appreciate your kind help in this regard.

    Khan

    Participating Frequently
    October 6, 2010

    http://help.adobe.com/en_US/flashmediaserver/devguide/WS5b3ccc516d4fbf 351e63e3d11a0773d56e-7ffb.html - this link should have example code - did you check that out. If that example code is still not clear let me know.

    Also i had posted some code here you can check that too : http://forums.adobe.com/message/3079910#3079910

    Coming to your second question: I think same domain/swf protection should be possible.