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 + ''); + }); + $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 + ''); + }); + $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)); + } } } }