diff --git a/includes/media_recorder.admin.inc b/includes/media_recorder.admin.inc
index 918993f7e054d61b7495582e9e840e0f74db584a..a442026f9648329c169e28e96925b5f7a94ab21f 100644
--- a/includes/media_recorder.admin.inc
+++ b/includes/media_recorder.admin.inc
@@ -98,5 +98,210 @@ function media_recorder_admin_form($form, $form_state) {
);
}
+ // Media: Kaltura integration.
+ if (module_exists('media_kaltura')) {
+
+ // Load existing servers and add to options array.
+ $rows = array();
+ $options = array();
+ $servers = entity_load('media_kaltura_server');
+ foreach ($servers as $server) {
+ $rows[$server->id] = array(
+ 'domain' => $server->domain,
+ 'force_ssl' => $server->force_ssl ? 'Yes' : 'No',
+ 'api' => $server->api ? 'Enabled' : 'Disabled',
+ 'partner_id' => $server->partner_id,
+ 'subpartner_id' => $server->subpartner_id,
+ 'user_id' => $server->user_id,
+ 'secret' => $server->secret,
+ 'uiconf_id' => $server->uiconf_id,
+ 'operations' => l(t('edit'), 'admin/config/media/media_kaltura/server/' . $server->id),
+ );
+ $options[$server->id] = $server->domain;
+ }
+
+ // Entry creation settings.
+ $form['media_recorder']['kaltura'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Media: Kaltura Integration'),
+ 'enable' => array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable Media: Kaltura integration?'),
+ '#description' => t('Recordings will be sent directly to the specified Kaltura server rather than local storage.'),
+ '#default_value' => $settings['kaltura']['enable'],
+ ),
+ 'server' => array(
+ '#type' => 'select',
+ '#title' => t('Default server to upload files to?'),
+ '#description' => t('Files will be automatically uploaded to the selected Kaltura server.'),
+ '#default_value' => $settings['kaltura']['server'],
+ '#options' => $options,
+ '#states' => array(
+ 'disabled' => array(
+ ':input[name="media_recorder[kaltura][enable]"]' => array('checked' => FALSE),
+ ),
+ ),
+ ),
+ );
+
+ // Server specific options.
+ if ($settings['kaltura']['enable'] && isset($settings['kaltura']['server'])) {
+
+ // Attempt to start a Kaltura session.
+ try {
+ $server = media_kaltura_server_load($settings['kaltura']['server']);
+ if (!$server) {
+ throw new Exception('Unable to load Kaltura server.');
+ }
+ $kaltura = media_kaltura_start_session($server);
+ if (!$kaltura) {
+ throw new Exception('Unable to start Kaltura session.');
+ }
+
+ // Get existing kRecord widgets for this server.
+ $filter = new KalturaUiConfFilter(array(
+ 'objTypeEqual' => 7,
+ ));
+ $result = $kaltura['client']->uiConf->listAction($filter);
+ $recorders = array();
+ foreach ($result->objects as $object) {
+ if ($object->swfUrlVersion >= '1.7') {
+ $recorders[$object->id] = $object->name;
+ }
+ }
+
+ // Recorder Kaltura recorder widget.
+ if (count($recorders)) {
+ $form['media_recorder']['kaltura']['recorder'] = array(
+ '#type' => 'select',
+ '#title' => t('Select a Recorder Widget (Flash Fallback)'),
+ '#description' => t('The kRecord widget must be version 1.7.2 or higher. Please note that these widgets are not normally available in the KMC and must be created through the Kaltura Client API.'),
+ '#options' => $recorders,
+ '#default_value' => isset($settings['kaltura']['recorder']) ? $settings['kaltura']['recorder'] : '',
+ '#disabled' => !$settings['kaltura']['server'],
+ '#states' => array(
+ 'disabled' => array(
+ ':input[name="media_recorder[kaltura][enable]"]' => array('checked' => FALSE),
+ ),
+ ),
+ );
+ }
+ else {
+ $form['media_recorder']['kaltura']['markup'] = array(
+ '#markup' => '
No compatible recorders found, would you like to create one?
',
+ );
+ $form['media_recorder']['kaltura']['create'] = array(
+ '#type' => 'submit',
+ '#value' => 'Create a Recorder Widget',
+ '#submit' => array('media_recorder_admin_form_create_recorder_widget_submit'),
+ );
+ }
+
+ // Default transcoding profile.
+ $filter = new KalturaConversionProfileFilter();
+ $results = $kaltura['client']->conversionProfile->listAction($filter);
+ $profiles = array('-- No Default --');
+ foreach ($results->objects as $result) {
+ $profiles[$result->id] = $result->name;
+ }
+ $form['media_recorder']['kaltura']['profile'] = array(
+ '#type' => 'select',
+ '#title' => t('Select a Default Transcoding Profile'),
+ '#description' => t('All new media entries will automatically be transcoded using this transcoding profile.'),
+ '#options' => $profiles,
+ '#default_value' => isset($settings['kaltura']['profile']) ? $settings['kaltura']['profile'] : 0,
+ '#states' => array(
+ 'disabled' => array(
+ ':input[name="media_recorder[kaltura][enable]"]' => array('checked' => FALSE),
+ ),
+ ),
+ );
+
+ // Default category.
+ $filter = new KalturaCategoryFilter();
+ $results = $kaltura['client']->category->listAction($filter);
+ $categories = array('-- No Default --');
+ foreach ($results->objects as $result) {
+ $categories[$result->id] = $result->fullName;
+ }
+ $form['media_recorder']['kaltura']['category'] = array(
+ '#type' => 'select',
+ '#title' => t('Select a Default Category'),
+ '#description' => t('All new media entries will be placed within this default category.'),
+ '#options' => $categories,
+ '#default_value' => isset($settings['kaltura']['category']) ? $settings['kaltura']['category'] : 0,
+ '#states' => array(
+ 'disabled' => array(
+ ':input[name="media_recorder[kaltura][enable]"]' => array('checked' => FALSE),
+ ),
+ ),
+ );
+ }
+ catch (Exception $e) {
+ watchdog('media_kaltura', 'There was a problem connecting to the kaltura server: @error', array('@error' => $e->getMessage()), WATCHDOG_ERROR);
+ }
+ }
+ }
+
return system_settings_form($form);
}
+
+/**
+ * Validate handler for media_recorder_admin_form().
+ */
+function media_recorder_admin_form_validate($form, &$form_state) {
+ if ($form_state['values']['media_recorder']['kaltura']['enable']) {
+ $server = media_kaltura_server_load($form_state['values']['media_recorder']['kaltura']['server']);
+ if (!$server) {
+ form_set_error('media_recorder][kaltura][enable', t('Unable to load server. Please check that your server information is correct.'));
+ }
+ $kaltura = media_kaltura_start_session($server);
+ if (!$kaltura) {
+ form_set_error('media_recorder][kaltura][enable', t('Unable to connect to server. Please check that your server information is correct.'));
+ }
+ }
+}
+
+/**
+ * Submit callback for creating a Kaltura recorder widget.
+ *
+ * @see media_recorder_admin_form()
+ */
+function media_recorder_admin_form_create_recorder_widget_submit($form, &$form_state) {
+ $settings = media_recorder_get_settings();
+
+ // Attempt to start a Kaltura session.
+ try {
+ $server = media_kaltura_server_load($settings['kaltura']['server']);
+ if (!$server) {
+ throw new Exception('Unable to load Kaltura server.');
+ }
+ $kaltura = media_kaltura_start_session($server);
+ if (!$kaltura) {
+ throw new Exception('Unable to start Kaltura session.');
+ }
+ }
+ catch (Exception $e) {
+ watchdog('media_kaltura', 'There was a problem connecting to the kaltura server: @error', array('@error' => $e->getMessage()), WATCHDOG_ERROR);
+ }
+
+ // Create a new kRecord widget.
+ $uiConf = new KalturaUiConf();
+ $uiConf->name = 'Media Recorder: kRecord Widget';
+ $uiConf->objType = 7;
+ $uiConf->width = 400;
+ $uiConf->height = 300;
+ $uiConf->swfUrl = '/flash/krecord/v1.7.2/KRecord.swf';
+ $uiConf->swfUrlVersion = '1.7.2';
+ $uiConf->confFile = '';
+ $uiConf->creationMode = 3;
+ $result = $kaltura['client']->uiConf->add($uiConf);
+
+ // Add widget to settings.
+ if ($result && isset($result->id)) {
+ $settings = media_recorder_get_settings();
+ $settings['kaltura']['recorder'] = $result->id;
+ variable_set('media_recorder', $settings);
+ drupal_set_message(t('kRecord widget successfully created.'));
+ }
+}
diff --git a/js/media-recorder-api-kaltura.js b/js/media-recorder-api-kaltura.js
new file mode 100644
index 0000000000000000000000000000000000000000..070f879ff383fc038f99b6b7e8a5da386913e3ff
--- /dev/null
+++ b/js/media-recorder-api-kaltura.js
@@ -0,0 +1,633 @@
+/**
+ * @file
+ * Provides an interface for the MediaRecorder API.
+ */
+
+(function ($) {
+ 'use strict';
+
+ Drupal.MediaRecorder = function (id, conf) {
+ var settings = conf;
+ var origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
+
+ var $element = $('#' + id);
+ var $inputFid = $('#' + id + '-fid');
+ var $statusWrapper = $element.find('.media-recorder-status');
+ var $previewWrapper = $element.find('.media-recorder-preview');
+ var $progressWrapper = $element.find('.media-recorder-progress');
+ var $video = $element.find('.media-recorder-video');
+ var $audio = $element.find('.media-recorder-audio');
+ var $meter = $element.find('.media-recorder-meter');
+ var $startButton = $element.find('.media-recorder-enable');
+ var $recordButton = $element.find('.media-recorder-record');
+ var $stopButton = $element.find('.media-recorder-stop');
+ var $playButton = $element.find('.media-recorder-play');
+ var $settingsButton = $element.find('.media-recorder-settings');
+ var $videoButton = $element.find('.media-recorder-enable-video');
+ var $audioButton = $element.find('.media-recorder-enable-audio');
+
+ var recording = false;
+ 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 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 blobCount = 0;
+ var blobSize = 0;
+ var statusInterval = null;
+ var constraints = {};
+
+ // 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();
+ $progressWrapper.hide();
+
+ // Set constraints.
+ 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 (conf.file) {
+ var file = conf.file;
+ switch (file.type) {
+ case 'video':
+ $previewWrapper.show();
+ $video.show();
+ $audio.hide();
+ $video[0].src = file.url;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ break;
+ case 'audio':
+ $previewWrapper.show();
+ $audio.show();
+ $video.hide();
+ $audio[0].src = file.url;
+ $audio[0].muted = '';
+ $audio[0].controls = 'controls';
+ $audio[0].load();
+ break;
+ }
+ }
+
+ initializeButtons();
+ initializeEvents();
+ setStatus('Click \'Start\' to enable your mic & camera.');
+
+ /**
+ * Set status message.
+ */
+ function setStatus(message) {
+ $element.trigger('status', message);
+ }
+
+ /**
+ * Create volume meter canvas element that uses getUserMedia stream.
+ */
+ function createVolumeMeter() {
+
+ // 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;
+ }
+
+ 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');
+ }
+
+ 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);
+ };
+ }
+
+ /**
+ * Create audio visualizer canvas element that uses getUserMedia stream.
+ */
+ function createAudioVisualizer() {
+
+ // 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;
+ }
+
+ 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');
+ }
+
+ 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(20);
+ }
+ 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();
+ }
+ }
+
+ /**
+ * 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();
+
+ if (constraints.video) {
+ createVolumeMeter();
+ }
+ else {
+ createAudioVisualizer();
+ }
+
+ 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.");
+ }
+ );
+ }
+
+ /**
+ * 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?');
+ }
+ }
+
+ /**
+ * Stop recording and trigger stopped event.
+ */
+ function stop() {
+ recorder.stop();
+ $element.trigger('recordStop');
+ }
+
+ /**
+ * Start recording and trigger recording event.
+ */
+ function record() {
+ var promises = [];
+ blobs = [];
+ blobCount = 0;
+ blobSize = 0;
+
+ // Send blob chunk to server when ondataavailable is triggered.
+ recorder.ondataavailable = function (e) {
+ var blob = new Blob([e.data], {type: e.data.type || mimetype});
+
+ if (blob.size > 1) {
+ var resume = (blobs.length === 0) ? false : true;
+
+ // Send data to server.
+ promises.push(new Promise(function (resolve, reject) {
+
+ // Build form data.
+ var formData = new FormData();
+ formData.append('service', 'uploadToken');
+ formData.append('action', 'upload');
+ formData.append('format', 1);
+ formData.append('ks', conf.kaltura.ks);
+ formData.append('uploadTokenId', conf.kaltura.token.id);
+ formData.append('resume', resume);
+ formData.append('finalChunk', 0);
+ formData.append('resumeAt', blobSize);
+ formData.append('fileData', blob, conf.kaltura.token.fileName);
+
+ // Create new XHR request.
+ var request = new XMLHttpRequest();
+ request.responseType = 'json';
+ request.open('POST', conf.kaltura.apiUrl, true);
+ request.onload = function (evt) {
+ if (evt.currentTarget.status === 200) {
+ if (evt.currentTarget.response.id) {
+ resolve(evt.currentTarget.response);
+ }
+ else {
+ reject(Error(evt.currentTarget.statusText));
+ }
+ }
+ else {
+ reject(Error(evt.currentTarget.statusText));
+ }
+ };
+ request.onerror = function (evt) {
+ reject(Error("Error fetching data."));
+ };
+
+ // Send request.
+ request.send(formData);
+
+ // Add this blob to blob totals.
+ blobCount++;
+ blobs.push(blob);
+ blobSize = blobSize + blob.size;
+ }));
+ }
+ };
+
+ // Notify server that recording has stopped when onstop is triggered.
+ recorder.onstop = function (e) {
+ Promise.all(promises).then(function (data) {
+ var blob = new Blob();
+ var formData = new FormData();
+ formData.append('service', 'uploadToken');
+ formData.append('action', 'upload');
+ formData.append('format', 1);
+ formData.append('ks', conf.kaltura.ks);
+ formData.append('uploadTokenId', conf.kaltura.token.id);
+ formData.append('resume', true);
+ formData.append('finalChunk', true);
+ formData.append('resumeAt', blobSize);
+ formData.append('fileData', blob, conf.kaltura.token.fileName);
+ var request = new XMLHttpRequest();
+ request.responseType = 'json';
+ request.open('POST', conf.kaltura.apiUrl, true);
+ request.onload = function (evt, data) {
+ var uploadTokenId = evt.currentTarget.response.id;
+ var xhr = new XMLHttpRequest();
+ var formData = new FormData();
+ formData.append('uploadTokenId', uploadTokenId);
+ formData.append('mimetype', mimetype);
+ xhr.open('POST', origin + Drupal.settings.basePath + 'media_recorder/record/kaltura/token', true);
+ xhr.onload = function (evt) {
+ var file = JSON.parse(xhr.response);
+ $element.trigger('refreshData', file);
+ };
+ xhr.onerror = function (evt) {
+ alert('There was an issue saving your recording, please try again.');
+ };
+ xhr.send(formData);
+ };
+ request.onerror = function (evt) {
+ alert('There was an issue saving your recording, please try again.');
+ };
+ request.send(formData);
+ }).catch(function (error) {
+ alert('There was an issue saving your recording, please try again.');
+ });
+ };
+
+ // Notify Kaltura server upload has started.
+ var formData = new FormData();
+ formData.append('ks', conf.kaltura.ks);
+ formData.append('service', 'uploadToken');
+ formData.append('action', 'add');
+ formData.append('format', 1);
+ formData.append('uploadToken:fileName', new Date().getTime().toString() + '.' + format);
+ formData.append('uploadToken:fileSize', -1);
+ var request = new XMLHttpRequest();
+ request.responseType = 'json';
+ request.open('POST', conf.kaltura.apiUrl, true);
+ request.onload = function (evt) {
+ if (request.status === 200 && request.response !== null) {
+ conf.kaltura.token = request.response;
+ recorder.start(3000);
+ $element.trigger('recordStart');
+ }
+ else {
+ alert('There was an issue starting your recording, please try again.');
+ }
+ };
+ request.onerror = function (evt) {
+ alert('There was an issue starting your recording, please try again.');
+ };
+ request.send(formData);
+ }
+
+ /**
+ * Initialize all control buttons.
+ */
+ function initializeButtons() {
+
+ // 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();
+ });
+
+ }
+
+ /**
+ * Initialize recorder.
+ */
+ function initializeEvents() {
+
+ // Stop page unload if there is a recording in process.
+ window.onbeforeunload = function () {
+ if (recording) {
+ return 'You are still in the process of recording, are you sure you want to leave this page?';
+ }
+ else {
+ return null;
+ }
+ };
+
+ // 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));
+
+ recording = true;
+ recordingPreview();
+ setStatus('Recording 00:00 (Time Limit: ' + timeLimitFormatted + ')');
+
+ $progressWrapper.show();
+ var $progress = $progressWrapper.children('.progress-bar');
+ $progress.css({
+ width: '0%'
+ });
+
+ currentSeconds = 0;
+ statusInterval = setInterval(function () {
+ currentSeconds = currentSeconds + 1;
+ var currentMilliSeconds = new Date(currentSeconds * 1000);
+ var time = millisecondsToTime(currentMilliSeconds);
+ var timePercentage = currentSeconds / settings.time_limit * 100;
+
+ $progress.css({
+ width: timePercentage + '%'
+ });
+
+ setStatus('Recording ' + time + ' (Time Limit: ' + timeLimitFormatted + ')');
+
+ if (currentSeconds >= settings.time_limit) {
+ stop();
+ }
+ }, 1000);
+ });
+
+ // Listen for the stop event.
+ $element.bind('recordStop', function (event) {
+ clearInterval(statusInterval);
+ $progressWrapper.hide();
+ setStatus('Please wait while the recording finishes uploading...');
+ });
+
+ // Append file object data.
+ $element.bind('refreshData', function (event, data) {
+ recording = false;
+ $inputFid.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;
+ }
+ };
+})(jQuery);
diff --git a/js/media-recorder-flash-kaltura.js b/js/media-recorder-flash-kaltura.js
new file mode 100644
index 0000000000000000000000000000000000000000..7aa066bc4f381b9108866473b821a5cfb722d85d
--- /dev/null
+++ b/js/media-recorder-flash-kaltura.js
@@ -0,0 +1,485 @@
+/**
+ * @file
+ * Provides an interface for the FWRecorder library.
+ */
+
+(function ($) {
+ 'use strict';
+
+ Drupal.kRecord = {};
+ Drupal.MediaRecorderFlash = function (id, conf) {
+ var settings = conf;
+ var origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
+
+ var $element = $('#' + id);
+ var $inputFid = $('#' + id + '-fid');
+ var $statusWrapper = $element.find('.media-recorder-status');
+ var $previewWrapper = $element.find('.media-recorder-preview');
+ var $progressWrapper = $element.find('.media-recorder-progress');
+ var $video = $element.find('.media-recorder-video');
+ var $audio = $element.find('.media-recorder-audio');
+ var $meter = $element.find('.media-recorder-meter');
+ var $startButton = $element.find('.media-recorder-enable');
+ var $recordButton = $element.find('.media-recorder-record');
+ var $stopButton = $element.find('.media-recorder-stop');
+ var $playButton = $element.find('.media-recorder-play');
+ var $settingsButton = $element.find('.media-recorder-settings');
+ var $videoButton = $element.find('.media-recorder-enable-video');
+ var $audioButton = $element.find('.media-recorder-enable-audio');
+
+ var recording = false;
+ var statusInterval = null;
+ var meterInterval = null;
+ var constraints = {};
+
+ // Initial state.
+ $recordButton[0].disabled = false;
+ $recordButton.hide();
+ $stopButton.hide();
+ $playButton.hide();
+ $settingsButton.hide();
+ $video.hide();
+ $audio.hide();
+ $meter.height(20);
+ $meter.hide();
+ $videoButton.hide();
+ $audioButton.hide();
+ $previewWrapper.hide();
+ $progressWrapper.hide();
+
+ // Set constraints. Video/Audio is forced for now.
+ // TODO: Add audio only support if this gets resolved: https://github.com/kaltura/krecord/issues/2
+ settings.constraints.audio = false;
+ settings.constraints.video = true;
+ settings.constraints.video_resolution = settings.constraints.video_resolution || 640;
+ constraints.audio = false;
+ 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 (conf.file) {
+ var file = conf.file;
+ switch (file.type) {
+ case 'video':
+ $previewWrapper.show();
+ $video.show();
+ $audio.hide();
+ $video[0].src = file.url;
+ $video[0].muted = '';
+ $video[0].controls = 'controls';
+ $video[0].load();
+ break;
+ case 'audio':
+ $previewWrapper.show();
+ $audio.show();
+ $video.hide();
+ $audio[0].src = file.url;
+ $audio[0].muted = '';
+ $audio[0].controls = 'controls';
+ $audio[0].load();
+ break;
+ }
+ }
+
+ /**
+ * Set status message.
+ */
+ function setStatus(message) {
+ $element.trigger('status', message);
+ }
+
+ /**
+ * Updates the volume meter.
+ */
+ function updateVolumeMeter() {
+ var level = kRecorder.getMicrophoneActivityLevel();
+ $meter.width(level + '%');
+ if (level <= 70) {
+ $meter.css({
+ 'background': 'green'
+ });
+ }
+ else if (level > 70 && level < 85) {
+ $meter.css({
+ 'background': 'yellow'
+ });
+ }
+ else if (level >= 85) {
+ $meter.css({
+ 'background': 'red'
+ });
+ }
+ }
+
+ /**
+ * Toggle to recording preview.
+ */
+ function playbackPreview(uploadedEntryId, preview) {
+ var kapi = new kWidget.api({'wid': '_' + settings.kaltura.partnerID});
+ function checkEntryStatus() {
+ setStatus('Recording is being processed, but you may save anytime.');
+ kapi.doRequest({
+ 'service': 'media',
+ 'action': 'get',
+ 'entryId': uploadedEntryId,
+ 'cache_st': Math.floor(Math.random() * 10000)
+ },
+ function (data) {
+ if (data.status === 2) {
+ $previewWrapper.append(preview);
+ setStatus('Entry has finished processing.');
+ }
+ else {
+ setTimeout(checkEntryStatus, 5000);
+ }
+ });
+ }
+ checkEntryStatus();
+ }
+
+ /**
+ * Start user media stream.
+ */
+ function startStream() {
+ $previewWrapper.prepend('Your browser must have JavaScript enabled and the Adobe Flash Player installed.
');
+ $previewWrapper.show();
+
+ swfobject.embedSWF(
+ 'https://' + conf.kaltura.flashVars.host + '/krecord/ui_conf_id/' + conf.kaltura.recorderUI + '/',
+ 'krecorder',
+ $element.width(),
+ $element.width() * 0.75,
+ '9.0.0',
+ 'expressInstall.swf',
+ conf.kaltura.flashVars,
+ {
+ allowScriptAccess: 'always',
+ allowNetworking: 'all',
+ wmode: 'window',
+ bgcolor: '000000'
+ },
+ {
+ id: "krecorder",
+ name: "kRecorder"
+ }
+ );
+
+ setStatus('Please allow access to your camera and mic.');
+ }
+
+ /**
+ * 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?');
+ }
+ }
+
+ /**
+ * Start recording and trigger recording event.
+ */
+ function showSettings() {
+ var microphones = kRecorder.getMicrophones().split(',');
+ var cameras = kRecorder.getCameras().split(',');
+ var activeCamera = kRecorder.getActiveCamera();
+ var activeMicrophone = kRecorder.getActiveMicrophone();
+ var msg = $statusWrapper.text();
+
+ setStatus('');
+
+ var $settings = $('');
+
+ // Add the camera dropdown.
+ var $camera = $('');
+ var $cameraLabel = $('');
+ var $cameraSelect = $('');
+ cameras.forEach(function (camera) {
+ var selected = (activeCamera === camera) ? ' selected="selected"' : '';
+ $cameraSelect.append('');
+ });
+ $camera.append($cameraLabel).append($cameraSelect);
+
+ // Add the microphone dropdown.
+ var $microphone = $('');
+ var $microphoneLabel = $('');
+ var $microphoneSelect = $('');
+ microphones.forEach(function (microphone) {
+ var selected = (activeMicrophone === microphone) ? ' selected="selected"' : '';
+ $microphoneSelect.append('');
+ });
+ $microphone.append($microphoneLabel).append($microphoneSelect);
+
+ var $doneButton = $('');
+
+ $cameraSelect.change(function () {
+ var camera = $(this).val();
+ kRecorder.setActiveCamera(camera);
+ });
+
+ $microphoneSelect.change(function () {
+ var microphone = $(this).val();
+ kRecorder.setActiveMicrophone(microphone);
+ });
+
+ $doneButton.bind('click', function (event) {
+ event.preventDefault();
+ $settingsButton[0].disabled = false;
+ $statusWrapper.html('');
+ setStatus(msg);
+ });
+
+ $settings.append($camera).append($microphone).append($doneButton);
+ $statusWrapper.append($settings);
+ }
+
+ /**
+ * Initialize all control buttons.
+ */
+ function initializeButtons() {
+
+ // Click handler for enable audio button.
+ $startButton.bind('click', function (event) {
+ event.preventDefault();
+ $startButton.hide();
+ start();
+ });
+
+ // Click handler for settings button.
+ $settingsButton.bind('click', function (event) {
+ event.preventDefault();
+ $settingsButton[0].disabled = true;
+ showSettings();
+ });
+
+ // Click handler for to change to video.
+ $videoButton.bind('click', function (event) {
+ event.preventDefault();
+ $videoButton.hide();
+ $audioButton.hide();
+ startStream();
+ });
+
+ // Click handler for to change to audio.
+ $audioButton.bind('click', function (event) {
+ event.preventDefault();
+ $videoButton.hide();
+ $audioButton.hide();
+ constraints = {
+ audio: true,
+ video: false
+ };
+ startStream();
+ });
+ }
+
+ /**
+ * Initialize recorder.
+ */
+ function initializeEvents() {
+
+ // Stop page unload if there is a recording in process.
+ window.onbeforeunload = function () {
+ if (recording) {
+ return 'You are still in the process of recording, are you sure you want to leave this page?';
+ }
+ else {
+ return null;
+ }
+ };
+
+ // 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));
+
+ recording = true;
+ setStatus('Recording 00:00 (Time Limit: ' + timeLimitFormatted + ')');
+
+ $progressWrapper.show();
+ var $progress = $progressWrapper.children('.progress-bar');
+ $progress.css({
+ width: '0%'
+ });
+
+ currentSeconds = 0;
+ statusInterval = setInterval(function () {
+ currentSeconds = currentSeconds + 1;
+ var currentMilliSeconds = new Date(currentSeconds * 1000);
+ var time = millisecondsToTime(currentMilliSeconds);
+ var timePercentage = currentSeconds / settings.time_limit * 100;
+
+ $progress.css({
+ width: timePercentage + '%'
+ });
+
+ setStatus('Recording ' + time + ' (Time Limit: ' + timeLimitFormatted + ')');
+
+ if (currentSeconds >= settings.time_limit) {
+ stop();
+ }
+ }, 1000);
+
+ $meter.show();
+ meterInterval = setInterval(updateVolumeMeter, 100);
+ });
+
+ // Listen for the stop event.
+ $element.bind('recordStop', function (event) {
+ clearInterval(statusInterval);
+ $progressWrapper.hide();
+ clearInterval(meterInterval);
+ $meter.hide();
+ setStatus('Press save to upload recording.');
+ });
+
+ // Append file object data.
+ $element.bind('refreshData', function (event, data) {
+ recording = false;
+ $inputFid.val(data.file.fid);
+ playbackPreview(data.entry.id, data.preview);
+ swfobject.removeSWF('krecorder');
+ setStatus('Recording saved successfully.');
+ });
+
+ $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;
+ }
+
+ Drupal.kRecord.microphoneDenied = function () {
+ alert('Unable to access microphone, please make sure you have allowed access in the dialog..');
+ };
+
+ Drupal.kRecord.noMicsFound = function () {
+ alert('No microphones found, please make sure you have a microphone attached.');
+ };
+
+ Drupal.kRecord.cameraDenied = function () {
+ alert('Unable to access camera, please make sure you have allowed access in the dialog..');
+ };
+
+ Drupal.kRecord.noCamerasFound = function () {
+ alert('No cameras found, please make sure you have a camera attached.');
+ };
+
+ Drupal.kRecord.recordStart = function () {
+ $element.trigger('recordStart');
+ };
+
+ Drupal.kRecord.recordComplete = function () {
+ $element.trigger('recordStop');
+ };
+
+ Drupal.kRecord.previewStarted = function () {
+ $element.trigger('previewStarted');
+ };
+
+ Drupal.kRecord.previewEnd = function () {
+ $element.trigger('previewEnd');
+ };
+
+ Drupal.kRecord.netconnectionConnectFailed = function () {
+ alert('Unable to connect to the Kaltura server.');
+ };
+
+ Drupal.kRecord.netconnectionConnectRejected = function () {
+ alert('Connection to the Kaltura server refused.');
+ };
+
+ Drupal.kRecord.connected = function () {
+ kRecorder.setQuality(100, 0, constraints.video.width, constraints.video.height, constraints.video.frameRate.ideal, constraints.video.frameRate.ideal, 70);
+ $settingsButton.show();
+ setStatus('Press record to start recording.');
+ };
+
+ Drupal.kRecord.addEntryFailed = function (errorObj) {
+ console.log(errorObj);
+ };
+
+ Drupal.kRecord.addEntryComplete = function (addedEntries) {
+ var xhr = new XMLHttpRequest();
+ var formData = new FormData();
+ formData.append('entries', JSON.stringify(addedEntries));
+ xhr.open('POST', origin + Drupal.settings.basePath + 'media_recorder/record/kaltura/entry', true);
+ xhr.onload = function (evt) {
+ $element.trigger('refreshData', JSON.parse(xhr.response));
+ };
+ xhr.onerror = function (evt) {
+ alert('There was an issue saving your recording, please try again.');
+ };
+ xhr.send(formData);
+ };
+
+ initializeButtons();
+ initializeEvents();
+ setStatus('Click \'Start\' to enable your mic & camera.');
+ };
+})(jQuery);
diff --git a/js/media-recorder.js b/js/media-recorder.js
index 29a76bd298aa92077de3729303015d0460048cf4..fa420aca100357ebb20a9f01fb9f8408f7c5351c 100644
--- a/js/media-recorder.js
+++ b/js/media-recorder.js
@@ -45,17 +45,24 @@
switch (recorderType) {
case 'MediaRecorder':
$mediaRecorder.show();
- $mediaRecorderFallback.hide();
+ $mediaRecorderFallback.remove();
new Drupal.MediaRecorder(info.id, info.conf);
break;
case 'MediaRecorderHTML5':
$mediaRecorder.show();
- $mediaRecorderFallback.hide();
- new Drupal.MediaRecorderHTML5(info.id, info.conf);
+ $mediaRecorderFallback.remove();
+ // Use the kaltura video recorder if kaltura is enabled, rather
+ // than the HTML5 audio only Recorder.js library.
+ if (info.conf.kaltura) {
+ new Drupal.MediaRecorderFlash(info.id, info.conf);
+ }
+ else {
+ new Drupal.MediaRecorderHTML5(info.id, info.conf);
+ }
break;
case 'MediaRecorderFlash':
$mediaRecorder.show();
- $mediaRecorderFallback.hide();
+ $mediaRecorderFallback.remove();
new Drupal.MediaRecorderFlash(info.id, info.conf);
break;
default:
diff --git a/media_recorder.module b/media_recorder.module
index 770f8cf22ea838ec8cb3d835a34e000426cecb28..9faa9dfd402d9f2f677f1378f89cd7543b485deb 100644
--- a/media_recorder.module
+++ b/media_recorder.module
@@ -85,6 +85,22 @@ function media_recorder_menu() {
'access arguments' => array('create'),
'type' => MENU_CALLBACK,
);
+ $items['media_recorder/record/kaltura/token'] = array(
+ 'title' => 'Record',
+ 'description' => 'Add a Kaltura recording from an upload token (html5).',
+ 'page callback' => 'media_recorder_record_kaltura_token',
+ 'access callback' => 'file_entity_access',
+ 'access arguments' => array('create'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items['media_recorder/record/kaltura/entry'] = array(
+ 'title' => 'Record',
+ 'description' => 'Add a Kaltura recording from an existing entry (flash).',
+ 'page callback' => 'media_recorder_record_kaltura_entry',
+ 'access callback' => 'file_entity_access',
+ 'access arguments' => array('create'),
+ 'type' => MENU_CALLBACK,
+ );
$items['media_recorder/record/stream/start'] = array(
'title' => 'Record',
'description' => 'Record a video or audio file as a stream.',
@@ -159,11 +175,13 @@ function media_recorder_get_settings() {
'css' => TRUE,
'time_limit' => 300,
'allowed_extensions' => 'wav mp3 m4a ogg oga weba wma mov mp4 wmv m4v mpeg avi ogv webp webm',
- 'upload_directory' => 300,
+ 'upload_directory' => '',
'kaltura' => array(
'enable' => FALSE,
'server' => 0,
'recorder' => 0,
+ 'profile' => 0,
+ 'category' => 0,
),
));
}
@@ -491,6 +509,182 @@ function media_recorder_record_file() {
drupal_json_output($file);
}
+/**
+ * Menu callback for saving a Kaltura recording from an upload token.
+ *
+ * This will create a new media entry and file. However it will not trigger the
+ * media_kaltura module's hook_file_insert since this is not a local file, thus
+ * we handle all creation logic here.
+ */
+function media_recorder_record_kaltura_token() {
+ $settings = media_recorder_get_settings();
+
+ // Validate that a upload location was sent.
+ if (!isset($_POST['uploadTokenId']) || empty($_POST['uploadTokenId'])) {
+ header('HTTP/1.0 419 Custom Error');
+ drupal_json_output('Missing configuration.');
+ return;
+ }
+
+ // Validate that a upload location was sent.
+ if (!isset($_POST['mimetype']) || empty($_POST['mimetype'])) {
+ header('HTTP/1.0 419 Custom Error');
+ drupal_json_output('Missing configuration.');
+ return;
+ }
+
+ // Check that Kaltura upload has been enabled.
+ if (!isset($settings['kaltura']['enable']) || !$settings['kaltura']['enable'] || !isset($settings['kaltura']['server']) || !$settings['kaltura']['server']) {
+ return;
+ }
+
+ // Attempt to start a Kaltura session.
+ try {
+
+ // Load the default Kaltura server.
+ $server = media_kaltura_server_load($settings['kaltura']['server']);
+ if (!$server) {
+ throw new Exception('Unable to load Kaltura server.');
+ }
+
+ // Start a new session with the Kaltura server.
+ $kaltura = media_kaltura_start_session($server);
+ if (!$kaltura) {
+ throw new Exception('Unable to start Kaltura session.');
+ }
+ }
+ catch (Exception $e) {
+ watchdog('media_kaltura', 'There was a problem connecting to the kaltura server: @error', array('@error' => $e->getMessage()), WATCHDOG_ERROR);
+ }
+
+ // Add a Kaltura media entry from the upload token.
+ try {
+ $token = $kaltura['client']->uploadToken->get($_POST['uploadTokenId']);
+ $type = substr($_POST['mimetype'], 0, strpos($_POST['mimetype'], '/'));
+
+ // Create a new media entry and set values.
+ $entry = new KalturaMediaEntry();
+ $entry->name = $token->fileName;
+ $entry->mediaType = ($type === 'audio') ? KalturaMediaType::AUDIO : KalturaMediaType::VIDEO;
+
+ // Set default profile if enabled.
+ if (isset($settings['kaltura']['profile']) && $settings['kaltura']['profile']) {
+ $entry->conversionProfileId = $settings['kaltura']['profile'];
+ }
+
+ // Set default category if enabled.
+ if (isset($settings['kaltura']['category']) && $settings['kaltura']['category']) {
+ $entry->categoriesIds = $settings['kaltura']['category'];
+ }
+
+ // Allow other modules to alter media entry object before operation.
+ drupal_alter('media_kaltura_entry', $entry, NULL, $kaltura['client']);
+
+ // Upload the file and create a new Kaltura media entry.
+ $entry = $kaltura['client']->media->addFromUploadedFile($entry, $token->id);
+
+ // Create a new file.
+ if ($entry) {
+ $file = file_uri_to_object('kaltura://' . $server->domain . '/' . $server->partner_id . '/' . $server->subpartner_id . '/' . $server->uiconf_id . '/' . $entry->id);
+ $file->type = $type;
+ $file->filemime = $type . '/kaltura';
+ $file->status = 0;
+ $file->filesize = 0;
+ file_save($file);
+ }
+
+ // Allow modules to act on entry create or update operation.
+ module_invoke_all('media_kaltura_entry', $entry, $file, $kaltura['client']);
+ }
+ catch (Exception $e) {
+ header('HTTP/1.0 419 Custom Error');
+ drupal_json_output($e->getMessage());
+ return;
+ }
+
+ // Return file information.
+ drupal_json_output($file);
+}
+
+/**
+ * Menu callback for saving a Kaltura recording from a media entry.
+ */
+function media_recorder_record_kaltura_entry() {
+ $settings = media_recorder_get_settings();
+
+ // Validate that a upload location was sent.
+ if (!isset($_POST['entries']) || empty($_POST['entries'])) {
+ header('HTTP/1.0 419 Custom Error');
+ drupal_json_output('Missing configuration.');
+ return;
+ }
+
+ // Check that Kaltura upload has been enabled.
+ if (!isset($settings['kaltura']['enable']) || !$settings['kaltura']['enable'] || !isset($settings['kaltura']['server']) || !$settings['kaltura']['server']) {
+ return;
+ }
+
+ // Attempt to start a Kaltura session.
+ try {
+
+ // Load the default Kaltura server.
+ $server = media_kaltura_server_load($settings['kaltura']['server']);
+ if (!$server) {
+ throw new Exception('Unable to load Kaltura server.');
+ }
+
+ // Start a new session with the Kaltura server.
+ $kaltura = media_kaltura_start_session($server);
+ if (!$kaltura) {
+ throw new Exception('Unable to start Kaltura session.');
+ }
+ }
+ catch (Exception $e) {
+ watchdog('media_kaltura', 'There was a problem connecting to the kaltura server: @error', array('@error' => $e->getMessage()), WATCHDOG_ERROR);
+ }
+
+ // Add a Kaltura media entry from the upload token.
+ try {
+ $entries = json_decode($_POST['entries']);
+
+ foreach ($entries as $entry) {
+
+ // Save the entry with a default category if this is enabled.
+ if ($settings['kaltura']['category']) {
+ $categoryEntry = new KalturaCategoryEntry();
+ $categoryEntry->categoryId = $settings['kaltura']['category'];
+ $categoryEntry->entryId = $entry->id;
+ $kaltura['client']->categoryEntry->add($categoryEntry);
+ }
+
+ // Create a new file associated with this entry.
+ if ($entry) {
+ $file = file_uri_to_object('kaltura://' . $server->domain . '/' . $server->partner_id . '/' . $server->subpartner_id . '/' . $server->uiconf_id . '/' . $entry->id);
+ $file->type = ($entry->type == 1 ? 'video' : 'audio');
+ $file->filemime = $file->type . '/kaltura';
+ $file->status = 0;
+ $file->filesize = 0;
+ file_save($file);
+ }
+ }
+ }
+ catch (Exception $e) {
+ header('HTTP/1.0 419 Custom Error');
+ drupal_json_output($e->getMessage());
+ return;
+ }
+
+ // Return file information.
+ $file_view = file_view($file);
+ unset($file_view['links']);
+ unset($file_view['#contextual_links']);
+ drupal_json_output(array(
+ 'file' => $file,
+ 'entry' => $entry,
+ 'preview' => drupal_render($file_view),
+ ));
+}
+
/**
* Implements hook_media_browser_plugin_info().
*/
@@ -540,7 +734,7 @@ function media_recorder_element_process($element, &$form_state, $form) {
$settings = media_recorder_get_settings();
$fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : 0;
$file = NULL;
- $id = uniqid('media-recorder-');
+ $id = $element['#id'];
// If the element as a default file, add the absolute url to the file.
if (!empty($fid) && $file = file_load($fid)) {
@@ -586,22 +780,22 @@ function media_recorder_element_process($element, &$form_state, $form) {
array('Recorderjs'),
),
'js' => array(
- array(
+ 'media-recorder-api' => array(
'type' => 'file',
'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder-api.js',
'scope' => 'footer',
),
- array(
+ 'media-recorder-html5' => array(
'type' => 'file',
'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder-html5.js',
'scope' => 'footer',
),
- array(
+ 'media-recorder-flash' => array(
'type' => 'file',
'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder-flash.js',
'scope' => 'footer',
),
- array(
+ 'media-recorder' => array(
'type' => 'file',
'data' => drupal_get_path('module', 'media_recorder') . '/js/media-recorder.js',
'scope' => 'footer',
@@ -640,6 +834,78 @@ function media_recorder_element_process($element, &$form_state, $form) {
);
}
+ // Add Media: Kaltura support if enabled.
+ if (module_exists('media_kaltura') && $settings['kaltura']['enable'] && $settings['kaltura']['server'] && $settings['kaltura']['recorder']) {
+
+ // Attempt to start a Kaltura session.
+ try {
+ $server = media_kaltura_server_load($settings['kaltura']['server']);
+ $kaltura = media_kaltura_start_session($server);
+
+ // Override fallback with kaltura upload.
+ $element['fallback'] = array(
+ '#type' => 'media_kaltura_upload',
+ '#required' => TRUE,
+ '#multiple' => FALSE,
+ '#cardinality' => 1,
+ '#extensions' => explode(' ', $element['#upload_validators']['file_validate_extensions'][0]),
+ '#api_url' => $server->api_url,
+ '#ks' => $kaltura['session'],
+ '#default_value' => array(
+ array(
+ 'fid' => $fid,
+ ),
+ ),
+ '#attributes' => array(
+ 'class' => array(
+ 'media-recorder-fallback',
+ ),
+ ),
+ );
+
+ // Add Kaltura related javascript.
+ unset($element['#attached']['js']['media-recorder-html5']);
+ $element['#attached']['js']['media-recorder-api']['data'] = drupal_get_path('module', 'media_recorder') . '/js/media-recorder-api-kaltura.js';
+ $element['#attached']['js']['media-recorder-flash']['data'] = drupal_get_path('module', 'media_recorder') . '/js/media-recorder-flash-kaltura.js';
+ $element['#attached']['js']['kwidget'] = array(
+ 'type' => 'file',
+ 'data' => '//' . $server->domain . '/p/' . $server->partner_id . '/sp/' . $server->subpartner_id . '/embedIframeJs/uiconf_id/' . $server->uiconf_id . '/partner_id/' . $server->partner_id,
+ 'scope' => 'footer',
+ 'external' => TRUE,
+ );
+ $element['#attached']['js'][0]['data']['mediaRecorder']['elements'][0]['conf']['kaltura'] = array(
+ 'ks' => $kaltura['session'],
+ 'partnerID' => $server->partner_id,
+ 'apiUrl' => $server->api_url,
+ 'playerUI' => $server->uiconf_id,
+ 'recorderUI' => $settings['kaltura']['recorder'],
+ 'flashVars' => array(
+ 'pid' => $server->partner_id,
+ 'ks' => $kaltura['session'],
+ 'isH264' => TRUE,
+ 'h264profile' => 'main',
+ 'h264level' => 3,
+ 'showUI' => TRUE,
+ 'autoPreview' => FALSE,
+ 'showPreviewTimer' => TRUE,
+ 'removePlayer' => FALSE,
+ 'disableglobalclick' => FALSE,
+ 'limitRecord' => $element['#time_limit'],
+ 'showErrorMessage' => TRUE,
+ 'themeURL' => '//' . $server->domain . '/p/' . $server->partner_id . '/sp/0/flash/krecord/v1.7.2/skin.swf',
+ 'localeURL' => '//' . $server->domain . '/p/' . $server->partner_id . '/sp/0/flash/krecord/v1.7.2/locale.xml',
+ 'host' => $server->domain,
+ 'delegate' => 'Drupal.kRecord',
+ 'debugMode' => TRUE,
+ 'conversionQuality' => $settings['kaltura']['profile'],
+ ),
+ );
+ }
+ catch (Exception $e) {
+ watchdog('media_kaltura', 'There was a problem connecting to the kaltura server: @error', array('@error' => $e->getMessage()), WATCHDOG_ERROR);
+ }
+ }
+
return $element;
}
@@ -675,12 +941,15 @@ function media_recorder_element_value(&$element, $input = FALSE, $form_state = N
}
}
// Load file if the FID has changed to confirm it exists.
- if (isset($input['fid']) && $file = file_load($input['fid'])) {
+ if (isset($input['fallback'][0]['fid']) && $file = file_load($input['fallback'][0]['fid'])) {
$fid = $file->fid;
}
elseif (isset($input['fallback']['fid']) && $file = file_load($input['fallback']['fid'])) {
$fid = $file->fid;
}
+ elseif (isset($input['fid']) && $file = file_load($input['fid'])) {
+ $fid = $file->fid;
+ }
}
// If there is no input, set the default value.
@@ -719,9 +988,14 @@ function media_recorder_element_validate(&$element, &$form_state) {
}
if (!empty($fid) && $file = file_load($fid)) {
- $file_validate_errors = file_validate($file, $element['#upload_validators']);
- if ($file_validate_errors) {
- form_error($element, implode('
', $file_validate_errors));
+ $scheme = file_uri_scheme($file->uri);
+
+ // Validate local files.
+ if ($scheme === 'public' || $scheme === 'private') {
+ $file_validate_errors = file_validate($file, $element['#upload_validators']);
+ if ($file_validate_errors) {
+ form_error($element, implode('
', $file_validate_errors));
+ }
}
}
}