在 FMS 寫 CODE



此篇為備忘錄

拿 Flash Media Server 來做視頻串流 不外乎就可以做
錄影,與額外的規範

可使用的內建方法可參考官方
https://helpx.adobe.com/adobe-media-server/ssaslr/application-class.html

實際存放CODE的位置在

C:\Program Files (x86)\Adobe\Flash Media Server 4.5\applications\live

範例 CODE 如下
底下實作一個,當呼叫 rtmp URL後 做出相對應輸入參數的判斷邏輯
 // mark - add application.doCheckClient = function() { var count = application.clients.length ; for(i = 0 ; i < count ; i++) { var target = application.clients[i] ; var server_id = target.server_id ; var no_run = target.no_run ; var no_active = target.no_active ; var game_status = target.game_status ; var check_value = no_run + "," + no_active + "," + game_status ; if(check_value != application.src_list[server_id]) { trace("loop-stop-it") ; application.disconnect(application.clients[i]) ; } else { trace("loop-it") ; } } } /* * 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."); // mark - add - start application.src_list = Array() ; setInterval(this.doCheckClient , 2000) ; // mark - add - end } /* * 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[i]); if ( (pos > 0) && (pos < domainEndPos) && (domainEndPos == (pos + patterns[i].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. */ // 用戶端連線 // 取得GET參數 // (1)轉換成serverid,norun,noactive,gamestatus [或其他] // (2)呼叫取得gs狀態api [或其他] // 比對(1)和(2)的結果字串:不一致則斷線 // [todo?] 每N分鐘重新檢查 application.onConnect = function( p_client, p_autoSenseBW ) { // mark - add - start trace("client-uri=" + p_client.uri) ; var uri = p_client.uri ; var start_index = uri.indexOf("?") + 1 ; var info = "" ; if(start_index != 0) { info = uri.slice(start_index) ; info = info.split("=")[1] ; sub_info = info.split(",") ; p_client.server_id = sub_info[0] ; p_client.no_run = sub_info[1] ; p_client.no_active = sub_info[2] ; p_client.game_status = sub_info[3] ; } else { p_client.server_id = "" ; p_client.no_run = "" ; p_client.no_active = "" ; p_client.game_status = "" ; } trace("info = " + info) ; trace("server_id = " + p_client.server_id) ; trace("no_run = " + p_client.no_run) ; trace("no_active = " + p_client.no_active) ; trace("game_status = " + p_client.game_status) ; var api_loader = new LoadVars(); api_loader.onData = function(src) { trace("api_loader.onData-start") ; if (src == undefined) { trace("Error loading content.") ; return false ; } // 0604250002,011118022,1182,4 var check_value = p_client.no_run + "," + p_client.no_active + "," + p_client.game_status ; trace("check_value = " + check_value) ; trace("src = " + src) ; application.src_list[p_client.server_id] = src ; // trace("show====" + application.src_list[p_client.server_id]) ; if(src == check_value) { trace("client pass") ; } else { trace("client cant pass") ; application.disconnect(p_client) ; return false ; } } ; api_loader.decode("serverid="+p_client.server_id) ; // http://ddd.bacc1688.com:8933/GetServerInfo.aspx?serverid=0604250002 var url = "http://ddd.bacc1688.com:8933/GetServerInfo.aspx" ; trace("api url = " + url) ; api_loader.load(url) ; // mark - add - end // 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); this.acceptConnection(p_client); } // 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"); trace(" @@@ onconnect-end @@@ "); } application.onStatus = function(info){ trace("code: " + info.code + " level: " + info.level); trace(info.code + " details: " + info.details); }; /* * 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 ) { trace("filename="+fileName); 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 , 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*$/, ""); } application.onPublish = function(client, stream){ trace("onPublish.client.uri=" + client.uri); } 

沒有留言:

張貼留言