michalstocki/FlashWavRecorder

Using StatusEvent.STATUS to detect microphone has poor usability

robinsmidsrod opened this issue · 1 comments

One of the main issues is that if you press the Allow radio box in the security dialog before you press the Remember checkbox, the security dialog automatically closes.

I've changed the code so that it will instead listen for MouseEvent.MOUSE_MOVE, which is disabled while the security panel is open, so the moment you close the panel (and you most likely move your mouse) the event will be triggered and permissions will be rechecked and callbacks triggered.

This patch is against version 0.5.0, so you might need to fudge it a bit to apply.

commit 0bf08eb53d744bf864aceff63b5a96c29f8ab1b6
Author: Robin Smidsrød <robin@smidsrod.no>
Date:   Fri Aug 30 16:38:02 2013 +0200

    Fixed security dialog usability issue

diff --git a/recorder/flash/Recorder.as b/recorder/flash/Recorder.as
index 9c70294..8435c87 100755
--- a/recorder/flash/Recorder.as
+++ b/recorder/flash/Recorder.as
@@ -24,7 +24,7 @@ package {
     public function Recorder() {
       this.stage.align = StageAlign.TOP_LEFT;
       this.stage.scaleMode = StageScaleMode.NO_SCALE;
-      recorderInterface = new RecorderJSInterface();
+      recorderInterface = new RecorderJSInterface(this.stage);

diff --git a/recorder/flash/RecorderJSInterface.as b/recorder/flash/RecorderJSInterface.as
index 336b159..ffa9dec 100755
--- a/recorder/flash/RecorderJSInterface.as
+++ b/recorder/flash/RecorderJSInterface.as
@@ -10,6 +10,10 @@ package {
   import flash.net.URLRequest;
   import flash.net.URLLoader;
   import flash.utils.ByteArray;
+  import flash.system.Security;
+  import flash.system.SecurityPanel;
+  import flash.display.Stage;
+  import flash.events.MouseEvent;

   import MicrophoneRecorder;
   import MultiPartFormUtil;
@@ -50,7 +54,10 @@ package {
     public var mic_timeout:int = 1000;
     //***********************************************************

-    public function RecorderJSInterface() {
+    private var stage:Stage;
+
+    public function RecorderJSInterface(stage:Stage) {
+      this.stage = stage;
       this.recorder = new MicrophoneRecorder();
       if(ExternalInterface.available && ExternalInterface.objectID) {
         ExternalInterface.addCallback("record", record);
@@ -118,8 +125,6 @@ package {
     public function isMicrophoneAvailable():Boolean {
       if(! this.recorder.mic.muted) {
         return true;
-      } else if(Microphone.names.length == 0) {
-        ExternalInterface.call(this.eventHandler, RecorderJSInterface.NO_MICROPHONE_FOUND);
       } else {
         ExternalInterface.call(this.eventHandler, RecorderJSInterface.MICROPHONE_USER_REQUEST);
       }
@@ -127,19 +132,35 @@ package {
     }

     public function requestMicrophoneAccess():void {
-      this.recorder.mic.addEventListener(StatusEvent.STATUS, onMicrophoneStatus);
-      this.recorder.mic.setLoopBack();
+      if ( this.recorder.mic != null ) {
+        // A microphone is connected
         this.configureMicrophone(44, this.mic_gain, this.mic_silenceLevel, this.mic_timeout);
+        if ( this.recorder.mic.muted ) {
+          // Microphone access is unavailable, so open security panel
+          Security.showSettings(SecurityPanel.PRIVACY);
+          // When privacy panel is open mouse events are disabled
+          // Use this event to track when the privacy panel is closed and trigger
+          // recording start after, in case user doesn't click the other option.
+          this.stage.addEventListener(MouseEvent.MOUSE_MOVE, onPrivacyPanelClosed);
+        }
+        else {
+          ExternalInterface.call(this.eventHandler, RecorderJSInterface.MICROPHONE_CONNECTED, this.recorder.mic);
+        }
+        return;
+      }
+      // A microphone is not connected
+      ExternalInterface.call(this.eventHandler, RecorderJSInterface.NO_MICROPHONE_FOUND);
     }

-    private function onMicrophoneStatus(event:StatusEvent):void
-    {
-      this.recorder.mic.setLoopBack(false);
-      if(event.code == "Microphone.Unmuted") {
-        ExternalInterface.call(this.eventHandler, RecorderJSInterface.MICROPHONE_CONNECTED, this.recorder.mic);
-      } else {
-        ExternalInterface.call(this.eventHandler, RecorderJSInterface.MICROPHONE_NOT_CONNECTED);
-      }
+    private function onPrivacyPanelClosed(event:Event):void {
+        // Remove event listener when triggered
+        this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onPrivacyPanelClosed);
+        if ( this.recorder.mic.muted ) {
+          ExternalInterface.call(this.eventHandler, RecorderJSInterface.MICROPHONE_NOT_CONNECTED);
+        }
+        else {
+          ExternalInterface.call(this.eventHandler, RecorderJSInterface.MICROPHONE_CONNECTED, this.recorder.mic);
+        }
     }

     public function configureMicrophone(rate:int=22, gain:int=100, silenceLevel:Number=0, silenceTimeout:int=4000):void {

Listening for MouseEvent.MOUSE_MOVE will not work on touch devices. In version 0.9.0 we've added permission_panel_closed event. Then you can call FWRecorder.isMicrophoneAvailable() or just listen for microphone_connected event.