A flash recording demonstration based on FMS recently has several technical points:
1. install and use the FMS
2. Flash recording and related security issues
3. audio file conversion
1. install and use the FMS
- Flash Media Server Download from Adobe Official Website: http://www.adobe.com/products/flashmediaserver/
The current version is 3.5. The FMS contains a series of software, which is priced at thousands of US dollars. As a developer, you can directly download the Flash Media Development Server. Most of the functions of FMS are supported.
- The installation and backend management are relatively simple. You can refer to Baidu's "quick start tutorial for Microsoft ".
- By default, streaming media is published through the rtmp Protocol over port 1935. If Apache is installed, HTTP Forwarding is supported. The default http port is 80 because my server has already deployed IIS, therefore, you need to modify the port. The specific configuration file is in the [FMS installation directory]/CONF/FMS. INI, and [FMS installation directory]/CONF/_ defaultroot _/adaptor. XML, see: http://help.adobe.com/en_US/FlashMediaServer/3.5_AdminGuide/WSE2A5A7B9-E118-496f-92F9-E295038DB7DB.html
Or here
.
2. Client Connection and release
Private var NC: netconnection;
Private var ns: netstream;
NC = new netconnection ();
NC. addeventlistener (netstatusevent. net_status, onnetstatus );
Private function onnetstatus (Event: netstatusevent): void {
Showtrace ("onnetstatus, Code:" + event.info. Code );
Switch (event.info. Code ){
// Connection successful
Case "netconnection. Connect. Success ":
Break;
Case "netstream. Play. Start ":
Break;
Case "netconnection. Connect. Closed ":
Case "netconnection. Connect. Failed ":
Case "netconnection. Connect. Rejected ":
If (FLAG)
Externalinterface. Call ("flash_callback_proxy", "stoprecord ");
Else
Externalinterface. Call ("flash_callback_proxy", "failrecord ");
Flag = false;
Break;
// Start recording. Before that, you will receive the netsteam. Publish. Start event.
Case "netstream. Record. Start ":
Externalinterface. Call ("flash_callback_proxy", "startrecord ");
Break;
}
}
// Start recording
Private function startrecord (audioid: string): Boolean
{
Showtrace ("Get JS call startrecord ");
If (! NC. Connected ){
If (retryflag = 0)
{
Showtrace ("startrecord, need connect to server, Count:" + retryflag );
Try
{
NC. Connect ("rtmp: // 192.168.5.2/demo"); // demo
}
Catch (e ){
Showtrace ("startrecord, catch exception:" + E. tostring ());
}
}
Retryflag ++;
If (retryflag> 3)
Showtrace ("startrecord, connect to server timeout! ");
Else
Intervalid = flash. utils. setTimeout (startrecord, 3000, audioid );
Return false;
} Else {
Flag = true;
Retryflag = 0;
Flash. utils. cleartimeout (intervalid );
}
// Publish audio
If (! Setupaudio ())
Return false;
Publishaudio (audioid );
Mictimer. Start ();
Showtrace ("startrecord, started, ID:" + audioid );
Return true;
}
Private function stoprecord ()
{
Showtrace ("Get JS call stoprecord ");
// Stop publish
Mictimer. Stop ();
NS. Close ();
NS = NULL;
NC. Close ();
}
3. display of recordings and volume bars
The following functions are related to recording. In flash, when you start recording to obtain micphone data, a security warning will pop up by default to request the user's permission, what's interesting is that my flash cannot come out, even if security is forcibly called in the program. showsettings (securitypanel. privacy); No. Right-click the page and set the menu to Gray. After a long time, I found that my flash was too small in the web page and the prompt box was displayed.
Private function setupaudio (): Boolean {
// Security. showsettings (securitypanel. Microphone );
MIC = microphone. getmicrophone ();
If (MIC = NULL)
{
Showtrace ("setupvideos, no micphone found! ");
Return false;
}
Else
{
Showtrace ("setupvideos, getmicrophone success! ");
Mic. Rate = 22; // use 22 K for sampling
Mic. setsilencelevel (5,-1 );
Mic. addeventlistener (statusevent. Status, micstatushandler );
// Mic. addeventlistener (activityevent. Activity, drawmiclevel );
}
Return true;
}
Private function publishaudio (audioid: string ){
// Start publish
NS = new netstream (NC );
NS. Client = new customclient ();
NS. addeventlistener (netstatusevent. net_status, onnetstatus );
NS. addeventlistener (asyncerrorevent. async_error, onasyncerror );
NS. attachaudio (MIC );
NS. Publish (audioid, "record"); // publish to the FMS and record
}
// Display of the recording volume bar. My actual practice is to draw a gradient in the back, and then draw a white mask dynamically based on the volume of the micphone.
Private function initbackground (): void
{
VaR mymatrix: matrix = new matrix ();
Trace ("initbackground:" + mymatrix. tostring (); // (a = 1, B = 0, c = 0, D = 1, Tx = 0, Ty = 0)
Mymatrix. creategradientbox (250,250, 0, 50, 50 );
Trace ("initbackground:" + mymatrix. tostring (); // (A = 0.1220703125, B = 0, c = 0, D = 0.1220703125, Tx = 150, Ty = 150)
VaR colors: array = [0x00ff00, 0xffff00, 0xffff00, 0xff0000];
VaR Alphas: array = [80,100,100,100];
VaR ratios: array = [0,175,215, 0xff];
This. Graphics. begingradientfill (gradienttype. Linear, colors, Alphas, ratios, mymatrix );
This. Graphics. drawrect (0, 0, stage. stagewidth, stage. stageheight );
This. Graphics. endfill ();
This. graphholder. Graphics. beginfill (0 xffffff );
This. graphholder. Graphics. drawrect (0, 0, stage. stagewidth, stage. stageheight );
This. graphholder. Graphics. endfill ();
}
Private function drawmiclevel (E: timerevent): void
{
If (! NC. Connected) return;
// Showtrace ("drawmiclevel, activitylevel:" + mic. activitylevel );
VaR levels = 100;
This. graphholder. Graphics. Clear ();
This. graphholder. Graphics. beginfill (0 xffffff );
If (vudirection = "horizontal ")
{
Level = (MIC. activitylevel/100) * stage. stagewidth;
This. graphholder. Graphics. drawrect (Level, 0, stage. stagewidth, stage. stageheight );
}
Else
{
Level = (MIC. activitylevel/100) * stage. stageheight;
This. graphholder. Graphics. drawrect (0, 0, stage. stagewidth, stage. stageheight-level );
}
This. graphholder. Graphics. endfill ();
// Showtrace ("drawmiclevel, level:" + level );
}
4. Mutual calls between flash and JavaScript
// Flash calls JS Functions
Externalinterface. Call ("flash_callback_proxy", "failrecord ");
// JavaScript calls should be allowed in flash and corresponding functions should be exported. Here I am doing a proxy, and all JS calls are forwarded through this function
{
Security. allowdomain ("*");
Security. allowinsecuredomain ("*");
Externalinterface. addcallback ("js_callback_proxy", js_callback_proxy );
}
// Function call by JavaScript
Function js_callback_proxy (_ P1, _ P2): Boolean
{
VaR RET: Boolean = true;
Showtrace ("js_callback_proxy, CMD:" + _ P1 );
Switch (_ P1 ){
Case "startrecord ":
Ret = startrecord (_ P2 );
Break;
Case "stoprecord ":
Stoprecord ();
Break;
Case "setdirection ":
Setdirection (_ P2 );
Break;
Case "sowpreference ":
Showparameters ();
Break;
Default:
Ret = false;
}
Return ret;
}
// This is basically the case for calling in Js.
OBJ. js_callback_proxy ('startrecord ', evalid );
I personally think that we should try not to call flash functions from Js. On the one hand, there may be some security issues. On the other hand, I also found some inexplicable problems when calling the flash function in JS when the flash object is dynamically loaded on the webpage.
5. Audio Format Conversion
FFmpeg is directly used to convert the FLV to 16 K 16 bit single-channel WAV.
FFmpeg-I d:/xxx. FLV-ar 16000-AB 16-Ac 1 D:/xxx.wav
6. Follow-up work
The server uses streaming media to be decoded to WAV in real time. After reading the Server API provided by the FMS, it does not seem to support real-time retrieving of streaming media data.
Another good news is that Adobe has published the rtmp protocol format, and I have also seen some open source server code written on the Internet to support this protocol, such as red5, therefore, you can develop on the basis of open source code.
Reference webpage: list of available rtmp servers