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

304 lines
9.9 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 $playButton = $('.play-button img.playbutton', $parentElement);
var $pauseButton = $('.play-button img.pausebutton', $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 $self = $(this);
var playbackPlaying = false;
var playbackDurationMs = 0;
var playbackPositionMs = 0;
var durationChanged = false;
var endReached = false;
var dragging = false;
var playingWhenDragStart = false;
var draggingUpdateTimer = null;
var canUpdateBackend = false;
var playbackMode = PlaybackMode.EveryWhere;
var monitorPlaybackTimeout = null;
var jamTrackMode = false; // if true, we use different APIs to determine playback info
function startPlay() {
updateIsPlaying(true);
if(endReached) {
update(0, playbackDurationMs, playbackPlaying);
}
$self.triggerHandler('play', {playbackMode: playbackMode});
}
function stopPlay() {
updateIsPlaying(false);
$self.triggerHandler('pause');
}
function updateOffsetBasedOnPosition(offsetLeft) {
var sliderBarWidth = $sliderBar.width();
playbackPositionMs = parseInt((offsetLeft / sliderBarWidth) * playbackDurationMs);
updateCurrentTimeText(playbackPositionMs);
if(canUpdateBackend) {
$self.triggerHandler('change-position', {positionMs: playbackPositionMs, jamTrackMode: jamTrackMode});
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;
}
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 monitorRecordingPlayback() {
if(jamTrackMode) {
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
//console.log("JamTrack start: " + start)
}
else {
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
}
var isPlaying = context.jamClient.isSessionTrackPlaying();
if(positionMs < 0) {
// bug in backend?
positionMs = 0;
}
update(positionMs, durationMs, isPlaying);
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", currentTimeMs, durationTimeMs);
if(currentTimeMs == 0 && durationTimeMs == 0) {
if(isPlaying) {
isPlaying = false;
durationTimeMs = playbackDurationMs;
currentTimeMs = playbackDurationMs;
stopPlay();
endReached = true;
logger.debug("end reached");
}
else {
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();
}
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(_jamTrackMode) {
jamTrackMode = !!_jamTrackMode;
monitorRecordingPlayback();
}
function stopMonitor() {
if(monitorPlaybackTimeout!= null) {
clearTimeout(monitorPlaybackTimeout);
monitorPlaybackTimeout = null;
}
}
this.update = update;
this.setPlaybackMode = setPlaybackMode;
this.startMonitor = startMonitor;
this.stopMonitor = stopMonitor;
return this;
}
})(window, jQuery);