/** * 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);