You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ma...@apache.org on 2016/03/28 00:38:18 UTC

cordova-plugin-media git commit: CB-9487: Support getting amplitude for recording

Repository: cordova-plugin-media
Updated Branches:
  refs/heads/master e5b663ac9 -> 3706b7576


CB-9487: Support getting amplitude for recording


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/commit/3706b757
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/tree/3706b757
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/diff/3706b757

Branch: refs/heads/master
Commit: 3706b757679d1470cb7a02a09c92e6faf52687b9
Parents: e5b663a
Author: Simon MacDonald <si...@gmail.com>
Authored: Sun Mar 27 17:54:20 2016 -0400
Committer: Simon MacDonald <si...@gmail.com>
Committed: Sun Mar 27 18:36:05 2016 -0400

----------------------------------------------------------------------
 README.md                     | 43 ++++++++++++++++++++++++++
 src/android/AudioHandler.java | 17 +++++++++-
 src/android/AudioPlayer.java  | 25 +++++++++++++--
 src/ios/CDVSound.h            |  3 +-
 src/ios/CDVSound.m            | 63 ++++++++++++++++++++++++++++++--------
 tests/tests.js                | 31 +++++++++++--------
 www/Media.js                  | 10 +++++-
 7 files changed, 162 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index a641e39..6ea4956 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,8 @@ The following constants are reported as the only parameter to the
 
 ### Methods
 
+- `media.getCurrentAmplitude`: Returns the current position within an audio file.
+
 - `media.getCurrentPosition`: Returns the current position within an audio file.
 
 - `media.getDuration`: Returns the duration of an audio file.
@@ -120,6 +122,47 @@ The following constants are reported as the only parameter to the
 - __duration__: The duration of the media, in seconds.
 
 
+## media.getCurrentAmplitude
+
+Returns the current amplitude of the current recording.
+
+    media.getCurrentAmplitude(mediaSuccess, [mediaError]);
+
+### Supported Platforms
+
+- Android
+- iOS
+
+### Parameters
+
+- __mediaSuccess__: The callback that is passed the current amplitude (0.0 - 1.0).
+
+- __mediaError__: (Optional) The callback to execute if an error occurs.
+
+### Quick Example
+
+    // Audio player
+    //
+    var my_media = new Media(src, onSuccess, onError);
+
+    // Record audio
+    my_media.startRecord();
+
+    mediaTimer = setInterval(function () {
+        // get media amplitude
+        my_media.getCurrentAmplitude(
+            // success callback
+            function (amp) {
+                console.log(amp + "%");
+            },
+            // error callback
+            function (e) {
+                console.log("Error getting amp=" + e);
+            }
+        );
+    }, 1000);
+
+
 ## media.getCurrentPosition
 
 Returns the current position within an audio file.  Also updates the `Media` object's `position` parameter.

http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/src/android/AudioHandler.java
----------------------------------------------------------------------
diff --git a/src/android/AudioHandler.java b/src/android/AudioHandler.java
index 2ff601d..75cdcde 100644
--- a/src/android/AudioHandler.java
+++ b/src/android/AudioHandler.java
@@ -164,6 +164,10 @@ public class AudioHandler extends CordovaPlugin {
         else if (action.equals("messageChannel")) {
             messageChannel = callbackContext;
             return true;
+        } else if (action.equals("getCurrentAmplitudeAudio")) {
+            float f = this.getCurrentAmplitudeAudio(args.getString(0));
+            callbackContext.sendPluginResult(new PluginResult(status, f));
+            return true;
         }
         else { // Unrecognized action.
             return false;
@@ -471,5 +475,16 @@ public class AudioHandler extends CordovaPlugin {
 
     }
 
-
+    /**
+     * Get current amplitude of recording.
+     * @param id				The id of the audio player
+     * @return 					amplitude
+     */
+    public float getCurrentAmplitudeAudio(String id) {
+        AudioPlayer audio = this.players.get(id);
+        if (audio != null) {
+            return (audio.getCurrentAmplitude());
+        }
+        return 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/src/android/AudioPlayer.java
----------------------------------------------------------------------
diff --git a/src/android/AudioPlayer.java b/src/android/AudioPlayer.java
index ede9330..26248e5 100644
--- a/src/android/AudioPlayer.java
+++ b/src/android/AudioPlayer.java
@@ -501,13 +501,13 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
                                 sendErrorStatus(MEDIA_ERR_ABORTED);
                             }
                             return false;//we´re not ready yet
-                        } 
+                        }
                         else {
                            //reset the audio file
                             player.seekTo(0);
                             player.pause();
-                            return true; 
-                        } 
+                            return true;
+                        }
                     } else {
                         //reset the player
                         this.player.reset();
@@ -598,4 +598,23 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
 
         this.handler.sendEventMessage("status", statusDetails);
     }
+
+    /**
+     * Get current amplitude of recording.
+     *
+     * @return amplitude or 0 if not recording
+     */
+    public float getCurrentAmplitude() {
+        if (this.recorder != null) {
+            try{
+                if (this.state == STATE.MEDIA_RUNNING) {
+                    return (float) this.recorder.getMaxAmplitude() / 32762;
+                }
+            }
+            catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/src/ios/CDVSound.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVSound.h b/src/ios/CDVSound.h
index 90da62e..5e795cc 100644
--- a/src/ios/CDVSound.h
+++ b/src/ios/CDVSound.h
@@ -110,8 +110,9 @@ typedef NSUInteger CDVMediaMsg;
 
 - (void)startRecordingAudio:(CDVInvokedUrlCommand*)command;
 - (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command;
+- (void)getCurrentAmplitudeAudio:(CDVInvokedUrlCommand*)command;
 
 - (void)setVolume:(CDVInvokedUrlCommand*)command;
 - (void)setRate:(CDVInvokedUrlCommand*)command;
 
-@end
\ No newline at end of file
+@end

http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/src/ios/CDVSound.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVSound.m b/src/ios/CDVSound.m
index 640ebcd..d99f181 100644
--- a/src/ios/CDVSound.m
+++ b/src/ios/CDVSound.m
@@ -206,7 +206,7 @@
 
     [errorDict setObject:[NSNumber numberWithUnsignedInteger:code] forKey:@"code"];
     [errorDict setObject:message ? message:@"" forKey:@"message"];
-    
+
     NSData* jsonData = [NSJSONSerialization dataWithJSONObject:errorDict options:0 error:nil];
     return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
 }
@@ -290,7 +290,7 @@
                 float customRate = [rate floatValue];
                 [avPlayer setRate:customRate];
             }
-            
+
             [[self soundCache] setObject:audioFile forKey:mediaId];
         }
     }
@@ -420,7 +420,7 @@
     if ([resourceURL isFileURL]) {
         audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:resourceURL error:&playerError];
     } else {
-        /*      
+        /*
         NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:resourceURL];
         NSString* userAgent = [self.commandDelegate userAgent];
         if (userAgent) {
@@ -541,10 +541,10 @@
     } else if (avPlayer != nil) {
         int32_t timeScale = avPlayer.currentItem.asset.duration.timescale;
         CMTime timeToSeek = CMTimeMakeWithSeconds(posInSeconds, timeScale);
-           
+
         BOOL isPlaying = (avPlayer.rate > 0 && !avPlayer.error);
         BOOL isReadyToSeek = (avPlayer.status == AVPlayerStatusReadyToPlay) && (avPlayer.currentItem.status == AVPlayerItemStatusReadyToPlay);
-        
+
         // CB-10535:
         // When dealing with remote files, we can get into a situation where we start playing before AVPlayer has had the time to buffer the file to be played.
         // To avoid the app crashing in such a situation, we only seek if both the player and the player item are ready to play. If not ready, we send an error back to JS land.
@@ -613,7 +613,7 @@
     }
 
     CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:position];
-    
+
     NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_POSITION, position];
     [self.commandDelegate evalJs:jsString];
     [self.commandDelegate sendPluginResult:result callbackId:callbackId];
@@ -636,7 +636,7 @@
 
         void (^startRecording)(void) = ^{
             NSError* __autoreleasing error = nil;
-            
+
             if (audioFile.recorder != nil) {
                 [audioFile.recorder stop];
                 audioFile.recorder = nil;
@@ -656,14 +656,20 @@
                     return;
                 }
             }
-            
+
             // create a new recorder for each start record
+            NSDictionary *audioSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC),
+                                             AVSampleRateKey: @(44100),
+                                             AVNumberOfChannelsKey: @(1),
+                                             AVEncoderAudioQualityKey: @(AVAudioQualityMedium)
+                                             };
             audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:nil error:&error];
-            
+
             bool recordingSuccess = NO;
             if (error == nil) {
                 audioFile.recorder.delegate = weakSelf;
                 audioFile.recorder.mediaId = mediaId;
+                audioFile.recorder.meteringEnabled = YES;
                 recordingSuccess = [audioFile.recorder record];
                 if (recordingSuccess) {
                     NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath);
@@ -671,7 +677,7 @@
                     [weakSelf.commandDelegate evalJs:jsString];
                 }
             }
-            
+
             if ((error != nil) || (recordingSuccess == NO)) {
                 if (error != nil) {
                     errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]];
@@ -686,7 +692,7 @@
                 [weakSelf.commandDelegate evalJs:jsString];
             }
         };
-        
+
         SEL rrpSel = NSSelectorFromString(@"requestRecordPermission:");
         if ([self hasAudioSession] && [self.avSession respondsToSelector:rrpSel])
         {
@@ -710,7 +716,7 @@
         } else {
             startRecording();
         }
-        
+
     } else {
         // file did not validate
         NSString* errorMsg = [NSString stringWithFormat:@"Could not record audio at '%@'", audioFile.resourcePath];
@@ -831,6 +837,39 @@
     [[self soundCache] removeAllObjects];
 }
 
+- (void)getCurrentAmplitudeAudio:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSString* mediaId = [command argumentAtIndex:0];
+
+#pragma unused(mediaId)
+    CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId];
+    float amplitude = 0; // The linear 0.0 .. 1.0 value
+
+    if ((audioFile != nil) && (audioFile.recorder != nil) && [audioFile.recorder isRecording]) {
+        [audioFile.recorder updateMeters];
+        float minDecibels = -60.0f; // Or use -60dB, which I measured in a silent room.
+        float decibels    = [audioFile.recorder averagePowerForChannel:0];
+        if (decibels < minDecibels) {
+            amplitude = 0.0f;
+        } else if (decibels >= 0.0f) {
+            amplitude = 1.0f;
+        } else {
+            float root            = 2.0f;
+            float minAmp          = powf(10.0f, 0.05f * minDecibels);
+            float inverseAmpRange = 1.0f / (1.0f - minAmp);
+            float amp             = powf(10.0f, 0.05f * decibels);
+            float adjAmp          = (amp - minAmp) * inverseAmpRange;
+            amplitude = powf(adjAmp, 1.0f / root);
+        }
+    }
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:amplitude];
+
+    NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_POSITION, amplitude];
+    [self.commandDelegate evalJs:jsString];
+    [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+ }
+
 @end
 
 @implementation CDVAudioFile

http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index 246e40b..08c0ff7 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -25,7 +25,7 @@
 // increased timeout for actual playback to give device chance to download and play mp3 file
 // some emulators can be REALLY slow at this, so two minutes
 var ACTUAL_PLAYBACK_TEST_TIMEOUT = 2 * 60 * 1000;
- 
+
 var isWindows = cordova.platformId == 'windows8' || cordova.platformId == 'windows';
 // detect whether audio hardware is available and enabled
 var isAudioSupported = isWindows ? Windows.Media.Devices.MediaDevice.getDefaultAudioRenderId(Windows.Media.Devices.AudioDeviceRole.default) : true;
@@ -168,7 +168,14 @@ exports.defineAutoTests = function () {
             media1.release();
         });
 
-        it("media.spec.15 should return MediaError for bad filename", function (done) {
+        it("media.spec.15 should contain a getCurrentAmplitude function", function () {
+            var media1 = new Media("dummy");
+            expect(media1.getCurrentAmplitude).toBeDefined();
+            expect(typeof media1.getCurrentAmplitude).toBe('function');
+            media1.release();
+        });
+
+        it("media.spec.16 should return MediaError for bad filename", function (done) {
             //bb10 dialog pops up, preventing tests from running
             if (cordova.platformId === 'blackberry10') {
                 pending();
@@ -203,7 +210,7 @@ exports.defineAutoTests = function () {
                 }
             });
 
-            it("media.spec.16 position should be set properly", function (done) {
+            it("media.spec.17 position should be set properly", function (done) {
                 // no audio hardware available
                 if (!isAudioSupported) {
                     pending();
@@ -233,7 +240,7 @@ exports.defineAutoTests = function () {
                 media.play();
             }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
 
-            it("media.spec.17 duration should be set properly", function (done) {
+            it("media.spec.18 duration should be set properly", function (done) {
                 if (!isAudioSupported || cordova.platformId === 'blackberry10') {
                     pending();
                 }
@@ -262,7 +269,7 @@ exports.defineAutoTests = function () {
                 media.play();
             }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
 
-            it("media.spec.20 should be able to resume playback after pause", function (done) {
+            it("media.spec.19 should be able to resume playback after pause", function (done) {
                 if (!isAudioSupported || cordova.platformId === 'blackberry10') {
                     pending();
                 }
@@ -297,15 +304,15 @@ exports.defineAutoTests = function () {
                     }
                 };
                 media = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange);
-                
+
                 // CB-10535: Play after a few secs, to give allow enough buffering of media file before seeking
                 setTimeout(function() {
                     media.play();
                 }, 4000);
-                
+
             }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
 
-            it("media.spec.21 should be able to seek through file", function (done) {
+            it("media.spec.20 should be able to seek through file", function (done) {
                 if (!isAudioSupported || cordova.platformId === 'blackberry10') {
                     pending();
                 }
@@ -330,23 +337,23 @@ exports.defineAutoTests = function () {
                     }
                 };
                 media = new Media(mediaFile, successCallback, failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context), statusChange);
-                
+
                 // CB-10535: Play after a few secs, to give allow enough buffering of media file before seeking
                 setTimeout(function() {
                     media.play();
                 }, 4000);
-                
+
             }, ACTUAL_PLAYBACK_TEST_TIMEOUT);
         });
 
-        it("media.spec.18 should contain a setRate function", function () {
+        it("media.spec.21 should contain a setRate function", function () {
             var media1 = new Media("dummy");
             expect(media1.setRate).toBeDefined();
             expect(typeof media1.setRate).toBe('function');
             media1.release();
         });
 
-        it("media.spec.19 playback rate should be set properly using setRate", function (done) {
+        it("media.spec.22 playback rate should be set properly using setRate", function (done) {
             if (cordova.platformId !== 'ios') {
                 expect(true).toFailWithMessage('Platform does not supported this feature');
                 pending();

http://git-wip-us.apache.org/repos/asf/cordova-plugin-media/blob/3706b757/www/Media.js
----------------------------------------------------------------------
diff --git a/www/Media.js b/www/Media.js
index d302cbe..192d4b3 100644
--- a/www/Media.js
+++ b/www/Media.js
@@ -163,6 +163,14 @@ Media.prototype.setRate = function(rate) {
     }
 };
 
+/**
+ * Get amplitude of audio.
+ */
+Media.prototype.getCurrentAmplitude = function(success, fail) {
+    exec(function(p) {
+        success(p);
+    }, fail, "Media", "getCurrentAmplitudeAudio", [this.id]);
+};
 
 /**
  * Audio has status update.
@@ -232,4 +240,4 @@ if (cordova.platformId === 'android' || cordova.platformId === 'amazon-fireos' |
         exec(onMessageFromNative, undefined, 'Media', 'messageChannel', []);
         channel.initializationComplete('onMediaPluginReady');
     });
-}
\ No newline at end of file
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org