381 lines
13 KiB
JavaScript
381 lines
13 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;
|
|
|
|
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(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 {
|
|
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) {
|
|
|
|
if(_playbackMonitorMode === undefined || _playbackMonitorMode === null) {
|
|
playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE;
|
|
}
|
|
else {
|
|
playbackMonitorMode = _playbackMonitorMode;
|
|
}
|
|
|
|
logger.debug("playbackControl.startMonitor " + playbackMonitorMode + "")
|
|
|
|
styleControls();
|
|
monitorRecordingPlayback();
|
|
}
|
|
|
|
function stopMonitor() {
|
|
logger.debug("playbackControl.stopMonitor")
|
|
if(monitorPlaybackTimeout!= null) {
|
|
clearTimeout(monitorPlaybackTimeout);
|
|
monitorPlaybackTimeout = null;
|
|
}
|
|
}
|
|
|
|
|
|
this.update = update;
|
|
this.setPlaybackMode = setPlaybackMode;
|
|
this.startMonitor = startMonitor;
|
|
this.stopMonitor = stopMonitor;
|
|
|
|
return this;
|
|
}
|
|
})(window, jQuery); |