Playing Recorded Streams When No Live Streams Available on Server Side
Hi,
Thanks to Adobe Forums, i am able to record live streams on server side.
Now i am looking for an option to play recorded streams on server side when no one is publishing a live stream.
Currently i am able to record all live streams that are currently being published in /opt/adobe/fms/webroot/live_recorded Folder.
All the recorded streams are saved in stream.f4v format.
I want to change main.asc in livemyapp folder in such a way that if any one is not publishing live streams of the name "abc" then automatically the client is served with the previously recorded abc.f4v in his browser.
Here is main.asc
-----------------------------------------------------------------------------------
/*
* application.onAppStart:
* is called when application load. It contains Live (out of the box)
* application specific initializations.
*/
application.onAppStart = function()
{
// Logging
trace("Starting Live Service...");
// Turning on the Authentication by default
this.HTMLDomainsAuth = true;
this.SWFDomainsAuth = true;
// Populating the list of domains which are allowed to host HTML file
// which in turn may embed a SWF that connects to this application
this.allowedHTMLDomains = this.readValidDomains("allowedHTMLdomains.txt","HTMLDomains");
// Populating the list of domains which are allowed to host a SWF file
// which may connect to this application
this.allowedSWFDomains = this.readValidDomains("allowedSWFdomains.txt","SWFDomains");
// Logging
if(this.HTMLDomainsAuth){
trace("Authentication of HTML page URL domains is enabled");
}
if(this.SWFDomainsAuth){
trace("Authentication of SWF URL domains is enabled");
}
trace("...loading completed.");
}
/*
* application.validate:
* function to validate a given URL by matching through a list of
* allowed patterns.
*
* Parameters:
* url: contains the input url string.
* patterns: Array; an array of permmited url patterns.
*
* return value:
* true; when 'url domain" contains a listed domains as a suffix.
* false; otherwise.
*/
application.validate = function( url, patterns )
{
// Convert to lower case
url = url.toLowerCase();
var domainStartPos = 0; // domain start position in the URL
var domainEndPos = 0; // domain end position in the URL
switch (url.indexOf( "://" ))
{
case 4:
if(url.indexOf( "http://" ) ==0)
domainStartPos = 7;
break;
case 5:
if(url.indexOf( "https://" ) ==0)
domainStartPos = 8;
break;
}
if(domainStartPos == 0)
{
// URL must be HTTP or HTTPS protocol based
return false;
}
domainEndPos = url.indexOf("/", domainStartPos);
if(domainEndPos>0)
{
colonPos = url.indexOf(":", domainStartPos);
if( (colonPos>0) && (domainEndPos > colonPos))
{
// probably URL contains a port number
domainEndPos = colonPos; // truncate the port number in the URL
}
}
for ( var i = 0; i < patterns.length; i++ )
{
var pos = url.lastIndexOf( patterns);
if ( (pos > 0) && (pos < domainEndPos) && (domainEndPos == (pos + patterns.length)) )
return true;
}
return 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 = "/";
p_client.setBandwidthLimit(75000, 75000);
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*$/, "");
}
var mystream;
application.onPublish = function(clientObj,streamObj){
mystream = Stream.get("mp4:"+streamObj.name+".f4v");
if (mystream)
{
mystream.record("record",600);
mystream.play(streamObj.name,-2,-1);
}
}
application.onUnpublish = function(clientObj,streamObj){
mystream.record(false);
}
---------------------------
in FMS.ini i have done following change -
LIVE_DIR = /opt/adobe/fms/webroot/live_recorded
-----------------------------------------------------
Just want to know what should i write in main.asc so that if a client is requesting to watch a stream and if that is not being published at the moment, he should be served the recorded version of that stream.
