jam-cloud/web/app/assets/javascripts/playbackControls.js

415 lines
14 KiB
JavaScript

/**
* Playback widget (play, pause , etc)
*/
(function(context, $) {
"use strict";
var PlaybackMode = {
NoPlayback: 0,
EveryWhere: 1,
PrivatePreview: 2,
PreviewToAll: 3,
LastPbMode: 4
};
context.JK = context.JK || {};
context.JK.PlaybackControls = function($parentElement, options){
options = $.extend(false, {playmodeControlsVisible:false}, options);
var logger = context.JK.logger;
if($parentElement.length == 0) {
logger.debug("no $parentElement specified in PlaybackControls");
}
var PLAYBACK_MONITOR_MODE = context.JK.PLAYBACK_MONITOR_MODE;
var $playButton = $('.play-button img.playbutton', $parentElement);
var $pauseButton = $('.play-button img.pausebutton', $parentElement);
var $stopButton = $('.stop-button img.stopbutton', $parentElement);
var $currentTime = $('.recording-current', $parentElement);
var $duration = $('.duration-time', $parentElement);
var $sliderBar = $('.recording-playback', $parentElement);
var $slider = $('.recording-slider', $parentElement);
var $playmodeButton = $('.playback-mode-buttons.icheckbuttons input', $parentElement);
var $jamTrackGetReady = $('.jam-track-get-ready', $parentElement);
var $self = $(this);
var playbackPlaying = false;
var playbackDurationMs = 0;
var playbackPositionMs = 0;
var durationChanged = false;
var seenActivity = false;
var endReached = false;
var dragging = false;
var playingWhenDragStart = false;
var draggingUpdateTimer = null;
var canUpdateBackend = false;
var playbackMode = PlaybackMode.EveryWhere;
var monitorPlaybackTimeout = null;
var playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE;
var monitoring = false;
function init() {
updateSliderPosition(0);
updateDurationTime(0);
updateCurrentTime(0);
seenActivity = false;
}
function startPlay() {
seenActivity = false;
updateIsPlaying(true);
if(endReached) {
update(0, playbackDurationMs, playbackPlaying);
}
$self.triggerHandler('play', {playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode});
if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
var sessionModel = context.JK.CurrentSessionModel || null;
context.JK.GA.trackJamTrackPlaySession(sessionModel.id(), true)
}
}
function stopPlay(endReached) {
updateIsPlaying(false);
$self.triggerHandler('stop', {playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode, endReached : endReached});
}
function pausePlay(endReached) {
updateIsPlaying(false);
$self.triggerHandler('pause', {playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode, endReached : endReached});
}
function updateOffsetBasedOnPosition(offsetLeft) {
var sliderBarWidth = $sliderBar.width();
playbackPositionMs = parseInt((offsetLeft / sliderBarWidth) * playbackDurationMs);
updateCurrentTimeText(playbackPositionMs);
if(canUpdateBackend) {
$self.triggerHandler('change-position', {positionMs: playbackPositionMs, playbackMonitorMode: playbackMonitorMode});
canUpdateBackend = false;
}
}
function startDrag(e, ui) {
dragging = true;
playingWhenDragStart = playbackPlaying;
draggingUpdateTimer = setInterval(function() { canUpdateBackend = true; }, 333); // only call backend up to 3 times a second while dragging
if(playingWhenDragStart) {
stopPlay();
}
}
function stopDrag(e, ui) {
dragging = false;
clearInterval(draggingUpdateTimer);
canUpdateBackend = true;
updateOffsetBasedOnPosition(ui.position.left);
if(playingWhenDragStart) {
playingWhenDragStart = false;
startPlay();
}
}
function onDrag(e, ui) {
updateOffsetBasedOnPosition(ui.position.left);
}
$playButton.on('click', function(e) {
var sessionModel = context.JK.CurrentSessionModel || null;
//if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
// context.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $playButton})
// return false;
//}
startPlay();
return false;
});
$pauseButton.on('click', function(e) {
var sessionModel = context.JK.CurrentSessionModel || null;
//if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
// context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton})
// return false;
//}
pausePlay();
return false;
});
$stopButton.on('click', function(e) {
var sessionModel = context.JK.CurrentSessionModel || null;
//if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
// context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton})
// return false;
//}
stopPlay();
return false;
});
$sliderBar.on('click', function(e) {
var offset = e.pageX - $(this).offset().left;
canUpdateBackend = true;
updateOffsetBasedOnPosition(offset);
updateSliderPosition(playbackPositionMs);
return false;
});
$slider.draggable({
axis: 'x',
containment: $sliderBar,
start: startDrag,
stop: stopDrag,
drag: onDrag
});
if(options.playmodeControlsVisible) {
$('.playback-mode-buttons.icheckbuttons', $parentElement).show();
}
$playmodeButton.iCheck({
checkboxClass: 'icheckbox_minimal',
radioClass: 'iradio_minimal',
inheritClass: true
});
$playmodeButton.on('ifChecked', function(e) {
var playmode = $(this).val();
logger.debug("set new playmode", playmode);
setPlaybackMode(playmode);
});
function styleControls() {
$jamTrackGetReady.attr('data-mode', playbackMonitorMode);
$parentElement.removeClass('mediafile-mode jamtrack-mode metronome-mode');
if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.MEDIA_FILE) {
$parentElement.addClass('mediafile-mode');
}
else if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
$parentElement.addClass('jamtrack-mode');
}
else if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.METRONOME) {
$parentElement.addClass('metronome-mode');
}
else
{
throw "unknown playbackMonitorMode: " + playbackMonitorMode;
}
}
function monitorRecordingPlayback() {
if(!monitoring) {
return;
}
if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs();
var duration = context.jamClient.SessionGetJamTracksPlayDurationMs();
var durationMs = duration.media_len;
var start = duration.start; // needed to understand start offset, and prevent slider from moving in tapins
}
else {
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
}
var isPlaying = context.jamClient.isSessionTrackPlaying();
if(positionMs < 0) {
// bug in backend?
positionMs = 0;
}
if(positionMs > 0) {
seenActivity = true;
}
if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.METRONOME) {
updateIsPlaying(isPlaying);
}
else {
update(positionMs, durationMs, isPlaying);
}
if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
if(playbackPlaying) {
$jamTrackGetReady.attr('data-current-time', positionMs)
}
else {
// this is so the jamtrack 'Get Ready!' stays hidden when it's not playing
$jamTrackGetReady.attr('data-current-time', -1)
}
}
monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
}
function update(currentTimeMs, durationTimeMs, isPlaying, offsetStart) {
if(dragging) {
return;
}
// at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to
//logger.debug("currentTimeMs, durationTimeMs, mode", currentTimeMs, durationTimeMs, playbackMonitorMode);
if(currentTimeMs == 0 && seenActivity) {
if(playbackPlaying) {
isPlaying = false;
durationTimeMs = playbackDurationMs;
currentTimeMs = playbackDurationMs;
stopPlay(true);
endReached = true;
logger.debug("end reached");
}
else {
// make sure slide shows '0'
updateCurrentTime(currentTimeMs);
return;
}
}
if(currentTimeMs < offsetStart) {
currentTimeMs = 0; // this is to squelch movement during tap-in period
}
updateDurationTime(durationTimeMs);
updateCurrentTime(currentTimeMs);
updateIsPlaying(isPlaying);
durationChanged = false;
}
function updateDurationTime(timeMs) {
if(timeMs != playbackDurationMs) {
$duration.text(context.JK.prettyPrintSeconds(parseInt(timeMs / 1000)));
playbackDurationMs = timeMs;
durationChanged = true;
}
}
function updateCurrentTimeText(timeMs) {
$currentTime.text(context.JK.prettyPrintSeconds(parseInt(timeMs / 1000)));
}
function updateSliderPosition(timeMs) {
var slideWidthPx = $sliderBar.width();
var xPos = Math.ceil(timeMs / playbackDurationMs * slideWidthPx);
$slider.css('left', xPos);
}
function updateCurrentTime(timeMs) {
if(timeMs != playbackPositionMs || durationChanged) {
updateCurrentTimeText(timeMs);
updateSliderPosition(timeMs);
playbackPositionMs = timeMs;
}
}
function updateIsPlaying(isPlaying) {
if(isPlaying != playbackPlaying) {
if(isPlaying) {
$playButton.hide();
$pauseButton.show();
}
else {
$playButton.show();
$pauseButton.hide();
}
logger.debug("updating is playing: " + isPlaying)
playbackPlaying = isPlaying;
}
}
function setPlaybackMode(mode) {
if(mode == 'preview-to-all') {
playbackMode = PlaybackMode.PreviewToAll;
}
else if(mode == 'preview-to-me') {
playbackMode = PlaybackMode.PrivatePreview;
}
else if(mode == 'eveywhere') {
playbackMode = PlaybackMode.EveryWhere;
}
else {
logger.error("unable to set playback mode", mode);
}
// let the mode change immediately affect the behavior of the stream
if(playbackPlaying) {
stopPlay();
startPlay();
}
}
function startMonitor(_playbackMonitorMode) {
monitoring = true;
// resets everything to zero
init();
if(_playbackMonitorMode === undefined || _playbackMonitorMode === null) {
playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE;
}
else {
playbackMonitorMode = _playbackMonitorMode;
}
logger.debug("playbackControl.startMonitor " + playbackMonitorMode + "")
styleControls();
monitorRecordingPlayback();
}
function stopMonitor() {
monitoring = false;
logger.debug("playbackControl.stopMonitor")
if(monitorPlaybackTimeout!= null) {
clearTimeout(monitorPlaybackTimeout);
monitorPlaybackTimeout = null;
}
}
function onPlayStartEvent() {
updateIsPlaying(true);
playbackPlaying = true;
seenActivity = false;
}
function onPlayStopEvent() {
updateIsPlaying(false);
playbackPlaying = false;
}
function onPlayPauseEvent() {
playbackPlaying = false;
}
this.update = update;
this.setPlaybackMode = setPlaybackMode;
this.startMonitor = startMonitor;
this.stopMonitor = stopMonitor;
this.onPlayStopEvent = onPlayStopEvent;
this.onPlayStartEvent = onPlayStartEvent;
this.onPlayPauseEvent = onPlayPauseEvent;
return this;
}
})(window, jQuery);