/** * Playback widget (play, pause , etc) */ (function (context, $) { // this check ensures we attempt to listen if this component is created in a popup var reactContext = window.opener ? window.opener : window // make sure this is actually us opening the window, not someone else (by checking for MixerStore) if (window.opener) { try { m = window.opener.MixerStore } catch (e) { reactContext = window } } var BrowserMediaStore = reactContext.BrowserMediaStore "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, mediaActions: null}, 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 disabled = false; 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); } if (options.mediaActions) { options.mediaActions.mediaStartPlay.trigger({playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode}) } else { $self.triggerHandler('play', {playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode}); } if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) { context.JK.GA.trackJamTrackPlaySession(context.SessionStore.id(), true) } } function stopPlay(endReached) { logger.debug("STOP PLAY CLICKED") updateIsPlaying(false); if (options.mediaActions) { logger.debug("mediaStopPlay", endReached) options.mediaActions.mediaStopPlay({ playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode, endReached: endReached }) } else { $self.triggerHandler('stop', { playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode, endReached: endReached }); } } function pausePlay(endReached) { updateIsPlaying(false); if (options.mediaActions) { options.mediaActions.mediaPausePlay({ playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode, endReached: endReached }) } else { $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) { if (options.mediaActions) { options.mediaActions.mediaChangePosition({ positionMs: playbackPositionMs, playbackMonitorMode: playbackMonitorMode }) } else { $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); updateSliderPosition(playbackPositionMs); //if(playingWhenDragStart) { // playingWhenDragStart = false; // startPlay(); //} } function onDrag(e, ui) { updateOffsetBasedOnPosition(ui.position.left); } $playButton.on('click', function (e) { if (disabled) { logger.debug("PlaybackControls are disabled; ignoring start button") return; } startPlay(); return false; }); $pauseButton.on('click', function (e) { pausePlay(); return false; }); $stopButton.on('click', function (e) { 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() { try { $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 if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.BROWSER_MEDIA) { $parentElement.addClass('mediafile-mode'); } else { throw "unknown playbackMonitorMode: " + playbackMonitorMode; } } catch (e) { logger.error("playbackControls: unable to style controls", e) } } function executeMonitor(positionMs, durationMs, isPlaying) { 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) } } if (setTimeout) { monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500); } } function monitorRecordingPlayback() { if (!monitoring) { return; } if (options.mediaActions) { options.mediaActions.positionUpdate(playbackMonitorMode) } else { if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) { var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs(); var duration = context.jamClient.SessionGetJamTracksPlayDurationMs(); var durationMs = duration.media_len; var isPlaying = context.jamClient.isSessionTrackPlaying(); } else if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.BROWSER_MEDIA) { var positionMs = BrowserMediaStore.onGetPlayPosition() || 0 var durationMs = BrowserMediaStore.onGetPlayDuration() || 0; var isPlaying = BrowserMediaStore.playing; } else { var positionMs = context.jamClient.SessionCurrrentPlayPosMs(); var durationMs = context.jamClient.SessionGetTracksPlayDurationMs(); var isPlaying = context.jamClient.isSessionTrackPlaying(); } executeMonitor(positionMs, durationMs, isPlaying) } } 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) { try { if (timeMs != playbackDurationMs) { $duration.text(context.JK.prettyPrintSeconds(parseInt(timeMs / 1000))); playbackDurationMs = timeMs; durationChanged = true; } } catch (e) { logger.error("playbackControls: updateDurationTime error", e) } } function updateCurrentTimeText(timeMs) { try { var time = context.JK.prettyPrintSeconds(parseInt(timeMs / 1000)) $currentTime.text(time); if (options.mediaActions) { options.mediaActions.currentTimeChanged(time) } } catch (e) { logger.error("playbackControls: updateCurrentTimeText error", e) } } function updateSliderPosition(timeMs) { try { var slideWidthPx = $sliderBar.width(); var xPos = Math.ceil(timeMs / playbackDurationMs * slideWidthPx); $slider.css('left', xPos); } catch (e) { logger.error("playbackControls: updateSliderPosition error", e) } } function updateCurrentTime(timeMs) { try { if (timeMs != playbackPositionMs || durationChanged) { updateCurrentTimeText(timeMs); updateSliderPosition(timeMs); playbackPositionMs = timeMs; } } catch (e) { logger.error("playbackControls: updateCurrentTime err", e) } } function updateIsPlaying(isPlaying) { try { if (isPlaying != playbackPlaying) { if (isPlaying) { $playButton.hide(); $pauseButton.show(); } else { $playButton.show(); $pauseButton.hide(); } logger.debug("updating is playing: " + isPlaying) playbackPlaying = isPlaying; } } catch (e) { logger.error("playbackControls: updateIsPlaying error", e) } } 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) { logger.debug("startMonitor: " + _playbackMonitorMode) if (monitoring && _playbackMonitorMode == playbackMonitorMode) { return; } 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(); if (monitorPlaybackTimeout != null) { clearTimeout(monitorPlaybackTimeout); monitorPlaybackTimeout = null; } 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; } function setDisabled(_disabled) { disabled = _disabled; } this.update = update; this.setPlaybackMode = setPlaybackMode; this.startMonitor = startMonitor; this.stopMonitor = stopMonitor; this.executeMonitor = executeMonitor; this.onPlayStopEvent = onPlayStopEvent; this.onPlayStartEvent = onPlayStartEvent; this.onPlayPauseEvent = onPlayPauseEvent; this.setDisabled = setDisabled; return this; } })(window, jQuery);