summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNorman Kerr 柯念北2015-05-29 16:25:24 (GMT)
committerNorman Kerr 柯念北2015-05-29 16:25:24 (GMT)
commitf3e38645d989bb57a7f32d021e40871609264904 (patch)
tree32ebd6721092113fb41c7accb774b93cc169fa84
parent9d53481c4d66a716f39210625be7b9b653154114 (diff)
Major update, see notes for issue list.7.x-1.0-alpha7
Replace Recorder.js as flash fallback: https://www.drupal.org/node/2456759 Constraint API/setting: https://www.drupal.org/node/2409525 ** This update requires all javascript libraries to be re-installed.
-rw-r--r--README.txt11
-rw-r--r--[-rwxr-xr-x]css/media-recorder.css105
-rw-r--r--[-rwxr-xr-x]includes/MediaRecorderBrowser.inc0
-rw-r--r--includes/media_recorder.admin.inc46
-rw-r--r--includes/media_recorder.drush.inc35
-rw-r--r--[-rwxr-xr-x]js/media-recorder-api.js842
-rw-r--r--[-rwxr-xr-x]js/media-recorder-flash.js458
-rw-r--r--[-rwxr-xr-x]js/media-recorder-html5.js685
-rw-r--r--js/media-recorder.browser.js12
-rw-r--r--[-rwxr-xr-x]js/media-recorder.js99
-rw-r--r--[-rwxr-xr-x]media_recorder.info0
-rw-r--r--[-rwxr-xr-x]media_recorder.install10
-rw-r--r--[-rwxr-xr-x]media_recorder.module241
-rw-r--r--theme/media-recorder.tpl.php16
14 files changed, 1561 insertions, 999 deletions
diff --git a/README.txt b/README.txt
index d90b2ba..cc26907 100644
--- a/README.txt
+++ b/README.txt
@@ -8,8 +8,8 @@ REQUIREMENTS
* Media module - https://drupal.org/project/media
* Libraries module - https://drupal.org/project/libraries
* RecorderJS library - https://github.com/mattdiamond/Recorderjs
- * Recorder.js library - https://github.com/jwagener/recorder.js
- * SWFObject library - http://code.google.com/p/swfobject
+ * FlashWavRecorder library - https://github.com/michalstocki/FlashWavRecorder
+ * SWFObject library - https://github.com/swfobject/swfobject
INSTALLATION
------------
@@ -18,9 +18,10 @@ INSTALLATION
1. Install the RecorderJS library in sites/all/libraries. The recorder.js file
should be located at sites/all/libraries/Recorderjs/recorder.js.
-2. Install the SWFObject & flash recorder.js libraries in sites/all/libraries. The
- swfobject.js file should be at sites/all/libraries/swfobject/swfobject.js,
- and recorder.js should be at sites/all/libraries/recorder.js/recorder.js.
+2. Install the SWFObject & FlashWavRecorder libraries in sites/all/libraries. The
+ files swfobject.js and recorder.js should be at:
+ swfobject.js: sites/{site}/libraries/swfobject/swfobject/swfobject.js
+ recorder.js: sites/{site}/libraries/FlashWavRecorder/html/js/recorder.js
3. Install dependencies and media recorder module as per:
https://drupal.org/documentation/install/modules-themes/modules-7
diff --git a/css/media-recorder.css b/css/media-recorder.css
index 97c3aee..e959608 100755..100644
--- a/css/media-recorder.css
+++ b/css/media-recorder.css
@@ -1,32 +1,3 @@
-div.media-recorder-toggle {
- margin-bottom: 2px;
- padding: 0;
-}
-
-div.media-recorder-toggle .form-item {
- margin: 0;
- padding: 0;
- display: inline-block;
-}
-
-div.media-recorder-toggle input {
- display: none;
-}
-
-div.media-recorder-toggle input:checked + label.option {
- background: #323232;
-}
-
-div.media-recorder-toggle label.option {
- background: #555555;
- border: #ccc;
- border-radius: 3px 3px 0 0;
- color: #ffffff;
- margin: 0 5px 0 0;
- padding: 5px 10px;
- cursor: pointer;
-}
-
.media-recorder-wrapper {
padding: 10px;
margin: 0;
@@ -50,63 +21,29 @@ div.media-recorder-toggle label.option {
.media-recorder-preview {
background: #222222;
padding: 0;
- margin: 5px 0;
+ margin: 0;
+ text-align: center;
}
-.media-recorder-preview canvas.media-recorder-visualizer {
+.media-recorder-preview canvas.media-recorder-meter {
width: 100%;
- height: 100%;
padding: 0;
margin: 0;
- display: inline-block;
- vertical-align: middle;
+ vertical-align: bottom;
}
-.media-recorder-preview canvas.media-recorder-meter {
- width: 10%;
- height: 100%;
- padding: 0;
+.media-recorder-video {
+ width: 100%;
+ padding: 5px 0;
margin: 0;
- display: inline-block;
vertical-align: middle;
}
-.media-recorder-preview video {
- width: 90%;
- padding: 0;
+.media-recorder-audio {
+ width: 100%;
+ padding: 5px 0;
margin: 0;
- display: inline-block;
- vertical-align: bottom;
-}
-
-.media-recorder-constraints {
- text-align: center;
- padding: 5px;
-}
-
-button.media-recorder-enable-audio, button.media-recorder-enable-video {
- display: inline-block;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- background: #555555;
- color: #fff;
- border: none;
- border-radius: 3px;
- padding: 5px 10px;
- cursor: pointer;
-}
-
-button.media-recorder-enable-audio.active, button.media-recorder-enable-video.active {
- font-weight: bold;
- -webkit-box-shadow: inset 0 0 3px #000000;
- -moz-box-shadow: inset 0 0 3px #000000;
- box-shadow: inset 0 0 3px #000000;
-}
-
-button.media-recorder-enable-video:disabled {
- color: #ccc;
- text-decoration: line-through;
+ vertical-align: middle;
}
.media-recorder-controls {
@@ -119,7 +56,6 @@ button.media-recorder-enable-video:disabled {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
- background: #FF4D4D;
color: #fff;
border: none;
border-radius: 2px;
@@ -127,19 +63,22 @@ button.media-recorder-enable-video:disabled {
cursor: pointer;
}
-.media-recorder-controls button.media-recorder-settings {
+.media-recorder-settings {
background: #00a5e1;
}
-.media-recorder-file-preview {
- background: #323232;
- color: #fff;
+.media-recorder-record {
+ background: #FF4D4D;
}
-#recorderFlashContainer {
- background: transparent !important;
- border: none !important;
+.media-recorder-play {
+ background: #2861ff;
}
-#recorderFlashContainer object {
+.media-recorder-stop {
+ background: #ffa42a;
+}
+
+#flash-wrapper {
+ text-align: center;
}
diff --git a/includes/MediaRecorderBrowser.inc b/includes/MediaRecorderBrowser.inc
index c56542b..c56542b 100755..100644
--- a/includes/MediaRecorderBrowser.inc
+++ b/includes/MediaRecorderBrowser.inc
diff --git a/includes/media_recorder.admin.inc b/includes/media_recorder.admin.inc
index 35e44c6..a944a3e 100644
--- a/includes/media_recorder.admin.inc
+++ b/includes/media_recorder.admin.inc
@@ -11,7 +11,7 @@
function media_recorder_admin_form($form, $form_state) {
// Check that all libraries exist.
- $required_libraries = array('swfobject', 'recorder.js', 'Recorderjs');
+ $required_libraries = array('swfobject', 'FlashWavRecorder', 'Recorderjs');
foreach ($required_libraries as $name) {
$library = libraries_detect($name);
if (!$library['installed']) {
@@ -19,6 +19,42 @@ function media_recorder_admin_form($form, $form_state) {
}
}
+ // Recorder constraints.
+ $constraints = variable_get('media_recorder_constraints', array(
+ 'audio' => TRUE,
+ 'video' => TRUE,
+ 'video_resolution' => 320,
+ ));
+ $form['media_recorder_constraints'] = array(
+ '#type' => 'fieldset',
+ '#tree' => TRUE,
+ '#title' => t('Media Constraints'),
+ '#description' => t('Select which recording options will be available using the Media Browser.'),
+ );
+ $form['media_recorder_constraints']['audio'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Audio'),
+ '#default_value' => $constraints['audio'],
+ );
+ $form['media_recorder_constraints']['video'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Video'),
+ '#default_value' => $constraints['video'],
+ );
+ $form['media_recorder_constraints']['video_resolution'] = array(
+ '#type' => 'radios',
+ '#title' => t('Video Resolution'),
+ '#default_value' => $constraints['video_resolution'],
+ '#options' => array(
+ 640 => t('640 x 480'),
+ 480 => t('480 x 360'),
+ 320 => t('320 x 240'),
+ 240 => t('240 x 180'),
+ 180 => t('180 x 135'),
+ ),
+ );
+
+ // Recorder time limit.
$form['media_recorder_time_limit'] = array(
'#type' => 'textfield',
'#title' => t('Time Limit'),
@@ -45,5 +81,13 @@ function media_recorder_admin_form($form, $form_state) {
);
}
+ // Recorder CSS enabled.
+ $form['media_recorder_css'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use default CSS stylesheet?'),
+ '#description' => t('Disable if you want to use a different set of styles without having to override the default CSS.'),
+ '#default_value' => variable_get('media_recorder_css', TRUE),
+ );
+
return system_settings_form($form);
}
diff --git a/includes/media_recorder.drush.inc b/includes/media_recorder.drush.inc
index 34b7e2b..dea498e 100644
--- a/includes/media_recorder.drush.inc
+++ b/includes/media_recorder.drush.inc
@@ -9,11 +9,14 @@
* Implements hook_drush_command().
*/
function media_recorder_drush_command() {
+ $items = array();
+
$items['media-recorder-download-libraries'] = array(
'description' => dt('Download and install all libraries associated with Media Recorder.'),
'aliases' => array('mrdl'),
'callback' => 'drush_media_recorder_download_libraries',
);
+
return $items;
}
@@ -22,13 +25,18 @@ function media_recorder_drush_command() {
* @see media_recorder_drush_command()
*/
function drush_media_recorder_download_libraries() {
+ if (!module_exists('libraries')) {
+ return FALSE;
+ }
+
+ // Get base path.
$base_path = drush_get_context('DRUSH_DRUPAL_CORE');
- // Create the libraries path if it doesn't exist.
- drush_mkdir($base_path . '/sites/all/libraries');
+ // Get sites path.
+ $site_path = (conf_path() == 'sites/default') ? 'sites/all' : conf_path();
// Check that all libraries exist.
- $required_libraries = array('swfobject', 'recorder.js', 'Recorderjs');
+ $required_libraries = array('swfobject', 'FlashWavRecorder', 'Recorderjs');
foreach ($required_libraries as $name) {
// Get library info for each library.
@@ -44,7 +52,8 @@ function drush_media_recorder_download_libraries() {
drush_op('chdir', drush_tempdir());
// Get library path and download link from library info.
- $library_path = $library['library path'] ? $base_path . '/' . $library['library path'] : $base_path . '/sites/all/libraries/' . $name;
+ $library_path = $base_path . '/' . $site_path . '/libraries/' . $name;
+
$download_url = '';
if (!empty($library['download url'])) {
$download_url = $library['download url'];
@@ -52,25 +61,33 @@ function drush_media_recorder_download_libraries() {
// Download and unzip into libraries.
if (!empty($download_url)) {
+
// Download the zip archive.
$filename = drush_download_file($download_url);
if (!file_exists($filename)) {
return drush_set_error(dt('Unable to download @url', array('@url' => $download_url)));
}
+
// Decompress the zip archive.
$extract = drush_tarball_extract($filename, FALSE, TRUE);
+
// Move directory.
- if (is_dir($extract[0])) {
- drush_move_dir($extract[0], $library_path);
+ if (is_dir($extract[0]) && drush_move_dir($extract[0], $library_path)) {
+ drush_log(dt('The @name library has been downloaded to @path', array('@name' => $name, '@path' => $library_path)), 'success');
+ }
+ elseif (is_dir($extract[1]) && drush_move_dir($extract[1], $library_path)) {
+ drush_log(dt('The @name library has been downloaded to @path', array('@name' => $name, '@path' => $library_path)), 'success');
}
- elseif (is_dir($extract[1])) {
- drush_move_dir($extract[1], $library_path);
+ else {
+ drush_log(dt('Unable to download @name library to @path', array('@name' => $name, '@path' => $library_path)), 'success');
}
- drush_log(dt('The @name library has been downloaded to @path', array('@name' => $name, '@path' => $library_path)), 'success');
}
// Return to base path.
drush_op('chdir', $base_path);
+
}
+
+ return NULL;
}
diff --git a/js/media-recorder-api.js b/js/media-recorder-api.js
index c7cff0f..1cae3bd 100755..100644
--- a/js/media-recorder-api.js
+++ b/js/media-recorder-api.js
@@ -3,350 +3,574 @@
* Adds an interface between the media recorder jQuery plugin and the drupal media module.
*/
-(function($) {
+(function ($) {
'use strict';
- Drupal.behaviors.mediaRecorder = {
- attach: function(context, settings) {
- $('.field-widget-media-recorder').once().each(function (key, element) {
-
- // Hide all file field related elements.
- $(element).find('span.file, span.file-size, .media-recorder-upload, .media-recorder-upload-button, .media-recorder-remove-button').hide();
-
- // Declare DOM elements.
- var $element = $(element);
- var $audioConstraintButton = $element.find('.media-recorder-enable-audio');
- var $videoConstraintButton = $element.find('.media-recorder-enable-video');
- var $previewWrapper = $element.find('.media-recorder-preview');
- var $statusWrapper = $element.find('.media-recorder-status');
- var $controlsWrapper = $element.find('.media-recorder-controls');
- var $recordButton = $element.find('.media-recorder-record');
- var $stopButton = $element.find('.media-recorder-stop');
-
- // Click handler for enable audio button.
- $audioConstraintButton.bind('click', function (event) {
- event.preventDefault();
- $audioConstraintButton.addClass('active');
- $videoConstraintButton.removeClass('active');
- startStream({
- audio: true,
- video: false
- });
- });
-
- // Click handler for enable video button.
- $videoConstraintButton.bind('click', function (event) {
- event.preventDefault();
- $audioConstraintButton.removeClass('active');
- $videoConstraintButton.addClass('active');
- startStream({
- audio: true,
- video: true
- });
- });
+ Drupal.MediaRecorder = (function () {
+ var settings = Drupal.settings.mediaRecorder.settings;
+ var origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
+ var audioContext = null;
+ var canvasContext = null;
+ var visualizerProcessor = null;
+ var freqData = null;
+ var volume = 0;
+ var barWidth = 0;
+ var level = 0;
+ var meterProcessor = null;
+ var constraints = {};
+ var localStream = null;
+ var recorder = null;
+ var recordURL = null;
+ var playbackURL = null;
+ var format = null;
+ var mimetype = null;
+ var analyser = null;
+ var microphone = null;
+ var blobs = [];
+ var files = [];
+ var blobCount = 0;
+ var statusInterval = null;
+ var $element = null;
+ var $statusWrapper = null;
+ var $previewWrapper = null;
+ var $video = null;
+ var $audio = null;
+ var $meter = null;
+ var $startButton = null;
+ var $recordButton = null;
+ var $stopButton = null;
+ var $playButton = null;
+ var $settingsButton = null;
+ var $videoButton = null;
+ var $audioButton = null;
+
+ /**
+ * Set status message.
+ */
+ function setStatus(message) {
+ $element.trigger('status', message);
+ }
- // Click handler for record button.
- $recordButton.bind('click', function (event) {
- event.preventDefault();
- Drupal.mediaRecorder.record();
- });
+ /**
+ * Create volume meter canvas element that uses getUserMedia stream.
+ */
+ function createVolumeMeter() {
- // Click handler for stop button.
- $stopButton.bind('click', function (event) {
- event.preventDefault();
- Drupal.mediaRecorder.stop();
- });
+ // Private function for determining current volume.
+ function getVolume() {
+ var values = 0;
+ var length = freqData.length;
- // Listen for the record event.
- $(Drupal.mediaRecorder).bind('recordStart', function (event, data) {
- var currentSeconds = 0;
- var timeLimit = millisecondsToTime(new Date(parseInt(Drupal.mediaRecorder.settings.time_limit, 10) * 1000));
-
- $recordButton.hide();
- $stopButton.show();
- $(Drupal.mediaRecorder).trigger('status', 'Recording 00:00 (Time Limit: ' + timeLimit + ')');
-
- function millisecondsToTime(milliSeconds) {
- var milliSecondsDate = new Date(milliSeconds);
- var mm = milliSecondsDate.getMinutes();
- var ss = milliSecondsDate.getSeconds();
- if (mm < 10) {
- mm = "0" + mm;
- }
- if (ss < 10) {
- ss = "0" + ss;
- }
- return mm + ':' + ss;
- }
+ for (var i = 0; i < length; i++) {
+ values += freqData[i];
+ }
- Drupal.mediaRecorder.statusInterval = setInterval(function () {
- currentSeconds = currentSeconds + 1;
- var currentMilliSeconds = new Date(currentSeconds * 1000);
- var time = millisecondsToTime(currentMilliSeconds);
- $(Drupal.mediaRecorder).trigger('status', 'Recording ' + time + ' (Time Limit: ' + timeLimit + ')');
+ return values / length;
+ }
- if (currentSeconds >= Drupal.mediaRecorder.settings.time_limit) {
- Drupal.mediaRecorder.stop();
- }
- }, 1000);
- });
+ canvasContext = $meter[0].getContext("2d");
+ meterProcessor = audioContext.createScriptProcessor(1024, 1, 1);
+ microphone.connect(analyser);
+ analyser.connect(meterProcessor);
+ meterProcessor.connect(audioContext.destination);
+ meterProcessor.onaudioprocess = function () {
+ freqData = new Uint8Array(analyser.frequencyBinCount);
+ analyser.getByteFrequencyData(freqData);
+ volume = getVolume();
+ level = Math.max.apply(Math, freqData);
+
+ if (volume === 0) {
+ $meter.addClass('muted');
+ }
+ else {
+ $meter.removeClass('muted');
+ }
- // Listen for the stop event.
- $(Drupal.mediaRecorder).bind('recordStop', function (event) {
- $stopButton.hide();
- clearInterval(Drupal.mediaRecorder.statusInterval);
- $(Drupal.mediaRecorder).trigger('status', 'Processing file...');
- });
+ canvasContext.clearRect(0, 0, $meter[0].width, $meter[0].height);
+ canvasContext.fillStyle = '#00ff00';
+ canvasContext.fillRect(0, 0, $meter[0].width * (level / 255), $meter[0].height);
+ };
+ }
- // Append file object data.
- $(Drupal.mediaRecorder).bind('refreshData', function (event, data) {
- $element.find('.media-recorder-fid').val(data.fid);
- $element.find('.media-recorder-refresh').trigger('mousedown');
- $recordButton[0].disabled = false;
- $(Drupal.mediaRecorder).trigger('status', 'Press record to start recording.');
- $recordButton.show();
- });
+ /**
+ * Create audio visualizer canvas element that uses getUserMedia stream.
+ */
+ function createAudioVisualizer() {
- $(Drupal.mediaRecorder).bind('status', function (event, msg) {
- $statusWrapper.text(msg);
- });
+ // Private function for determining current volume.
+ function getVolume() {
+ var values = 0;
+ var length = freqData.length;
- // Initial state.
- $previewWrapper.hide();
- $controlsWrapper.hide();
- $(Drupal.mediaRecorder).trigger('status', 'Select audio or video to begin recording.');
-
- /**
- * Start user media stream.
- */
- function startStream (constraints) {
- if (Drupal.mediaRecorder.stream) {
- stopStream();
- }
- navigator.getUserMedia(
- constraints,
- function(stream) {
- Drupal.mediaRecorder.stream = stream;
- Drupal.mediaRecorder.recorder = new MediaRecorder(Drupal.mediaRecorder.stream);
- Drupal.mediaRecorder.format = constraints.video ? 'webm' : 'ogg';
- Drupal.mediaRecorder.mimetype = constraints.video ? 'video/webm' : 'audio/ogg';
- Drupal.mediaRecorder.audioContext = new AudioContext();
- Drupal.mediaRecorder.analyser = Drupal.mediaRecorder.audioContext.createAnalyser();
- Drupal.mediaRecorder.microphone = Drupal.mediaRecorder.audioContext.createMediaStreamSource(stream);
- Drupal.mediaRecorder.analyser.smoothingTimeConstant = 0.75;
- Drupal.mediaRecorder.analyser.fftSize = 512;
-
- $previewWrapper.show();
- $controlsWrapper.show();
- $stopButton.hide();
-
- $(Drupal.mediaRecorder).trigger('status', 'Press record to start recording.');
-
- if (constraints.video) {
- var video = $('<video autoplay muted src="' + URL.createObjectURL(Drupal.mediaRecorder.stream) + '"></video>');
- video[0].muted = 'muted'; // Firefox isn't muting as expected.
- var volumeMeter = $(createVolumeMeter());
- video.appendTo($previewWrapper).height($previewWrapper.height());
- volumeMeter.appendTo($previewWrapper).height($previewWrapper.height());
- video[0].play();
- $previewWrapper.addClass('video').removeClass('audio');
- } else {
- var audioVisualizer = $(createAudioVisualizer());
- audioVisualizer.appendTo($previewWrapper).height($previewWrapper.height());
- $previewWrapper.addClass('audio').removeClass('video');
- }
- },
- function(error) {
- alert("There was a problem accessing your camera or mic. Please click 'Allow' at the top of the page.");
- }
- );
+ for (var i = 0; i < length; i++) {
+ values += freqData[i];
}
- /**
- * Stop user media stream.
- */
- function stopStream () {
- Drupal.mediaRecorder.analyser.disconnect();
- Drupal.mediaRecorder.microphone.disconnect();
- Drupal.mediaRecorder.stream.stop();
- $previewWrapper.text('');
- $previewWrapper.hide();
+ return values / length;
+ }
+
+ canvasContext = $meter[0].getContext("2d");
+
+ visualizerProcessor = audioContext.createScriptProcessor(1024, 1, 1);
+ microphone.connect(analyser);
+ analyser.connect(visualizerProcessor);
+ visualizerProcessor.connect(audioContext.destination);
+
+ visualizerProcessor.onaudioprocess = function () {
+ freqData = new Uint8Array(analyser.frequencyBinCount);
+ analyser.getByteFrequencyData(freqData);
+ volume = getVolume();
+ barWidth = Math.ceil($meter[0].width / (analyser.frequencyBinCount * 0.5));
+
+ if (volume === 0) {
+ $meter.addClass('muted');
+ }
+ else {
+ $meter.removeClass('muted');
}
- /**
- * Create volume meter canvas element that uses getUserMedia stream.
- */
- function createVolumeMeter () {
- var canvas = document.createElement('canvas');
- var canvasContext = canvas.getContext("2d");
-
- Drupal.mediaRecorder.meterProcessor = Drupal.mediaRecorder.audioContext.createScriptProcessor(2048, 1, 1);
- Drupal.mediaRecorder.microphone.connect(Drupal.mediaRecorder.analyser);
- Drupal.mediaRecorder.analyser.connect(Drupal.mediaRecorder.meterProcessor);
- Drupal.mediaRecorder.meterProcessor.connect(Drupal.mediaRecorder.audioContext.destination);
-
- Drupal.mediaRecorder.meterProcessor.onaudioprocess = function() {
- var freqData = new Uint8Array(Drupal.mediaRecorder.analyser.frequencyBinCount);
- Drupal.mediaRecorder.analyser.getByteFrequencyData(freqData);
- var level = Math.max.apply(Math, freqData);
- canvasContext.clearRect(0, 0, canvas.width, canvas.clientHeight);
- canvasContext.fillStyle = '#00ff00';
- canvasContext.fillRect(0, canvas.height - (canvas.height * (level / 255)), canvas.width, canvas.height * (level / 255));
- };
-
- canvas.className = 'media-recorder-meter';
-
- return canvas;
+ canvasContext.clearRect(0, 0, $meter[0].width, $meter[0].height);
+ for (var i = 0; i < analyser.frequencyBinCount; i++) {
+ canvasContext.fillStyle = 'hsl(' + i / analyser.frequencyBinCount * 360 + ', 100%, 50%)';
+ if ((barWidth * i) + barWidth < $meter[0].width) {
+ canvasContext.fillRect(barWidth * i, $meter[0].height, barWidth - 1, -(Math.floor((freqData[i] / 255) * $meter[0].height)));
+ }
}
+ };
+ }
- /**
- * Create audio visualizer canvas element that uses getUserMedia stream.
- */
- function createAudioVisualizer () {
- var canvas = document.createElement('canvas');
- var canvasContext = canvas.getContext("2d");
- var micStatus = false;
+ /**
+ * Toggle to recording preview.
+ */
+ function recordingPreview() {
+ if (constraints.video) {
+ $video.show();
+ $audio.hide();
+ $video[0].src = recordURL;
+ $video[0].muted = 'muted';
+ $video[0].controls = '';
+ $video[0].load();
+ $video[0].play();
+ $meter.height(20);
+ }
+ else {
+ $video.hide();
+ $audio.hide();
+ $meter.height($meter.width() / 2);
+ }
+ }
- if (!Drupal.mediaRecorder.audioContext || !Drupal.mediaRecorder.microphone || !Drupal.mediaRecorder.analyser) {
- var textWidth, textString = 'Audio visualizer unable to initialize';
+ /**
+ * Toggle to recording preview.
+ */
+ function playbackPreview() {
+ if (blobs.length === 0) {
+ return;
+ }
+ if (constraints.video) {
+ playbackURL = URL.createObjectURL(new Blob(blobs, {type: mimetype}));
+ $video.show();
+ $audio.hide();
+ $video[0].src = playbackURL;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ }
+ else {
+ playbackURL = URL.createObjectURL(new Blob(blobs, {type: mimetype}));
+ $audio.show();
+ $audio[0].src = playbackURL;
+ $audio[0].load();
+ }
+ }
- canvasContext.font = 'bold 1em Arial';
- canvasContext.fillStyle = '#ffffff';
- textWidth = canvasContext.measureText(textString).width;
- canvasContext.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2);
+ /**
+ * Send a blob as form data to the server. Requires jQuery 1.5+.
+ */
+ function sendBlob(blob, count) {
+
+ // Create formData object.
+ var formData = new FormData();
+ formData.append("blob", blob);
+ formData.append("count", count);
+
+ // Return ajax promise.
+ $.ajax({
+ url: origin + Drupal.settings.basePath + 'media_recorder/record/stream/record',
+ type: 'POST',
+ data: formData,
+ processData: false,
+ contentType: false,
+ success: function (data) {
+ files.push(data);
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ }
+ });
+ }
+
+ /**
+ * Stop user media stream.
+ */
+ function stopStream() {
+ analyser.disconnect();
+ microphone.disconnect();
+ localStream.stop();
+ $previewWrapper.hide();
+ $startButton.show();
+ $recordButton.hide();
+ $stopButton.hide();
+ }
+
+ /**
+ * Start user media stream.
+ */
+ function startStream() {
+ if (localStream) {
+ stopStream();
+ }
+ navigator.getUserMedia(
+ constraints,
+ function (stream) {
+ localStream = stream;
+ recorder = new MediaRecorder(localStream);
+ recordURL = URL.createObjectURL(localStream);
+ format = constraints.video ? 'webm' : 'ogg';
+ mimetype = constraints.video ? 'video/webm' : 'audio/ogg';
+ audioContext = new AudioContext();
+ analyser = audioContext.createAnalyser();
+ analyser.smoothingTimeConstant = 0.75;
+ analyser.fftSize = 512;
+ microphone = audioContext.createMediaStreamSource(stream);
+
+ $previewWrapper.show();
+ $meter.show();
+ $startButton.hide();
+ $videoButton.hide();
+ $audioButton.hide();
+ $recordButton.show();
+ $stopButton.hide();
+ recordingPreview();
- return canvas;
+ if (constraints.video) {
+ createVolumeMeter();
+ }
+ else {
+ createAudioVisualizer();
}
- Drupal.mediaRecorder.visualizerProcessor = Drupal.mediaRecorder.audioContext.createScriptProcessor(2048, 1, 1);
- Drupal.mediaRecorder.microphone.connect(Drupal.mediaRecorder.analyser);
- Drupal.mediaRecorder.analyser.connect(Drupal.mediaRecorder.visualizerProcessor);
- Drupal.mediaRecorder.visualizerProcessor.connect(Drupal.mediaRecorder.audioContext.destination);
-
- Drupal.mediaRecorder.visualizerProcessor.onaudioprocess = function() {
- var freqData = new Uint8Array(Drupal.mediaRecorder.analyser.frequencyBinCount);
- Drupal.mediaRecorder.analyser.getByteFrequencyData(freqData);
- var volume = getVolume();
-
- if (volume === 0) {
- micStatus = false;
- $(Drupal.mediaRecorder).trigger('status', 'Your mic has a problem. Check your browser or computer audio settings.');
- } else if (volume && !micStatus) {
- micStatus = true;
- $(Drupal.mediaRecorder).trigger('status', 'Press record to start recording.');
- }
+ setStatus('Press record to start recording.');
+ },
+ function (error) {
+ stopStream();
+ alert("There was a problem accessing your camera or mic. Please click 'Allow' at the top of the page.");
+ }
+ );
+ }
- var barWidth = Math.ceil(canvas.width / (Drupal.mediaRecorder.analyser.frequencyBinCount * 0.5));
- canvasContext.clearRect(0, 0, canvas.width, canvas.height);
- for (var i = 0; i < Drupal.mediaRecorder.analyser.frequencyBinCount; i++) {
- canvasContext.fillStyle = 'hsl(' + i / Drupal.mediaRecorder.analyser.frequencyBinCount * 360 + ', 100%, 50%)';
- if ((barWidth * i) + barWidth < canvas.width) {
- canvasContext.fillRect(barWidth * i, canvas.height, barWidth - 1, -(Math.floor((freqData[i] / 255) * canvas.height) + 1));
- }
- }
+ /**
+ * Enable mic or camera.
+ */
+ function start() {
+ if (settings.constraints.audio && !settings.constraints.video) {
+ constraints = {
+ audio: true,
+ video: false
+ };
+ startStream();
+ }
+ else if (!settings.constraints.audio && settings.constraints.video) {
+ startStream();
+ }
+ else {
+ $startButton.hide();
+ $videoButton.show();
+ $audioButton.show();
+ setStatus('Record with audio or video?');
+ }
+ }
- // Private function for determining current volume.
- function getVolume() {
- var values = 0;
- var length = freqData.length;
- for (var i = 0; i < length; i++) {
- values += freqData[i];
- }
- return values / length;
- }
- };
+ /**
+ * Stop recording and trigger stopped event.
+ */
+ function stop() {
+ recorder.stop();
+ $element.trigger('recordStop');
+ }
- canvas.className = 'media-recorder-visualizer';
+ /**
+ * Start recording and trigger recording event.
+ */
+ function record() {
+ blobs = [];
+ files = [];
+ blobCount = 0;
+
+ // Triggered on data available.
+ recorder.ondataavailable = function (e) {
+ var blob = new Blob([e.data], {type: e.data.type || mimetype});
+ if (blob.size > 0) {
+ blobs.push(blob);
+ blobCount++;
+ sendBlob(blob, blobCount);
+ }
+ };
+
+ // Triggered when recording is stopped. Requires ajax 1.5+.
+ recorder.onstop = function (e) {
+ $(document).ajaxStop(function () {
+ $(this).unbind("ajaxStop");
+ $.ajax({
+ url: origin + Drupal.settings.basePath + 'media_recorder/record/stream/finish',
+ type: 'POST',
+ async: true,
+ data: {
+ count: blobs.length
+ },
+ success: function (data) {
+ $element.trigger('refreshData', data);
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ alert('There was an issue saving your recording, please try again.');
+ }
+ });
+ });
+ };
- return canvas;
+ // Notify server that recording has started. Start recording if server is available.
+ $.ajax({
+ url: origin + Drupal.settings.basePath + 'media_recorder/record/stream/start',
+ type: 'POST',
+ data: {
+ format: format
+ },
+ async: false,
+ success: function (data) {
+ recorder.start(3000);
+ $element.trigger('recordStart');
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ alert('There was an issue starting your recording, please try again.');
}
});
+ }
- /**
- * Start recording and trigger recording event.
- */
- Drupal.mediaRecorder.record = function () {
- Drupal.mediaRecorder.blobs = [];
- Drupal.mediaRecorder.blobCount = 0;
-
- // Triggered on data available.
- Drupal.mediaRecorder.recorder.ondataavailable = function (e) {
- var blob = new Blob([e.data], { type: e.data.type || Drupal.mediaRecorder.mimetype });
- if (blob.size > 0) {
- Drupal.mediaRecorder.blobCount++;
- Drupal.mediaRecorder.sendBlob(blob, Drupal.mediaRecorder.blobCount);
- }
- };
+ /**
+ * Initialize all control buttons.
+ */
+ function initializeButtons() {
- // Triggered when recording is stopped. Requires ajax 1.5+.
- Drupal.mediaRecorder.recorder.onstop = function (e) {
- $(document).ajaxStop(function () {
- $(this).unbind("ajaxStop");
- $.ajax({
- url: Drupal.mediaRecorder.origin + Drupal.settings.basePath + 'media_recorder/record/stream/finish',
- type: 'POST',
- async: true,
- data: {
- count: Drupal.mediaRecorder.blobs.length
- },
- success: function (data) {
- $(Drupal.mediaRecorder).trigger('refreshData', data);
- },
- error: function (data) {
- alert('There was an issue saving your recording, please try again.');
- }
- });
- });
+ // Click handler for enable audio button.
+ $startButton.bind('click', function (event) {
+ event.preventDefault();
+ start();
+ });
+
+ // Click handler for record button.
+ $recordButton.bind('click', function (event) {
+ event.preventDefault();
+ $recordButton[0].disabled = true;
+ $recordButton.hide();
+ $stopButton.show();
+ record();
+ });
+
+ // Click handler for stop button.
+ $stopButton.bind('click', function (event) {
+ event.preventDefault();
+ $stopButton.hide();
+ $recordButton.show();
+ stop();
+ });
+
+ // Click handler for to change to video.
+ $videoButton.bind('click', function (event) {
+ event.preventDefault();
+ setStatus('Allow access at top of page.');
+ startStream();
+ });
+
+ // Click handler for to change to audio.
+ $audioButton.bind('click', function (event) {
+ event.preventDefault();
+ constraints = {
+ audio: true,
+ video: false
};
+ setStatus('Allow access at top of page.');
+ startStream();
+ });
- // Notify server that recording has started. Start recording if server is available.
- $.ajax({
- url: Drupal.mediaRecorder.origin + Drupal.settings.basePath + 'media_recorder/record/stream/start',
- type: 'POST',
- data: {
- format: Drupal.mediaRecorder.format
- },
- async: false,
- success: function (data) {
- Drupal.mediaRecorder.recorder.start(1000);
- $(Drupal.mediaRecorder).trigger('recordStart');
- }
- });
- };
+ }
- /**
- * Stop recording and trigger stopped event.
- */
- Drupal.mediaRecorder.stop = function () {
- Drupal.mediaRecorder.recorder.stop();
- $(Drupal.mediaRecorder).trigger('recordStop');
- };
+ /**
+ * Initialize recorder.
+ */
+ function initializeEvents() {
+
+ // Listen for the record event.
+ $element.bind('recordStart', function (event, data) {
+ var currentSeconds = 0;
+ var timeLimitFormatted = millisecondsToTime(new Date(parseInt(settings.time_limit, 10) * 1000));
+
+ recordingPreview();
+ setStatus('Recording 00:00 (Time Limit: ' + timeLimitFormatted + ')');
+
+ statusInterval = setInterval(function () {
+ currentSeconds = currentSeconds + 1;
+ var currentMilliSeconds = new Date(currentSeconds * 1000);
+ var time = millisecondsToTime(currentMilliSeconds);
+ setStatus('Recording ' + time + ' (Time Limit: ' + timeLimitFormatted + ')');
- /**
- * Send a blob as form data to the server. Requires jQuery 1.5+.
- */
- Drupal.mediaRecorder.sendBlob = function (blob, count) {
-
- // Create formData object.
- var formData = new FormData();
- formData.append("blob", blob);
- formData.append("count", count);
-
- // Return ajax promise.
- $.ajax({
- url: Drupal.mediaRecorder.origin + Drupal.settings.basePath + 'media_recorder/record/stream/record',
- type: 'POST',
- data: formData,
- processData: false,
- contentType: false,
- success: function (data) {
- Drupal.mediaRecorder.blobs.push(data);
- },
- error: function (jqXHR, textStatus, errorThrown) {
- console.log(jqXHR, textStatus, errorThrown);
+ if (currentSeconds >= settings.time_limit) {
+ stop();
}
- });
+ }, 1000);
+ });
+
+ // Listen for the stop event.
+ $element.bind('recordStop', function (event) {
+ clearInterval(statusInterval);
+ setStatus('Please wait while the recording finishes uploading...');
+ });
+
+ // Append file object data.
+ $element.bind('refreshData', function (event, data) {
+ $element.find('.media-recorder-fid').val(data.fid);
+ $recordButton[0].disabled = false;
+ playbackPreview();
+ setStatus('Press record to start recording.');
+ });
+
+ $element.bind('status', function (event, msg) {
+ $statusWrapper.text(msg);
+ });
+ }
+
+ /**
+ * Convert milliseconds to time format.
+ */
+ function millisecondsToTime(milliSeconds) {
+ var milliSecondsDate = new Date(milliSeconds);
+ var mm = milliSecondsDate.getMinutes();
+ var ss = milliSecondsDate.getSeconds();
+ if (mm < 10) {
+ mm = "0" + mm;
+ }
+ if (ss < 10) {
+ ss = "0" + ss;
+ }
+ return mm + ':' + ss;
+ }
+
+ /**
+ * Initialize recorder.
+ */
+ function init(element) {
+ $element = $(element);
+ $statusWrapper = $element.find('.media-recorder-status');
+ $previewWrapper = $element.find('.media-recorder-preview');
+ $video = $element.find('.media-recorder-video');
+ $audio = $element.find('.media-recorder-audio');
+ $meter = $element.find('.media-recorder-meter');
+ $startButton = $element.find('.media-recorder-enable');
+ $recordButton = $element.find('.media-recorder-record');
+ $stopButton = $element.find('.media-recorder-stop');
+ $playButton = $element.find('.media-recorder-play');
+ $settingsButton = $element.find('.media-recorder-settings');
+ $videoButton = $element.find('.media-recorder-enable-video');
+ $audioButton = $element.find('.media-recorder-enable-audio');
+
+ // Initial state.
+ $recordButton[0].disabled = false;
+ $recordButton.hide();
+ $stopButton.hide();
+ $playButton.hide();
+ $settingsButton.hide();
+ $video.hide();
+ $audio.hide();
+ $meter.hide();
+ $videoButton.hide();
+ $audioButton.hide();
+ $previewWrapper.hide();
+
+ constraints.audio = true;
+ constraints.video = {};
+ if (settings.constraints.video) {
+ switch (settings.constraints.video_resolution) {
+ case '640':
+ constraints.video = {
+ width: 640,
+ height: 480
+ };
+ break;
+ case '480':
+ constraints.video = {
+ width: 480,
+ height: 360
+ };
+ break;
+ case '320':
+ constraints.video = {
+ width: 320,
+ height: 240
+ };
+ break;
+ case '240':
+ constraints.video = {
+ width: 240,
+ height: 180
+ };
+ break;
+ case '180':
+ constraints.video = {
+ width: 180,
+ height: 135
+ };
+ break;
+ }
+ constraints.video.frameRate = {
+ min: 30,
+ ideal: 30,
+ max: 30
+ };
}
+
+ // Show file preview if file exists.
+ if (Drupal.settings.mediaRecorder.file) {
+ var file = Drupal.settings.mediaRecorder.file;
+ switch (file.type) {
+ case 'video':
+ $previewWrapper.show();
+ $video.show();
+ $audio.hide();
+ $video[0].src = Drupal.settings.mediaRecorder.file.url;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ break;
+ case 'audio':
+ $previewWrapper.show();
+ $audio.show();
+ $video.hide();
+ $audio[0].src = Drupal.settings.mediaRecorder.file.url;
+ $audio[0].muted = '';
+ $audio[0].controls = 'controls';
+ $audio[0].load();
+ break;
+ }
+ }
+
+ initializeButtons();
+ initializeEvents();
+ setStatus('Click \'Start\' to enable your mic & camera.');
}
- };
+
+ return {
+ init: init,
+ start: start,
+ record: record,
+ stop: stop
+ };
+ })();
})(jQuery);
diff --git a/js/media-recorder-flash.js b/js/media-recorder-flash.js
index 5b8ed60..b4511c5 100755..100644
--- a/js/media-recorder-flash.js
+++ b/js/media-recorder-flash.js
@@ -3,152 +3,362 @@
* Adds an interface between the media recorder jQuery plugin and the drupal media module.
*/
-(function($) {
+(function ($) {
'use strict';
- Drupal.behaviors.mediaRecorder = {
- attach: function(context, settings) {
- $('.field-widget-media-recorder').once().each(function (key, element) {
-
- // Store all data in the element, since we may very well have many recorders on a page.
- var $element = $(element);
-
- // Hide file field related markup.
- $element.find('span.file, span.file-size, .media-recorder-upload, .media-recorder-upload-button, .media-recorder-remove-button').hide();
-
- // Declare DOM elements.
- var $constraintsWrapper = $element.find('.media-recorder-constraints');
- var $previewWrapper = $element.find('.media-recorder-preview');
- var $statusWrapper = $element.find('.media-recorder-status');
- var $controlsWrapper = $element.find('.media-recorder-controls');
- var $recordButton = $element.find('.media-recorder-record');
- var $stopButton = $element.find('.media-recorder-stop');
- var $settingsButton = $('<button class="media-recorder-settings">Settings</button>');
-
- // Initialize flash recorder.
- Recorder.initialize({
- swfSrc: settings.basePath + settings.mediaRecorder.swfurl + '/recorder.swf',
- });
-
- // Click handler for record button.
- $recordButton.bind('click', function (event) {
- event.preventDefault();
- Drupal.mediaRecorder.record();
- });
-
- // Click handler for stop button.
- $stopButton.bind('click', function (event) {
- event.preventDefault();
- Drupal.mediaRecorder.stop();
- });
-
- // Click handler for stop button.
- $settingsButton.bind('click', function (event) {
- event.preventDefault();
- Recorder.flashInterface().showFlash();
- });
-
- // Listen for the record event.
- $(Drupal.mediaRecorder).bind('recordStart', function (event, data) {
- $recordButton.hide();
- $stopButton.show();
- });
-
- // Listen for the progress event.
- $(Drupal.mediaRecorder).bind('progress', function (event, data) {
- function millisecondsToTime(milliSeconds) {
- // Format Current Time
- var milliSecondsDate = new Date(milliSeconds);
- var mm = milliSecondsDate.getMinutes();
- var ss = milliSecondsDate.getSeconds();
- if (mm < 10) {
- mm = "0" + mm;
- }
- if (ss < 10) {
- ss = "0" + ss;
- }
- return mm + ':' + ss;
- }
- var time = millisecondsToTime(data);
- var timeLimit = millisecondsToTime(new Date(parseInt(Drupal.mediaRecorder.settings.time_limit, 10) * 1000));
+ Drupal.MediaRecorderFlash = (function () {
+ var settings = Drupal.settings.mediaRecorder.settings;
+ var origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
+ var recordingName;
+ var statusInterval;
+ var $element;
+ var $statusWrapper;
+ var $previewWrapper;
+ var $video;
+ var $audio;
+ var $meter;
+ var $startButton;
+ var $recordButton;
+ var $playButton;
+ var $stopButton;
+ var $settingsButton;
+ var $videoButton;
+ var $audioButton;
- $statusWrapper.html('Recording ' + time + ' (Time Limit: ' + timeLimit + ')');
+ /**
+ * Set status message.
+ */
+ function setStatus(message) {
+ $element.trigger('status', message);
+ }
- if (data / 1000 >= Drupal.mediaRecorder.settings.time_limit) {
- Drupal.mediaRecorder.stop();
- }
- });
+ /**
+ * Toggle to recording preview.
+ */
+ function showSettings() {
+ FWRecorder.showPermissionWindow({permanent: true});
+ }
+
+ /**
+ * Send a blob as form data to the server. Requires jQuery 1.5+.
+ */
+ function sendBlob(blob) {
+ setStatus('Uploading, please wait...');
+
+ // Create formData object.
+ var formData = new FormData();
+ var req = new XMLHttpRequest();
+ formData.append("mediaRecorder", blob);
+
+ // Send file.
+ req.addEventListener("load", transferComplete, false);
+ req.open('POST', origin + Drupal.settings.basePath + 'media_recorder/record/file', true);
+ req.send(formData);
+ function transferComplete(evt) {
+ var file = JSON.parse(req.response);
+ $element.trigger('uploadFinished', file);
+ }
+ }
+
+ /**
+ * Stop recording and trigger stopped event.
+ */
+ function start() {
+ showSettings();
+ }
- // Listen for the stop event.
- $(Drupal.mediaRecorder).bind('recordStop', function (event) {
- $recordButton.show();
- $stopButton.hide();
- });
+ /**
+ * Stop recording and trigger stopped event.
+ */
+ function stop() {
+ FWRecorder.stopPlayBack();
+ FWRecorder.stopRecording();
+ }
- $(Drupal.mediaRecorder).bind('uploadStarted', function (event) {
- $statusWrapper.html('<div>Uploading, please wait...</div>');
- });
+ /**
+ * Start recording and trigger recording event.
+ */
+ function record() {
+ FWRecorder.record(recordingName);
+ }
- $(Drupal.mediaRecorder).bind('uploadFinished', function (event, data) {
- $statusWrapper.html('<div>Press record to start recording.</div>');
+ /**
+ * Initialize all control buttons.
+ */
+ function initializeButtons() {
- // Append file object data.
- $element.find('.media-recorder-fid').val(data.fid);
- $element.find('.media-recorder-refresh').trigger('mousedown');
- });
+ // Click handler for enable button.
+ $startButton.bind('click', function (event) {
+ event.preventDefault();
+ $startButton[0].disabled = true;
+ start();
+ setStatus('Allow access to your mic in the settings panel.');
+ });
+
+ // Click handler for record button.
+ $recordButton.bind('click', function (event) {
+ event.preventDefault();
+ $recordButton[0].disabled = true;
+ $recordButton.hide();
+ $playButton.hide();
+ $stopButton.show();
+ record();
+ });
- // Initial state.
- $constraintsWrapper.hide();
- $previewWrapper.hide();
+ // Click handler for stop button.
+ $stopButton.bind('click', function (event) {
+ event.preventDefault();
$stopButton.hide();
- $statusWrapper.html('<div>Press record to start recording.</div>');
- $controlsWrapper.append($settingsButton);
+ $recordButton.show();
+ $playButton.show();
+ stop();
+ });
+
+ // Click handler for play button.
+ $playButton.bind('click', function (event) {
+ event.preventDefault();
+ $playButton.hide();
+ $stopButton.show();
+ FWRecorder.playBack(recordingName);
+ });
+
+ // Click handler for settings button.
+ $settingsButton.bind('click', function (event) {
+ event.preventDefault();
+ showSettings();
+ });
+ }
+
+ /**
+ * Initialize recorder.
+ */
+ function initializeEvents() {
+
+ // FWRecorder ready event.
+ $element.bind('ready', function (event) {
+
+ // Fix for weird FWRecorder use of window instead of document.
+ window['flashRecorder'] = document['flashRecorder'];
+
+ FWRecorder.connect('flashRecorder', 0);
+ FWRecorder.recorderOriginalWidth = 1;
+ FWRecorder.recorderOriginalHeight = 1;
+
+ if (!FWRecorder.isMicrophoneAccessible()) {
+ $startButton.show();
+ }
+ });
+
+ // FWRecorder microphone_connected event.
+ $element.bind('microphone_user_request', function (event) {
+ FWRecorder.showPermissionWindow();
+ });
+
+ // FWRecorder microphone_connected event.
+ $element.bind('microphone_connected', function (event) {
+ FWRecorder.configure(22, 50, 0, 4000);
+ $startButton.hide();
+ $recordButton.show();
+ setStatus('Press record to start recording.');
+ FWRecorder.observeLevel();
});
- /**
- * Start recording and trigger recording event.
- */
- Drupal.mediaRecorder.record = function () {
+ // FWRecorder microphone_not_connected event.
+ $element.bind('microphone_not_connected', function (event) {
+ $startButton.show();
+ $startButton[0].disabled = false;
+ $recordButton.hide();
+ setStatus('Click \'Start\' to enable your mic & camera.');
+ });
+
+ // FWRecorder no_microphone_found event.
+ $element.bind('no_microphone_found', function (event, name, data) {
+ $startButton.show();
+ $startButton[0].disabled = false;
+ $recordButton.hide();
+ setStatus('No mic found. Click \'Start\' to enable your mic & camera.');
+ });
+
+ // FWRecorder permission_panel_closed event.
+ $element.bind('permission_panel_closed', function (event) {
+ FWRecorder.defaultSize();
+ });
+
+ // FWRecorder observing_level event.
+ $element.bind('observing_level', function (event, name, data) {
+ $meter.show();
+ $meter.height(20);
+ });
+
+ // FWRecorder observing_level_stopped event.
+ $element.bind('observing_level_stopped', function (event, name, data) {
+ $meter.hide();
+ });
- Recorder.record({
- start: function(){
+ // FWRecorder microphone_level event.
+ $element.bind('microphone_level', function (event, name, data) {
+ var level = data * 100;
+ $meter.width(level + '%');
+ if (data * 100 <= 70) {
+ $meter.css({
+ 'background': 'green'
+ });
+ }
+ else if (level > 70 && level < 85) {
+ $meter.css({
+ 'background': 'yellow'
+ });
+ }
+ else if (level >= 85) {
+ $meter.css({
+ 'background': 'red'
+ });
+ }
+ });
+
+ // FWRecorder recording event.
+ $element.bind('recording', function (event, data) {
+ var currentSeconds = 0;
+ var timeLimitFormatted = millisecondsToTime(new Date(parseInt(settings.time_limit, 10) * 1000));
- // Trigger recording event.
- $(Drupal.mediaRecorder).trigger('recordStart');
- },
- progress: function (milliseconds) {
+ setStatus('Recording 00:00 (Time Limit: ' + timeLimitFormatted + ')');
+ statusInterval = setInterval(function () {
+ currentSeconds = currentSeconds + 1;
+ var currentMilliSeconds = new Date(currentSeconds * 1000);
+ var time = millisecondsToTime(currentMilliSeconds);
+ setStatus('Recording ' + time + ' (Time Limit: ' + timeLimitFormatted + ')');
- // Trigger recording event.
- $(Drupal.mediaRecorder).trigger('progress', milliseconds);
+ if (currentSeconds >= settings.time_limit) {
+ stop();
}
- });
- };
+ }, 1000);
+ });
- /**
- * Stop recording and trigger stopped event.
- */
- Drupal.mediaRecorder.stop = function () {
+ // FWRecorder recording_stopped event.
+ $element.bind('recording_stopped', function (event) {
+ var blob = FWRecorder.getBlob(recordingName);
+ clearInterval(statusInterval);
+ sendBlob(blob);
+ });
- Recorder.stop();
+ // FWRecorder recording_stopped event.
+ $element.bind('stopped', function (event) {
+ $playButton.show();
+ $stopButton.hide();
+ });
- // Trigger uploading event.
- $(Drupal.mediaRecorder).trigger('uploadStarted');
+ $element.bind('uploadFinished', function (event, data) {
+ $element.find('.media-recorder-fid').val(data.fid);
+ $recordButton[0].disabled = false;
+ setStatus('Press record to start recording.');
+ });
- Recorder.upload({
- url: Drupal.mediaRecorder.origin + Drupal.settings.basePath + '/media_recorder/record/file',
- audioParam: 'mediaRecorder',
- success: function(response) {
- var file = JSON.parse(response);
+ $element.bind('status', function (event, msg) {
+ $statusWrapper.text(msg);
+ });
+ }
- // Trigger stopped event.
- $(Drupal.mediaRecorder).trigger('uploadFinished', file);
- },
- });
+ /**
+ * Convert milliseconds to time format.
+ */
+ function millisecondsToTime(milliSeconds) {
+ var milliSecondsDate = new Date(milliSeconds);
+ var mm = milliSecondsDate.getMinutes();
+ var ss = milliSecondsDate.getSeconds();
+ if (mm < 10) {
+ mm = "0" + mm;
+ }
+ if (ss < 10) {
+ ss = "0" + ss;
+ }
+ return mm + ':' + ss;
+ }
- // Trigger stopped event.
- $(Drupal.mediaRecorder).trigger('recordStop');
+ /**
+ * Initialize recorder.
+ */
+ function init(element) {
+ $element = $(element);
+ $statusWrapper = $element.find('.media-recorder-status');
+ $previewWrapper = $element.find('.media-recorder-preview');
+ $video = $element.find('.media-recorder-video');
+ $audio = $element.find('.media-recorder-audio');
+ $meter = $element.find('.media-recorder-meter');
+ $startButton = $element.find('.media-recorder-enable');
+ $recordButton = $element.find('.media-recorder-record');
+ $stopButton = $element.find('.media-recorder-stop');
+ $playButton = $element.find('.media-recorder-play');
+ $settingsButton = $element.find('.media-recorder-settings');
+ $videoButton = $element.find('.media-recorder-enable-video');
+ $audioButton = $element.find('.media-recorder-enable-audio');
+ recordingName = 'audio';
+
+ // Append flash recorder div.
+ $element.append('<div id="flash-wrapper"><div id="flashcontent"><p>Your browser must have JavaScript enabled and the Adobe Flash Player installed.</p></div></div>');
+
+ // Initialize flash recorder.
+ window.fwr_event_handler = function (eventName) {
+ $element.trigger(eventName, arguments);
};
+ swfobject.embedSWF(
+ Drupal.settings.basePath + Drupal.settings.mediaRecorder.flashurl + '/html/recorder.swf',
+ 'flashcontent',
+ 1,
+ 1,
+ '11.0.0',
+ '',
+ {},
+ {},
+ {'id': 'flashRecorder', 'name': 'flashRecorder'}
+ );
+
+ // Initial state.
+ $recordButton.hide();
+ $recordButton.hide();
+ $stopButton.hide();
+ $playButton.hide();
+ $stopButton.before($playButton);
+ $video.hide();
+ $audio.hide();
+ $meter.hide();
+ $videoButton.hide();
+ $audioButton.hide();
+
+ // Show file preview if file exists.
+ if (Drupal.settings.mediaRecorder.file) {
+ var file = Drupal.settings.mediaRecorder.file;
+ switch (file.type) {
+ case 'video':
+ $previewWrapper.show();
+ $video.show();
+ $audio.hide();
+ $video[0].src = Drupal.settings.mediaRecorder.file.url;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ break;
+ case 'audio':
+ $previewWrapper.show();
+ $audio.show();
+ $video.hide();
+ $audio[0].src = Drupal.settings.mediaRecorder.file.url;
+ $audio[0].muted = '';
+ $audio[0].controls = 'controls';
+ $audio[0].load();
+ break;
+ }
+ }
+
+ initializeButtons();
+ initializeEvents();
+ setStatus('Click \'Start\' to enable your mic & camera.');
+ }
- },
- };
+ return {
+ init: init,
+ start: start,
+ record: record,
+ stop: stop
+ };
+ })();
})(jQuery);
diff --git a/js/media-recorder-html5.js b/js/media-recorder-html5.js
index 36e50ea..1766f09 100755..100644
--- a/js/media-recorder-html5.js
+++ b/js/media-recorder-html5.js
@@ -3,319 +3,426 @@
* Adds an interface between the media recorder jQuery plugin and the drupal media module.
*/
-(function($) {
+(function ($) {
'use strict';
- Drupal.behaviors.mediaRecorder = {
- attach: function(context, settings) {
- $('.field-widget-media-recorder').once().each(function (key, element) {
-
- // Hide all file field related elements.
- $(element).find('span.file, span.file-size, .media-recorder-upload, .media-recorder-upload-button, .media-recorder-remove-button').hide();
-
- // Declare DOM elements.
- var $element = $(element);
- var $audioConstraintButton = $element.find('.media-recorder-enable-audio');
- var $videoConstraintButton = $element.find('.media-recorder-enable-video');
- var $previewWrapper = $element.find('.media-recorder-preview');
- var $statusWrapper = $element.find('.media-recorder-status');
- var $controlsWrapper = $element.find('.media-recorder-controls');
- var $recordButton = $element.find('.media-recorder-record');
- var $stopButton = $element.find('.media-recorder-stop');
-
- // Click handler for enable audio button.
- $audioConstraintButton.bind('click', function (event) {
- event.preventDefault();
- $audioConstraintButton.addClass('active');
- $videoConstraintButton.removeClass('active');
- startStream({
- audio: true,
- video: false
- });
- });
-
- // Click handler for enable video button.
- $videoConstraintButton.bind('click', function (event) {
- event.preventDefault();
- $audioConstraintButton.removeClass('active');
- $videoConstraintButton.addClass('active');
- startStream({
- audio: true,
- video: true
- });
- });
-
- // Click handler for record button.
- $recordButton.bind('click', function (event) {
- event.preventDefault();
- Drupal.mediaRecorder.record();
- });
-
- // Click handler for stop button.
- $stopButton.bind('click', function (event) {
- event.preventDefault();
- Drupal.mediaRecorder.stop();
- });
-
- // Listen for the record event.
- $(Drupal.mediaRecorder).bind('recordStart', function (event, data) {
- var currentSeconds = 0;
- var timeLimit = millisecondsToTime(new Date(parseInt(Drupal.mediaRecorder.settings.time_limit, 10) * 1000));
-
- $recordButton.hide();
- $stopButton.show();
- $(Drupal.mediaRecorder).trigger('status', 'Recording 00:00 (Time Limit: ' + timeLimit + ')');
-
- function millisecondsToTime(milliSeconds) {
- var milliSecondsDate = new Date(milliSeconds);
- var mm = milliSecondsDate.getMinutes();
- var ss = milliSecondsDate.getSeconds();
- if (mm < 10) {
- mm = "0" + mm;
- }
- if (ss < 10) {
- ss = "0" + ss;
- }
- return mm + ':' + ss;
- }
+ Drupal.MediaRecorderHTML5 = (function () {
+ var settings = Drupal.settings.mediaRecorder.settings;
+ var origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
+ var audioContext;
+ var canvasContext;
+ var visualizerProcessor;
+ var freqData;
+ var volume;
+ var barWidth;
+ var level;
+ var meterProcessor;
+ var constraints;
+ var localStream;
+ var recorder;
+ var recordURL;
+ var playbackURL;
+ var mimetype;
+ var analyser;
+ var microphone;
+ var blobs;
+ var statusInterval;
+ var $element;
+ var $statusWrapper;
+ var $previewWrapper;
+ var $video;
+ var $audio;
+ var $meter;
+ var $startButton;
+ var $recordButton;
+ var $playButton;
+ var $stopButton;
+ var $settingsButton;
+ var $videoButton;
+ var $audioButton;
+
+ /**
+ * Set status message.
+ */
+ function setStatus(message) {
+ $element.trigger('status', message);
+ }
+
+ /**
+ * Create volume meter canvas element that uses getUserMedia stream.
+ */
+ function createVolumeMeter() {
+ canvasContext = $meter[0].getContext("2d");
+ meterProcessor = audioContext.createScriptProcessor(1024, 1, 1);
+ microphone.connect(analyser);
+ analyser.connect(meterProcessor);
+ meterProcessor.connect(audioContext.destination);
+ meterProcessor.onaudioprocess = function () {
+ freqData = new Uint8Array(analyser.frequencyBinCount);
+ analyser.getByteFrequencyData(freqData);
+ level = Math.max.apply(Math, freqData);
+ canvasContext.clearRect(0, 0, $meter[0].width, $meter[0].height);
+ canvasContext.fillStyle = '#00ff00';
+ canvasContext.fillRect(0, 0, $meter[0].width * (level / 255), $meter[0].height);
+ };
+ }
- Drupal.mediaRecorder.statusInterval = setInterval(function () {
- currentSeconds = currentSeconds + 1;
- var currentMilliSeconds = new Date(currentSeconds * 1000);
- var time = millisecondsToTime(currentMilliSeconds);
- $(Drupal.mediaRecorder).trigger('status', 'Recording ' + time + ' (Time Limit: ' + timeLimit + ')');
+ /**
+ * Create audio visualizer canvas element that uses getUserMedia stream.
+ */
+ function createAudioVisualizer() {
- if (currentSeconds >= Drupal.mediaRecorder.settings.time_limit) {
- Drupal.mediaRecorder.stop();
- }
- }, 1000);
- });
+ // Private function for determining current volume.
+ function getVolume() {
+ var values = 0;
+ var length = freqData.length;
- // Listen for the stop event.
- $(Drupal.mediaRecorder).bind('recordStop', function (event) {
- $recordButton.show();
- $stopButton.hide();
- clearInterval(Drupal.mediaRecorder.statusInterval);
- });
-
- $(Drupal.mediaRecorder).bind('uploadStarted', function (event) {
- $(Drupal.mediaRecorder).trigger('status', 'Uploading, please wait...');
- });
-
- $(Drupal.mediaRecorder).bind('uploadFinished', function (event, data) {
- $(Drupal.mediaRecorder).trigger('status', 'Press record to start recording.');
-
- // Append file object data.
- $element.find('.media-recorder-fid').val(data.fid);
- $element.find('.media-recorder-refresh').trigger('mousedown');
- });
-
- $(Drupal.mediaRecorder).bind('status', function (event, msg) {
- $statusWrapper.text(msg);
- });
-
- // Initial state.
- $previewWrapper.hide();
- $controlsWrapper.hide();
- //$(Drupal.mediaRecorder).trigger('status', 'Select audio or video to begin recording.');
-
- // Disable video for now.
- $videoConstraintButton.hide();
- $audioConstraintButton.text('Start');
- $(Drupal.mediaRecorder).trigger('status', 'Click \'Start\' to enable your microphone.');
-
- /**
- * Start user media stream.
- */
- function startStream (constraints) {
- if (Drupal.mediaRecorder.stream) {
- stopStream();
- }
- navigator.getUserMedia(constraints,
- function(stream) {
- Drupal.mediaRecorder.stream = stream;
- Drupal.mediaRecorder.format = constraints.video ? 'webm' : 'ogg';
- Drupal.mediaRecorder.mimetype = constraints.video ? 'video/webm' : 'audio/ogg';
- Drupal.mediaRecorder.audioContext = new AudioContext();
- Drupal.mediaRecorder.analyser = Drupal.mediaRecorder.audioContext.createAnalyser();
- Drupal.mediaRecorder.microphone = Drupal.mediaRecorder.audioContext.createMediaStreamSource(stream);
- Drupal.mediaRecorder.analyser.smoothingTimeConstant = 0.75;
- Drupal.mediaRecorder.analyser.fftSize = 512;
-
- $previewWrapper.show();
- $controlsWrapper.show();
- $stopButton.hide();
-
- $(Drupal.mediaRecorder).trigger('status', 'Press record to start recording.');
-
- if (constraints.video) {
- var video = $('<video muted autoplay src="' + URL.createObjectURL(Drupal.mediaRecorder.stream) + '"></video>');
- var volumeMeter = $(createVolumeMeter());
- video.appendTo($previewWrapper).height($previewWrapper.height());
- volumeMeter.appendTo($previewWrapper).height($previewWrapper.height());
- video[0].play();
- $previewWrapper.addClass('video').removeClass('audio');
- } else {
- var audioVisualizer = $(createAudioVisualizer());
- audioVisualizer.appendTo($previewWrapper).height($previewWrapper.height());
- $previewWrapper.addClass('audio').removeClass('video');
- }
- },
- function(error) {
- }
- );
+ for (var i = 0; i < length; i++) {
+ values += freqData[i];
}
- /**
- * Stop user media stream.
- */
- function stopStream () {
- Drupal.mediaRecorder.analyser.disconnect();
- Drupal.mediaRecorder.microphone.disconnect();
- Drupal.mediaRecorder.stream.stop();
- $previewWrapper.text('');
- $previewWrapper.hide();
- }
+ return values / length;
+ }
- /**
- * Create volume meter canvas element that uses getUserMedia stream.
- */
- function createVolumeMeter () {
- var canvas = document.createElement('canvas');
- var canvasContext = canvas.getContext("2d");
-
- Drupal.mediaRecorder.meterProcessor = Drupal.mediaRecorder.audioContext.createScriptProcessor(2048, 1, 1);
- Drupal.mediaRecorder.microphone.connect(Drupal.mediaRecorder.analyser);
- Drupal.mediaRecorder.analyser.connect(Drupal.mediaRecorder.meterProcessor);
- Drupal.mediaRecorder.meterProcessor.connect(Drupal.mediaRecorder.audioContext.destination);
-
- Drupal.mediaRecorder.meterProcessor.onaudioprocess = function() {
- var freqData = new Uint8Array(Drupal.mediaRecorder.analyser.frequencyBinCount);
- Drupal.mediaRecorder.analyser.getByteFrequencyData(freqData);
- var level = Math.max.apply(Math, freqData);
- canvasContext.clearRect(0, 0, canvas.width, canvas.clientHeight);
- canvasContext.fillStyle = '#00ff00';
- canvasContext.fillRect(0, canvas.height - (canvas.height * (level / 255)), canvas.width, canvas.height * (level / 255));
- };
-
- canvas.className = 'media-recorder-meter';
-
- return canvas;
- }
+ canvasContext = $meter[0].getContext("2d");
+
+ visualizerProcessor = audioContext.createScriptProcessor(1024, 1, 1);
+ microphone.connect(analyser);
+ analyser.connect(visualizerProcessor);
+ visualizerProcessor.connect(audioContext.destination);
- /**
- * Create audio visualizer canvas element that uses getUserMedia stream.
- */
- function createAudioVisualizer () {
- var canvas = document.createElement('canvas');
- var canvasContext = canvas.getContext("2d");
- var micStatus = false;
+ visualizerProcessor.onaudioprocess = function (audioProcessingEvent) {
+ freqData = new Uint8Array(analyser.frequencyBinCount);
+ analyser.getByteFrequencyData(freqData);
+ volume = getVolume();
- if (!Drupal.mediaRecorder.audioContext || !Drupal.mediaRecorder.microphone || !Drupal.mediaRecorder.analyser) {
- var textWidth, textString = 'Audio visualizer unable to initialize';
+ if (volume === 0) {
+ $meter.addClass('muted');
+ }
+ else {
+ $meter.removeClass('muted');
+ }
- canvasContext.font = 'bold 1em Arial';
- canvasContext.fillStyle = '#ffffff';
- textWidth = canvasContext.measureText(textString).width;
- canvasContext.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2);
+ barWidth = Math.ceil($meter[0].width / (analyser.frequencyBinCount * 0.5));
+ canvasContext.clearRect(0, 0, $meter[0].width, $meter[0].height);
+ for (var i = 0; i < analyser.frequencyBinCount; i++) {
+ canvasContext.fillStyle = 'hsl(' + i / analyser.frequencyBinCount * 360 + ', 100%, 50%)';
+ if ((barWidth * i) + barWidth < $meter[0].width) {
+ canvasContext.fillRect(barWidth * i, $meter[0].height, barWidth - 1, -(Math.floor((freqData[i] / 255) * $meter[0].height)));
+ }
+ }
+ };
+ }
+
+ /**
+ * Toggle to recording preview.
+ */
+ function recordingPreview() {
+ if (constraints.video) {
+ $video.show();
+ $audio.hide();
+ $video[0].src = recordURL;
+ $video[0].muted = 'muted';
+ $video[0].controls = '';
+ $video[0].load();
+ $video[0].play();
+ $meter.height(10);
+ }
+ else {
+ $video.hide();
+ $audio.hide();
+ $meter.height($meter.width() / 2);
+ }
+ }
+
+ /**
+ * Toggle to recording preview.
+ */
+ function playbackPreview() {
+ if (blobs.length === 0) {
+ return;
+ }
+ if (constraints.video) {
+ playbackURL = URL.createObjectURL(new Blob(blobs, {type: mimetype}));
+ $video.show();
+ $audio.hide();
+ $video[0].src = playbackURL;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ }
+ else {
+ playbackURL = URL.createObjectURL(new Blob(blobs, {type: mimetype}));
+ $audio.show();
+ $audio[0].src = playbackURL;
+ $audio[0].load();
+ }
+ }
+
+ /**
+ * Send a blob as form data to the server. Requires jQuery 1.5+.
+ */
+ function sendBlob(blob, count) {
+
+ // Create formData object.
+ var formData = new FormData();
+ var req = new XMLHttpRequest();
+ formData.append("mediaRecorder", blob);
+ blobs = [blob];
+
+ // Send file.
+ req.addEventListener("load", transferComplete, false);
+ req.open('POST', origin + Drupal.settings.basePath + 'media_recorder/record/file', true);
+ req.send(formData);
+ function transferComplete(evt) {
+ var file = JSON.parse(req.response);
+ $element.trigger('uploadFinished', file);
+ }
+ }
+
+ /**
+ * Stop user media stream.
+ */
+ function stopStream() {
+ analyser.disconnect();
+ microphone.disconnect();
+ localStream.stop();
+ $previewWrapper.hide();
+ $startButton.show();
+ $recordButton.hide();
+ $stopButton.hide();
+ }
+
+ /**
+ * Start user media stream.
+ */
+ function startStream() {
+ if (localStream) {
+ stopStream();
+ }
+ navigator.getUserMedia(
+ constraints,
+ function (stream) {
+ localStream = stream;
+ recordURL = URL.createObjectURL(localStream);
+ mimetype = settings.constraints.video ? 'video/webm' : 'audio/ogg';
+ audioContext = new AudioContext();
+ analyser = audioContext.createAnalyser();
+ analyser.smoothingTimeConstant = 0.75;
+ analyser.fftSize = 512;
+ microphone = audioContext.createMediaStreamSource(stream);
+ recorder = new Recorder(microphone, {workerPath: Drupal.settings.basePath + Drupal.settings.mediaRecorder.html5url + '/recorderWorker.js'});
+
+ $previewWrapper.show();
+ $meter.show();
+ $startButton.hide();
+ $recordButton.show();
+ $stopButton.hide();
+ recordingPreview();
- return canvas;
+ if (constraints.video) {
+ createVolumeMeter();
+ }
+ else {
+ createAudioVisualizer();
}
- Drupal.mediaRecorder.visualizerProcessor = Drupal.mediaRecorder.audioContext.createScriptProcessor(2048, 1, 1);
- Drupal.mediaRecorder.microphone.connect(Drupal.mediaRecorder.analyser);
- Drupal.mediaRecorder.analyser.connect(Drupal.mediaRecorder.visualizerProcessor);
- Drupal.mediaRecorder.visualizerProcessor.connect(Drupal.mediaRecorder.audioContext.destination);
-
- Drupal.mediaRecorder.visualizerProcessor.onaudioprocess = function() {
- var freqData = new Uint8Array(Drupal.mediaRecorder.analyser.frequencyBinCount);
- Drupal.mediaRecorder.analyser.getByteFrequencyData(freqData);
- var volume = getVolume();
-
- if (volume === 0) {
- micStatus = false;
- $(Drupal.mediaRecorder).trigger('status', 'Your mic has a problem. Check your browser or computer audio settings.');
- } else if (volume && !micStatus) {
- micStatus = true;
- $(Drupal.mediaRecorder).trigger('status', 'Press record to start recording.');
- }
-
- var barWidth = Math.ceil(canvas.width / (Drupal.mediaRecorder.analyser.frequencyBinCount * 0.5));
- canvasContext.clearRect(0, 0, canvas.width, canvas.height);
- for (var i = 0; i < Drupal.mediaRecorder.analyser.frequencyBinCount; i++) {
- canvasContext.fillStyle = 'hsl(' + i / Drupal.mediaRecorder.analyser.frequencyBinCount * 360 + ', 100%, 50%)';
- if ((barWidth * i) + barWidth < canvas.width) {
- canvasContext.fillRect(barWidth * i, canvas.height, barWidth - 1, -(Math.floor((freqData[i] / 255) * canvas.height) + 1));
- }
- }
-
- // Private function for determining current volume.
- function getVolume() {
- var values = 0;
- var length = freqData.length;
- for (var i = 0; i < length; i++) {
- values += freqData[i];
- }
- return values / length;
- }
- };
-
- canvas.className = 'media-recorder-visualizer';
-
- return canvas;
+ setStatus('Press record to start recording.');
+ },
+ function (error) {
+ stopStream();
+ alert("There was a problem accessing your camera or mic. Please click 'Allow' at the top of the page.");
}
+ );
+ }
+
+ /**
+ * Stop recording and trigger stopped event.
+ */
+ function start() {
+ constraints = {
+ audio: true,
+ video: false
+ };
+
+ startStream();
+ }
+
+ /**
+ * Stop recording and trigger stopped event.
+ */
+ function stop() {
+ recorder.stop();
+ recorder.exportWAV(function (blob) {
+ sendBlob(blob);
+ });
+ recorder.clear();
+ $element.trigger('recordStop');
+ }
+
+ /**
+ * Start recording and trigger recording event.
+ */
+ function record() {
+ recorder.record();
+ $element.trigger('recordStart');
+ }
+
+ /**
+ * Initialize all control buttons.
+ */
+ function initializeButtons() {
+
+ // Click handler for enable audio button.
+ $startButton.bind('click', function (event) {
+ event.preventDefault();
+ $startButton[0].disabled = true;
+ start();
+ setStatus('Allow access at top of page.');
});
- /**
- * Start recording and trigger recording event.
- */
- Drupal.mediaRecorder.record = function () {
+ // Click handler for record button.
+ $recordButton.bind('click', function (event) {
+ event.preventDefault();
+ $recordButton[0].disabled = true;
+ $recordButton.hide();
+ $stopButton.show();
+ record();
+ });
- // Create a recorder using the gain node.
- Drupal.mediaRecorder.recorder = new Recorder(Drupal.mediaRecorder.microphone, {workerPath:settings.basePath + settings.mediaRecorder.html5url + '/recorderWorker.js'});
- Drupal.mediaRecorder.recorder.record();
+ // Click handler for stop button.
+ $stopButton.bind('click', function (event) {
+ event.preventDefault();
+ $stopButton.hide();
+ $recordButton.show();
+ stop();
+ });
+ }
- // Trigger recording event.
- $(Drupal.mediaRecorder).trigger('recordStart');
- };
+ /**
+ * Initialize recorder.
+ */
+ function initializeEvents() {
- /**
- * Stop recording and trigger stopped event.
- */
- Drupal.mediaRecorder.stop = function () {
+ // Listen for the record event.
+ $element.bind('recordStart', function (event, data) {
+ var currentSeconds = 0;
+ var timeLimitFormatted = millisecondsToTime(new Date(parseInt(settings.time_limit, 10) * 1000));
- // Stop MediaRecorder and delete object (is deletion needed?).
- Drupal.mediaRecorder.recorder.stop();
+ recordingPreview();
+ setStatus('Recording 00:00 (Time Limit: ' + timeLimitFormatted + ')');
- // Export the wav and send to server.
- Drupal.mediaRecorder.recorder.exportWAV(function(blob) {
- Drupal.mediaRecorder.sendBlob(blob);
- });
+ statusInterval = setInterval(function () {
+ currentSeconds = currentSeconds + 1;
+ var currentMilliSeconds = new Date(currentSeconds * 1000);
+ var time = millisecondsToTime(currentMilliSeconds);
+ setStatus('Recording ' + time + ' (Time Limit: ' + timeLimitFormatted + ')');
- // Clear the recorder.
- Drupal.mediaRecorder.recorder.clear();
+ if (currentSeconds >= settings.time_limit) {
+ stop();
+ }
+ }, 1000);
+ });
- // Trigger stopped event.
- $(Drupal.mediaRecorder).trigger('recordStop');
- };
+ // Listen for the stop event.
+ $element.bind('recordStop', function (event) {
+ clearInterval(statusInterval);
+ setStatus('Uploading, please wait...');
+ });
- Drupal.mediaRecorder.sendBlob = function (blob) {
- var formData = new FormData();
- var req = new XMLHttpRequest();
- formData.append("mediaRecorder", blob);
-
- // Trigger uploading event.
- $(Drupal.mediaRecorder).trigger('uploadStarted');
-
- // Send file.
- req.addEventListener("load", transferComplete, false);
- req.open('POST', Drupal.mediaRecorder.origin + Drupal.settings.basePath + 'media_recorder/record/file', true);
- req.send(formData);
- function transferComplete(evt) {
- var file = JSON.parse(req.response);
- $(Drupal.mediaRecorder).trigger('uploadFinished', file);
+ $element.bind('uploadFinished', function (event, data) {
+ $element.find('.media-recorder-fid').val(data.fid);
+ $recordButton[0].disabled = false;
+ playbackPreview();
+ setStatus('Press record to start recording.');
+ });
+
+ $element.bind('status', function (event, msg) {
+ $statusWrapper.text(msg);
+ });
+ }
+
+ /**
+ * Convert milliseconds to time format.
+ */
+ function millisecondsToTime(milliSeconds) {
+ var milliSecondsDate = new Date(milliSeconds);
+ var mm = milliSecondsDate.getMinutes();
+ var ss = milliSecondsDate.getSeconds();
+ if (mm < 10) {
+ mm = "0" + mm;
+ }
+ if (ss < 10) {
+ ss = "0" + ss;
+ }
+ return mm + ':' + ss;
+ }
+
+ /**
+ * Initialize recorder.
+ */
+ function init(element) {
+ $element = $(element);
+ $statusWrapper = $element.find('.media-recorder-status');
+ $previewWrapper = $element.find('.media-recorder-preview');
+ $video = $element.find('.media-recorder-video');
+ $audio = $element.find('.media-recorder-audio');
+ $meter = $element.find('.media-recorder-meter');
+ $startButton = $element.find('.media-recorder-enable');
+ $recordButton = $element.find('.media-recorder-record');
+ $stopButton = $element.find('.media-recorder-stop');
+ $playButton = $element.find('.media-recorder-play');
+ $settingsButton = $element.find('.media-recorder-settings');
+ $videoButton = $element.find('.media-recorder-enable-video');
+ $audioButton = $element.find('.media-recorder-enable-audio');
+
+ // Initial state.
+ $recordButton.hide();
+ $stopButton.hide();
+ $playButton.hide();
+ $settingsButton.hide();
+ $video.hide();
+ $audio.hide();
+ $meter.hide();
+ $videoButton.hide();
+ $audioButton.hide();
+ $previewWrapper.hide();
+
+ // Show file preview if file exists.
+ if (Drupal.settings.mediaRecorder.file) {
+ var file = Drupal.settings.mediaRecorder.file;
+ switch (file.type) {
+ case 'video':
+ $previewWrapper.show();
+ $video.show();
+ $audio.hide();
+ $video[0].src = Drupal.settings.mediaRecorder.file.url;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ break;
+ case 'audio':
+ $previewWrapper.show();
+ $audio.show();
+ $video.hide();
+ $audio[0].src = Drupal.settings.mediaRecorder.file.url;
+ $audio[0].muted = '';
+ $audio[0].controls = 'controls';
+ $audio[0].load();
+ break;
}
- };
- },
- };
+ }
+
+ initializeButtons();
+ initializeEvents();
+ setStatus('Click \'Start\' to enable your mic & camera.');
+ }
+
+ return {
+ init: init,
+ start: start,
+ record: record,
+ stop: stop
+ };
+ })();
})(jQuery);
diff --git a/js/media-recorder.browser.js b/js/media-recorder.browser.js
index af2f9fc..d23533f 100644
--- a/js/media-recorder.browser.js
+++ b/js/media-recorder.browser.js
@@ -3,23 +3,25 @@
* Media browser JS integration for the Media Recorder module.
*/
-(function($) {
+(function ($) {
+ 'use strict';
+
Drupal.behaviors.mediaRecorderBrowser = {
- attach: function (context, settings) {
+ attach: function () {
// Bind click handler to media recorder submit input.
- $('#media-tab-media_recorder input[type="submit"]').bind('click', function (event) {
+ $('#media-recorder-add #edit-submit').bind('click', function (event) {
// Prevent regular form submit.
event.preventDefault();
// Get the fid value.
- var fid = $('#media-tab-media_recorder .media-recorder-fid').val();
+ var fid = $('#media-recorder-add .media-recorder-fid').val();
// Build file object.
var file = {};
file.fid = fid;
- file.preview = $('#media-tab-media_recorder .media-recorder-preview .content').html();
+ file.preview = $('#media-recorder-add .media-recorder-preview').html();
// Add to selected media.
var files = [];
diff --git a/js/media-recorder.js b/js/media-recorder.js
index 394130a..47b7abc 100755..100644
--- a/js/media-recorder.js
+++ b/js/media-recorder.js
@@ -4,70 +4,59 @@
* libraries.
*/
-(function($) {
+(function ($) {
'use strict';
- // Add mediaRecorder object to Drupal.
- Drupal.mediaRecorder = Drupal.mediaRecorder || {};
- Drupal.mediaRecorder.settings = Drupal.settings.mediaRecorder.settings;
-
// Normalize features.
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
window.URL = window.URL || window.webkitURL;
- Drupal.mediaRecorder.origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
// Feature detection.
- var getUserMediaCheck = typeof(navigator.getUserMedia) === 'function';
- var mediaRecorderCheck = typeof(window.MediaRecorder) === 'function';
- var webAudioCheck = typeof(window.AudioContext) === 'function';
- var swfobjectCheck = typeof(window.swfobject) === 'object';
+ var getUserMediaCheck = typeof (navigator.getUserMedia) === 'function';
+ var mediaRecorderCheck = typeof (window.MediaRecorder) === 'function';
+ var webAudioCheck = typeof (window.AudioContext) === 'function';
+ var swfobjectCheck = typeof (window.swfobject) === 'object';
var flashVersionCheck = swfobjectCheck ? (swfobject.getFlashPlayerVersion().major >= 10) : false;
- // Check to see that browser can use the recorder.
- if ((getUserMediaCheck && webAudioCheck) || (flashVersionCheck && swfobjectCheck)) {
-
- // Use the MediaRecorder API. Currently only works in firefox.
- if (getUserMediaCheck && webAudioCheck && mediaRecorderCheck) {
- $.ajax({
- url: Drupal.settings.basePath + Drupal.settings.mediaRecorder.modulePath + '/media-recorder-api.js',
- async: false,
- dataType: 'script'
- });
- }
-
- // Use HTML5 features (Web Audio API).
- else if (getUserMediaCheck && webAudioCheck && !mediaRecorderCheck) {
- $.ajax({
- url: Drupal.settings.basePath + Drupal.settings.mediaRecorder.html5url + '/recorder.js',
- async: false,
- dataType: 'script'
- });
- $.ajax({
- url: Drupal.settings.basePath + Drupal.settings.mediaRecorder.modulePath + '/media-recorder-html5.js',
- async: false,
- dataType: 'script'
- });
+ Drupal.behaviors.mediaRecorder = {
+ attach: function () {
+
+ // Check to see that browser can use the recorder.
+ if ((getUserMediaCheck && webAudioCheck) || (flashVersionCheck && swfobjectCheck)) {
+
+ $('.field-widget-media-recorder').once().each(function (key, element) {
+
+ // Add Drupal MediaRecorder module and initialize.
+ if (getUserMediaCheck && webAudioCheck && mediaRecorderCheck) {
+ element.recorder = Drupal.MediaRecorder;
+ }
+ else if (getUserMediaCheck && webAudioCheck && !mediaRecorderCheck) {
+ element.recorder = Drupal.MediaRecorderHTML5;
+ }
+ else if (flashVersionCheck) {
+
+ // Check for IE9+.
+ if (!document.addEventListener) {
+ alert("The media recorder is not available on versions of Internet Explorer earlier than IE9.");
+ $('.field-widget-media-recorder').find('.media-recorder-wrapper').hide();
+ return;
+ }
+ element.recorder = Drupal.MediaRecorderFlash;
+ }
+
+ // Hide the normal file input.
+ $(element).find('span.file, span.file-size, .media-recorder-upload, .media-recorder-upload-button, .media-recorder-remove-button').hide();
+
+ // Initialize the recorder.
+ element.recorder.init(element);
+ });
+ }
+
+ // Otherwise just use the basic file field.
+ else {
+ $('.field-widget-media-recorder').find('.media-recorder-wrapper').hide();
+ }
}
-
- // Use Flash.
- else if (flashVersionCheck) {
- $.ajax({
- url: Drupal.settings.basePath + Drupal.settings.mediaRecorder.swfurl + '/recorder.js',
- async: false,
- dataType: 'script'
- });
- $.ajax({
- url: Drupal.settings.basePath + Drupal.settings.mediaRecorder.modulePath + '/media-recorder-flash.js',
- async: false,
- dataType: 'script'
- });
- }
- }
-
- // Otherwise just use the basic file field.
- else {
- $('.field-widget-media-recorder').find('.media-recorder-wrapper').hide();
- }
-
+ };
})(jQuery);
diff --git a/media_recorder.info b/media_recorder.info
index 34e6daf..34e6daf 100755..100644
--- a/media_recorder.info
+++ b/media_recorder.info
diff --git a/media_recorder.install b/media_recorder.install
index 4795676..c6a378f 100755..100644
--- a/media_recorder.install
+++ b/media_recorder.install
@@ -18,7 +18,7 @@ function media_recorder_requirements($phase) {
// Check that all libraries exist.
$required_libraries = array(
'swfobject',
- 'recorder.js',
+ 'FlashWavRecorder',
'Recorderjs',
);
foreach ($required_libraries as $name) {
@@ -53,7 +53,7 @@ function media_recorder_enable() {
foreach ($required_libraries as $name) {
$library = libraries_detect($name);
if (!$library['installed']) {
- $drush_msg = t('You can use the drush command "drush @site mrdl" to automatically install all required libraries.');
+ $drush_msg = t('You can use the drush command "drush mrdl" to automatically install all required libraries.');
drupal_set_message($library['error message'] . ' ' . $drush_msg, 'error');
}
}
@@ -63,8 +63,8 @@ function media_recorder_enable() {
* Implements hook_uninstall().
*/
function media_recorder_uninstall() {
- variable_del('media_recorder_width');
- variable_del('media_recorder_height');
- variable_del('media_recorder_timelimit');
+ variable_del('media_recorder_constraints');
+ variable_del('media_recorder_time_limit');
variable_del('media_recorder_upload_directory');
+ variable_del('media_recorder_css');
}
diff --git a/media_recorder.module b/media_recorder.module
index 67a96ee..09a7139 100755..100644
--- a/media_recorder.module
+++ b/media_recorder.module
@@ -13,15 +13,15 @@ function media_recorder_libraries_info() {
$libraries['swfobject'] = array(
'name' => 'SWFObject',
'description' => 'SWFObject is an easy-to-use and standards-friendly method to embed Flash content, which utilizes one small JavaScript file.',
- 'vendor url' => 'http://code.google.com/p/swfobject',
- 'download url' => 'http://swfobject.googlecode.com/files/swfobject_2_2.zip',
+ 'vendor url' => 'https://github.com/swfobject/swfobject',
+ 'download url' => 'https://github.com/swfobject/swfobject/zipball/master',
'version arguments' => array(
- 'file' => 'swfobject.js',
+ 'file' => 'swfobject/swfobject.js',
'pattern' => '@v([0-9a-zA-Z\.-]+)@',
),
'files' => array(
'js' => array(
- 'swfobject.js' => array(
+ 'swfobject/swfobject.js' => array(
'type' => 'file',
'scope' => 'header',
'group' => JS_LIBRARY,
@@ -29,20 +29,23 @@ function media_recorder_libraries_info() {
),
),
);
- $libraries['recorder.js'] = array(
- 'name' => 'recorder.js',
- 'description' => 'JavaScript library to record audio in browsers as used in the SoundCloud Javascript SDK.',
- 'vendor url' => 'https://github.com/jwagener/recorder.js',
- 'download url' => 'https://github.com/jwagener/recorder.js/zipball/master',
- 'version arguments' => array(
- 'file' => 'recorder.js',
- 'pattern' => '@version: ([0-9a-zA-Z\.-]+),@',
- ),
+ $libraries['FlashWavRecorder'] = array(
+ 'name' => 'FlashWavRecorder',
+ 'description' => 'Simple flash file for recording audio and saving as a WAV.',
+ 'vendor url' => 'https://github.com/michalstocki/FlashWavRecorder',
+ 'download url' => 'https://github.com/michalstocki/FlashWavRecorder/zipball/master',
+ 'version' => '0.9.0',
'dependencies' => array(
'swfobject (>=2.2)',
),
'files' => array(
- 'js' => array('recorder.js'),
+ 'js' => array(
+ 'html/js/recorder.js' => array(
+ 'type' => 'file',
+ 'scope' => 'header',
+ 'group' => JS_LIBRARY,
+ ),
+ ),
),
);
$libraries['Recorderjs'] = array(
@@ -127,6 +130,7 @@ function media_recorder_help($path, $arg) {
$output = file_get_contents(drupal_get_path('module', 'media_recorder') . '/README.txt');
return nl2br($output);
}
+ return NULL;
}
/**
@@ -274,7 +278,8 @@ function media_recorder_record_stream_finish() {
}
// Sort files in case they are out of order.
- ksort($files, SORT_NATURAL);
+ $files = array_keys($files);
+ natsort($files);
// Open temp file.
try {
@@ -290,7 +295,7 @@ function media_recorder_record_stream_finish() {
}
// Iterate over file list and append to temp file.
- foreach (array_keys($files) as $filename) {
+ foreach ($files as $filename) {
// Get data from file.
try {
@@ -338,8 +343,10 @@ function media_recorder_record_stream_finish() {
// Change the file name and save as temporary managed file.
try {
- file_unmanaged_move($_SESSION['media_recorder']['tempnam'], $_SESSION['media_recorder']['tempnam'] . '.' . $_SESSION['media_recorder']['format']);
- $file = file_uri_to_object($_SESSION['media_recorder']['tempnam'] . '.' . $_SESSION['media_recorder']['format']);
+ $uri = $_SESSION['media_recorder']['tempnam'];
+ $extension = '.' . $_SESSION['media_recorder']['format'];
+ file_unmanaged_move($uri, $uri . $extension);
+ $file = file_uri_to_object($uri . $extension);
$file->status = 0;
file_save($file);
}
@@ -422,8 +429,9 @@ function media_recorder_record_file() {
// Change the file name and save as temporary managed file.
try {
- file_unmanaged_move($uri, $uri . '.wav');
- $file = file_uri_to_object($uri . '.wav');
+ $extension = '.wav';
+ file_unmanaged_move($uri, $uri . $extension);
+ $file = file_uri_to_object($uri . $extension);
$file->status = 0;
file_save($file);
}
@@ -433,9 +441,6 @@ function media_recorder_record_file() {
return;
}
- // Close session.
- unset($_SESSION['media_recorder']);
-
// Return file information.
drupal_json_output($file);
}
@@ -455,7 +460,7 @@ function media_recorder_media_browser_plugin_info() {
/**
* Provides a form for adding media items using the media recorder.
*/
-function media_recorder_add($form, &$form_state) {
+function media_recorder_add($form, &$form_state, $types = array(), $multiselect = FALSE) {
// Set field variables.
$field_name = 'field_media_recorder';
@@ -479,6 +484,11 @@ function media_recorder_add($form, &$form_state) {
'settings' => array(
'progress_indicator' => 'throbber',
'time_limit' => variable_get('media_recorder_time_limit', 300),
+ 'constraints' => variable_get('media_recorder_constraints', array(
+ 'audio' => TRUE,
+ 'video' => TRUE,
+ 'video_resolution' => 320,
+ )),
),
),
);
@@ -512,8 +522,10 @@ function media_recorder_add($form, &$form_state) {
$key = array_search('file_field_widget_process', $form[$field_name][$langcode][0]['#process']);
unset($form[$field_name][$langcode][0]['#process'][$key]);
- // Add media browser javascript and CSS.
- drupal_add_js(drupal_get_path('module', 'media_recorder') . '/js/media-recorder.browser.js');
+ // Add javascript if this is the media browser.
+ if ($types) {
+ drupal_add_js(drupal_get_path('module', 'media_recorder') . '/js/media-recorder.browser.js');
+ }
// Add a submit button.
$form['actions']['submit']['#type'] = 'submit';
@@ -534,7 +546,7 @@ function media_recorder_add_submit($form, &$form_state) {
$file->status = FILE_STATUS_PERMANENT;
$file = file_save($file);
}
- drupal_set_message(t('The file <em>!filename</em> was successfully loaded.', array('!filename' => l(check_plain($file->filename), 'file/' . $file->fid))), 'status');
+ drupal_set_message(t('The file <em>!filename</em> was successfully saved.', array('!filename' => l(check_plain($file->filename), 'file/' . $file->fid))), 'status');
}
else {
drupal_set_message(t('An unrecoverable error occurred. Try reloading the page and submitting again.'), 'error');
@@ -552,6 +564,12 @@ function media_recorder_field_widget_info() {
'settings' => array(
'progress_indicator' => 'throbber',
'allowed_schemes' => array('public', 'private'),
+ 'time_limit' => 300,
+ 'constraints' => array(
+ 'audio' => TRUE,
+ 'video' => TRUE,
+ 'video_resolution' => 320,
+ ),
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
@@ -575,10 +593,37 @@ function media_recorder_field_widget_settings_form($field, $instance) {
'#type' => 'textfield',
'#title' => t('Time Limit'),
'#description' => t('Time limit in seconds. Defaults to 300 seconds (5 minutes).'),
- '#default_value' => isset($settings['time_limit']) ? $settings['time_limit'] : 300,
+ '#default_value' => $settings['time_limit'],
'#element_validate' => array('element_validate_integer_positive'),
'#required' => TRUE,
);
+ $form['constraints'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Media Constraints'),
+ '#description' => t('Select which recording options will be available.'),
+ );
+ $form['constraints']['audio'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Audio'),
+ '#default_value' => $settings['constraints']['audio'],
+ );
+ $form['constraints']['video'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Video'),
+ '#default_value' => $settings['constraints']['video'],
+ );
+ $form['constraints']['video_resolution'] = array(
+ '#type' => 'radios',
+ '#title' => t('Video Resolution'),
+ '#default_value' => $settings['constraints']['video_resolution'],
+ '#options' => array(
+ 640 => t('640 x 480'),
+ 480 => t('480 x 360'),
+ 320 => t('320 x 240'),
+ 240 => t('240 x 180'),
+ 180 => t('180 x 135'),
+ ),
+ );
return $form;
}
@@ -606,15 +651,13 @@ function media_recorder_field_widget_form(&$form, &$form_state, $field, $instanc
*/
function media_recorder_field_widget_form_process($element, &$form_state, $form) {
- // Alter file elements.
- $element['fid']['#attributes']['class'][] = 'media-recorder-fid';
- $element['upload']['#attributes']['class'][] = 'media-recorder-upload';
- $element['upload_button']['#attributes']['class'][] = 'media-recorder-upload-button';
- $element['remove_button']['#attributes']['class'][] = 'media-recorder-remove-button';
- $element['remove_button']['#weight'] = 100;
-
- // Add validation handler to beginning of validation handler stack.
- array_unshift($element['#element_validate'], 'media_recorder_field_widget_form_process_record_validate');
+ // Get current file if it exists.
+ $fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : (isset($form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['fid']) ? $form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['fid'] : 0);
+ $file = NULL;
+ if ($fid) {
+ $file = file_load($fid);
+ $file->url = file_create_url($file->uri);
+ }
// Add media recorder.
$element['record'] = array(
@@ -622,99 +665,77 @@ function media_recorder_field_widget_form_process($element, &$form_state, $form)
'#title' => 'Record',
);
- // Add hidden refresh submit, which is triggered on record finish.
- // This will rebuild the form with new file preview.
- $element['refresh'] = array(
- '#type' => 'submit',
- '#executes_submit_callback' => FALSE,
- '#limit_validation_errors' => array(),
- '#value' => t('Refresh'),
- '#ajax' => array(
- 'callback' => 'media_recorder_field_widget_form_process_ajax_refresh',
- 'wrapper' => $element['#id'] . '-file-preview-ajax-wrapper',
- ),
- '#attributes' => array(
- 'style' => 'display: none;',
- 'class' => array('media-recorder-refresh'),
- ),
+ // Add libraries.
+ $element['#attached']['libraries_load'] = array(
+ array('swfobject'),
+ array('FlashWavRecorder'),
+ array('Recorderjs'),
);
- // Add file preview to render array.
- $element['preview'] = array(
- '#type' => 'container',
- '#weight' => 50,
- '#attributes' => array(
- 'class' => array('media-recorder-file-preview'),
+ // Add custom js.
+ $element['#attached']['js'] = array(
+ array(
+ 'type' => 'file',
+ 'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder-api.js',
+ 'scope' => 'footer',
),
- '#id' => $element['#id'] . '-file-preview-ajax-wrapper',
- );
-
- // Only display file if fid exists.
- $fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : (isset($form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['fid']) ? $form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['fid'] : 0);
- if ($fid) {
- $file = file_load($fid);
- $element['preview']['file'] = file_view($file);
- $element['preview']['#type'] = 'fieldset';
- $element['preview']['#title'] = 'File Preview';
- }
-
- // Add attached files and settings.
- $element['#attached'] = array(
- 'libraries_load' => array(
- array('swfobject'),
+ array(
+ 'type' => 'file',
+ 'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder-html5.js',
+ 'scope' => 'footer',
),
- 'js' => array(
- array(
- 'type' => 'file',
- 'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder.js',
- 'scope' => 'footer',
- ),
- array(
- 'type' => 'setting',
- 'data' => array(
- 'mediaRecorder' => array(
- 'swfurl' => libraries_get_path('recorder.js'),
- 'html5url' => libraries_get_path('Recorderjs'),
- 'modulePath' => drupal_get_path('module', 'media_recorder') . '/js',
- 'settings' => $element['#settings'],
- ),
+ array(
+ 'type' => 'file',
+ 'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder-flash.js',
+ 'scope' => 'footer',
+ ),
+ array(
+ 'type' => 'file',
+ 'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder.js',
+ 'scope' => 'footer',
+ ),
+ array(
+ 'type' => 'setting',
+ 'data' => array(
+ 'mediaRecorder' => array(
+ 'settings' => $element['#settings'],
+ 'flashurl' => libraries_get_path('FlashWavRecorder'),
+ 'html5url' => libraries_get_path('Recorderjs'),
+ 'file' => $file,
),
- 'scope' => 'header',
),
+ 'scope' => 'header',
),
- 'css' => array(
+ );
+
+ // Add custom css.
+ if (variable_get('media_recorder_css', TRUE)) {
+ $element['#attached']['css'] = array(
array(
'type' => 'file',
'data' => drupal_get_path('module', 'media_recorder') . '/css/media-recorder.css',
),
- ),
- );
-
- return $element;
-}
-
-/**
- * Ajax callback for form element rebuild.
- * @see media_recorder_field_widget_form_process()
- */
-function media_recorder_field_widget_form_process_ajax_refresh($form, &$form_state) {
+ );
+ }
- // Rebuild the form.
- $form_state['rebuild'] = TRUE;
+ // Alter file elements.
+ $element['fid']['#attributes']['class'][] = 'media-recorder-fid';
+ $element['upload']['#attributes']['class'][] = 'media-recorder-upload';
+ $element['upload_button']['#attributes']['class'][] = 'media-recorder-upload-button';
+ $element['remove_button']['#attributes']['class'][] = 'media-recorder-remove-button';
+ $element['remove_button']['#weight'] = 100;
- // Get the file field element.
- $parents = $form_state['triggering_element']['#array_parents'];
- array_pop($parents);
- $element = drupal_array_get_nested_value($form, $parents);
+ // Add validation handler to beginning of validation handler stack.
+ array_unshift($element['#element_validate'], 'media_recorder_field_widget_form_process_validate');
- return $element['preview'];
+ return $element;
}
/**
* Custom validation callback.
* @see media_recorder_field_widget_form_process()
*/
-function media_recorder_field_widget_form_process_record_validate(&$element, &$form_state) {
+function media_recorder_field_widget_form_process_validate(&$element, &$form_state, $form) {
// Get field information.
$field_name = $element['#parents'][0];
diff --git a/theme/media-recorder.tpl.php b/theme/media-recorder.tpl.php
index 2dbc3e4..f8331a8 100644
--- a/theme/media-recorder.tpl.php
+++ b/theme/media-recorder.tpl.php
@@ -6,21 +6,29 @@
*
* @see template_preprocess()
* @see template_process()
+ *
+ * Important: Do not change any classes for elements. Media Recorder uses
+ * these to bind recorder functionality. Adding classes will not affect this.
*/
?>
<div class="media-recorder-wrapper">
<div class="media-recorder">
- <div class="media-recorder-constraints">
- <button class="media-recorder-enable-audio" title="Click to enable audio recorder.">Audio</button>
- <button class="media-recorder-enable-video" title="Click to enable video recorder.">Video</button>
+ <div class="media-recorder-preview">
+ <video class="media-recorder-video"></video>
+ <canvas class="media-recorder-meter"></canvas>
+ <audio class="media-recorder-audio" controls></audio>
</div>
- <div class="media-recorder-preview"></div>
<div class="media-recorder-status"></div>
<div class="media-recorder-controls">
+ <button class="media-recorder-enable" title="Click to enable your mic & camera.">Start</button>
<button class="media-recorder-record" title="Click to start recording.">Record</button>
<button class="media-recorder-stop" title="Click to stop recording.">Stop</button>
+ <button class="media-recorder-play" title="Click to play recording.">Play</button>
+ <button class="media-recorder-settings" title="Click to access settings.">Settings</button>
+ <button class="media-recorder-enable-audio" title="Click to enable your mic.">Audio</button>
+ <button class="media-recorder-enable-video" title="Click to enable your camera.">Video</button>
</div>
</div>
</div>