From 7c73e2ab5ca4579c8565cb45cbf264d27490d4e7 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 12 Mar 2015 21:53:23 -0500 Subject: [PATCH] * VRFS-2922 - show spinner for pending metronome --- db/manifest | 3 +- db/up/connection_metronome.sql | 1 + ruby/lib/jam_ruby/connection_manager.rb | 2 +- ruby/lib/jam_ruby/models/connection.rb | 1 + ruby/lib/jam_ruby/models/track.rb | 7 ++- ruby/spec/jam_ruby/models/track_spec.rb | 16 +++++++ web/app/assets/javascripts/session.js | 41 ++++++++++++---- web/app/assets/javascripts/sessionModel.js | 48 ++++++++++++++----- web/app/assets/javascripts/trackHelpers.js | 32 ++++++++++--- .../stylesheets/client/session.css.scss | 10 ++++ .../api_music_sessions_controller.rb | 2 +- web/app/views/api_music_sessions/show.rabl | 2 +- web/app/views/clients/_session.html.slim | 7 ++- web/lib/music_session_manager.rb | 4 +- 14 files changed, 143 insertions(+), 33 deletions(-) create mode 100644 db/up/connection_metronome.sql diff --git a/db/manifest b/db/manifest index 9cc4e1fac..267d3a46f 100755 --- a/db/manifest +++ b/db/manifest @@ -260,4 +260,5 @@ jam_track_jmep_data.sql add_jam_track_bitrates.sql jam_track_importer.sql jam_track_pro_licensing_update.sql -jam_track_redeemed.sql \ No newline at end of file +jam_track_redeemed.sql +connection_metronome.sql \ No newline at end of file diff --git a/db/up/connection_metronome.sql b/db/up/connection_metronome.sql new file mode 100644 index 000000000..78ed3219e --- /dev/null +++ b/db/up/connection_metronome.sql @@ -0,0 +1 @@ +ALTER TABLE connections ADD COLUMN metronome_open BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/connection_manager.rb b/ruby/lib/jam_ruby/connection_manager.rb index 3ab2f4a84..352048dc0 100644 --- a/ruby/lib/jam_ruby/connection_manager.rb +++ b/ruby/lib/jam_ruby/connection_manager.rb @@ -89,7 +89,7 @@ module JamRuby udp_reachable_value = udp_reachable.nil? ? 'udp_reachable' : udp_reachable sql =< "JamRuby::BackingTrack", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all has_many :video_sources, :class_name => "JamRuby::VideoSource", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all + validates :metronome_open, :inclusion => {:in => [true, false]} validates :as_musician, :inclusion => {:in => [true, false, nil]} validates :client_type, :inclusion => {:in => CLIENT_TYPES} validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true diff --git a/ruby/lib/jam_ruby/models/track.rb b/ruby/lib/jam_ruby/models/track.rb index c06ad2d7a..e430edb2d 100644 --- a/ruby/lib/jam_ruby/models/track.rb +++ b/ruby/lib/jam_ruby/models/track.rb @@ -109,7 +109,7 @@ module JamRuby # this is a bit different from a normal track synchronization in that the client just sends up all tracks, # ... some may already exist - def self.sync(clientId, tracks, backing_tracks = []) + def self.sync(clientId, tracks, backing_tracks = [], metronome_open = false) result = {} backing_tracks = [] unless backing_tracks @@ -117,6 +117,11 @@ module JamRuby Track.transaction do connection = Connection.find_by_client_id!(clientId) + # synchronize metronome_open on connection + if connection.metronome_open != metronome_open + Connection.where(:id => connection.id).update_all(:metronome_open => metronome_open) + end + # each time tracks are synced we have to update the entry in music_sessions_user_history msh = MusicSessionUserHistory.find_by_client_id!(clientId) instruments = [] diff --git a/ruby/spec/jam_ruby/models/track_spec.rb b/ruby/spec/jam_ruby/models/track_spec.rb index 4b27ad062..4db0f59a5 100644 --- a/ruby/spec/jam_ruby/models/track_spec.rb +++ b/ruby/spec/jam_ruby/models/track_spec.rb @@ -172,5 +172,21 @@ describe Track do expect(found.updated_at.to_i).to eq backing_track.updated_at.to_i end end + + describe "metronome_open" do + it "sets metronome_open to true" do + result = Track.sync(connection.client_id, [track_hash], [], true) + connection.reload + connection.metronome_open.should be_true + end + + it "sets metronome_open to false" do + connection.metronome_open = true + connection.save! + result = Track.sync(connection.client_id, [track_hash], [], false) + connection.reload + connection.metronome_open.should be_false + end + end end end \ No newline at end of file diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index f6cda4a51..2bedb654d 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -114,6 +114,7 @@ var $openBackingTrack = null; var $metronomePlaybackSelect = null; var $metronomePlaybackHelp = null; + var $templatePendingMetronome = null; var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup]; var muteBothMasterAndPersonalGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup]; @@ -234,12 +235,8 @@ promptLeave = false; window.location = '/client#/home' }); - }) - }) - - } function notifyWithUserInfo(title , text, clientId) { @@ -495,7 +492,7 @@ } function checkJamTrackTransition(currentSession) { -// handle jam tracks + // handle jam tracks if (jamTrack == null && (currentSession && currentSession.jam_track != null)) { playbackControls.startMonitor(context.JK.PLAYBACK_MONITOR_MODE.JAMTRACK); } @@ -506,7 +503,7 @@ } function checkBackingTrackTransition(currentSession) { -// handle backing tracks + // handle backing tracks if (backing_track_path == null && (currentSession && currentSession.backing_track_path != null)) { playbackControls.startMonitor(); } @@ -517,7 +514,7 @@ } function checkRecordingTransition(currentSession) { -// handle claimed recordings + // handle claimed recordings if (claimedRecording == null && (currentSession && currentSession.claimed_recording != null)) { // this is a 'started with a claimed_recording' transition. // we need to start a timer to watch for the state of the play session @@ -601,10 +598,11 @@ } function resetOtherAudioContent() { - if ($('.session-recordings .track').length === 0 && $('.session-recordings .download-jamtrack').length === 0) { + if ($('.session-recordings .track').length === 0 && $('.session-recordings .download-jamtrack').length === 0 && $('.session-recordings .pending-metronome').length === 0) { $('.session-recordings .when-empty').show(); $('.session-recording-name-wrapper').hide(); $('.session-recordings .recording-controls').hide(); + $closePlaybackRecording.show(); $('.session-recordings .session-recording-name').text('(No audio loaded)') } } @@ -635,6 +633,7 @@ if ($('.session-livetracks .track').length === 0) { $('.session-livetracks .when-empty').show(); } + checkPendingMetronome(); resetOtherAudioContent(); /** @@ -1345,6 +1344,7 @@ setFormFromMetronome() metroCricket = context.jamClient.getMetronomeCricketTestState(); setMetronomePlaybackMode() + $closePlaybackRecording.show(); } @@ -2447,6 +2447,30 @@ .fail(app.ajaxError); } + function checkPendingMetronome() { + logger.debug("checkPendingMetronome", sessionModel.isMetronomeOpen(), getMetronomeMasterMixers().length) + if(sessionModel.isMetronomeOpen() && getMetronomeMasterMixers().length == 0) { + var pendingMetronome = $($templatePendingMetronome.html()) + + // hide the open options + otherAudioFilled(); + // fill out the 'media' name + $('.session-recordings .session-recording-name').text('Metronome') + // and hide the close button + $closePlaybackRecording.hide(); + + // avoid double addition of pending metronome + if($otherAudioContainer.find('.pending-metronome').length === 0) { + $otherAudioContainer.append(pendingMetronome) + } + + } + else { + $('.session-recordings .pending-metronome').remove() + } + + } + function openBackingTrack(e) { if($openBackingTrack.is('.disabled')) { @@ -2946,6 +2970,7 @@ $openBackingTrack = $('#open-a-backingtrack'); $metronomePlaybackSelect = $('#metronome-playback-select') $metronomePlaybackHelp = $('#metronome-playback-help') + $templatePendingMetronome = $('#template-pending-metronome'); events(); diff --git a/web/app/assets/javascripts/sessionModel.js b/web/app/assets/javascripts/sessionModel.js index b61292800..723ed08f1 100644 --- a/web/app/assets/javascripts/sessionModel.js +++ b/web/app/assets/javascripts/sessionModel.js @@ -34,7 +34,7 @@ var sessionPageEnterTimeout = null; var startTime = null; var joinDeferred = null; - var previousBackingTracks = []; + var previousAllTracks = {userTracks: [], backingTracks: [], metronomeTracks: []}; var openBackingTrack = null; var shownAudioMediaMixerHelp = false; var controlsLockedForJamTrackRecording = false; @@ -68,6 +68,20 @@ } } + // if any participant has the metronome open, then we say this session has the metronome open + function isMetronomeOpen() { + var metronomeOpen = false; + context._.each(participants(), function(participant) { + console.log("paritiparc.", participant.metronome_open) + if(participant.metronome_open) { + metronomeOpen = true; + return false; + } + }) + + return metronomeOpen; + } + function isPlayingRecording() { // this is the server's state; there is no guarantee that the local tracks // requested from the backend will have corresponding track information @@ -358,7 +372,7 @@ } currentSessionId = null; currentParticipants = {} - previousBackingTracks = [] + previousAllTracks = {userTracks: [], backingTracks: [], metronomeTracks: []} openBackingTrack = null shownAudioMediaMixerHelp = false controlsLockedForJamTrackRecording = false; @@ -603,26 +617,27 @@ return mixerMode; } - function syncTracks(backingTracks) { + function syncTracks(allTracks) { // double check that we are in session, since a bunch could have happened since then if(!inSession()) { logger.debug("dropping queued up sync tracks because no longer in session"); return null; } - // this is a local change to our tracks. we need to tell the server about our updated track information - var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient); - - // backingTracks can be passed in as an optimization, so that we don't hit the backend excessively - if(backingTracks === undefined ) { - backingTracks = context.JK.TrackHelpers.getBackingTracks(context.jamClient); + if(allTracks === undefined) { + allTracks = context.JK.TrackHelpers.getTrackInfo(context.jamClient); } + var inputTracks = allTracks.userTracks; + var backingTracks = allTracks.backingTracks; + var metronomeTracks = allTracks.metronomeTracks; + // create a trackSync request based on backend data var syncTrackRequest = {}; syncTrackRequest.client_id = app.clientId; syncTrackRequest.tracks = inputTracks; syncTrackRequest.backing_tracks = backingTracks; + syncTrackRequest.metronome_open = metronomeTracks.length > 0; syncTrackRequest.id = id(); return rest.putTrackSyncChange(syncTrackRequest) @@ -793,17 +808,27 @@ } else if(inSession() && (text == 'RebuildMediaControl' || text == 'RebuildRemoteUserControl')) { - var backingTracks = context.JK.TrackHelpers.getBackingTracks(context.jamClient); + var allTracks = context.JK.TrackHelpers.getTrackInfo(context.jamClient); + var backingTracks = allTracks.backingTracks; + var previousBackingTracks = previousAllTracks.backingTracks; + var metronomeTracks = allTracks.metronomeTracks; + var previousMetronomeTracks = previousAllTracks.metronomeTracks; // the way we know if backing tracks changes, or recordings are opened, is via this event. // but we want to report to the user when backing tracks change; so we need to detect change on our own if(!(previousBackingTracks.length == 0 && backingTracks.length == 0) && previousBackingTracks != backingTracks) { logger.debug("backing tracks changed", previousBackingTracks, backingTracks) - syncTracks(backingTracks); + syncTracks(allTracks); + } + else if(!(previousMetronomeTracks.length == 0 && metronomeTracks.length == 0) && previousMetronomeTracks != metronomeTracks) { + logger.debug("metronome state changed ", previousMetronomeTracks, metronomeTracks) + syncTracks(allTracks); } else { refreshCurrentSession(true); } + + previousAllTracks = allTracks; } else if(inSession() && (text == 'Global Peer Input Mixer Mode')) { setMixerMode(MIX_MODES.MASTER); @@ -840,6 +865,7 @@ this.isPersonalMixMode = isPersonalMixMode; this.getMixMode = getMixMode; this.selfOpenedJamTracks = selfOpenedJamTracks; + this.isMetronomeOpen = isMetronomeOpen; this.areControlsLockedForJamTrackRecording = areControlsLockedForJamTrackRecording; this.lockControlsforJamTrackRecording = lockControlsforJamTrackRecording; this.unlockControlsforJamTrackRecording = unlockControlsforJamTrackRecording; diff --git a/web/app/assets/javascripts/trackHelpers.js b/web/app/assets/javascripts/trackHelpers.js index a77792a1c..b434d80a9 100644 --- a/web/app/assets/javascripts/trackHelpers.js +++ b/web/app/assets/javascripts/trackHelpers.js @@ -14,9 +14,28 @@ // take all necessary arguments to complete its work. context.JK.TrackHelpers = { - getTracks: function(jamClient, groupId) { + getTrackInfo: function(jamClient) { + + var allTracks = context.jamClient.SessionGetAllControlState(true); + + var userTracks = context.JK.TrackHelpers.getUserTracks(jamClient, allTracks); + var backingTracks = context.JK.TrackHelpers.getBackingTracks(jamClient, allTracks); + var metronomeTracks = context.JK.TrackHelpers.getTracks(jamClient, 12); + + return { + userTracks: userTracks, + backingTracks: backingTracks, + metronomeTracks: metronomeTracks + } + }, + + // allTracks is the result of SessionGetAllControlState; as an optimization + getTracks: function(jamClient, groupId, allTracks) { var tracks = []; - var allTracks = context.jamClient.SessionGetAllControlState(true); + + if(!allTracks) { + allTracks = context.jamClient.SessionGetAllControlState(true); + } //var trackIds = jamClient.SessionGetIDs(); //var allTracks = jamClient.SessionGetControlState(trackIds, true); @@ -30,8 +49,9 @@ return tracks; }, - getBackingTracks: function(jamClient) { - var mediaTracks = context.JK.TrackHelpers.getTracks(jamClient, 4); + // allTracks is the result of SessionGetAllControlState; as an optimization + getBackingTracks: function(jamClient, allTracks) { + var mediaTracks = context.JK.TrackHelpers.getTracks(jamClient, 4, allTracks); var backingTracks = [] context._.each(mediaTracks, function(mediaTrack) { @@ -56,11 +76,11 @@ * from jamClient. If none exist there, the first instrument from the * user's profile is used. */ - getUserTracks: function(jamClient) { + getUserTracks: function(jamClient, allTracks) { var localMusicTracks = []; var i; - localMusicTracks = context.JK.TrackHelpers.getTracks(jamClient, 2); + localMusicTracks = context.JK.TrackHelpers.getTracks(jamClient, 2, allTracks); var trackObjects = []; diff --git a/web/app/assets/stylesheets/client/session.css.scss b/web/app/assets/stylesheets/client/session.css.scss index 116ba1e1a..42467d158 100644 --- a/web/app/assets/stylesheets/client/session.css.scss +++ b/web/app/assets/stylesheets/client/session.css.scss @@ -15,6 +15,16 @@ position:relative; } + .pending-metronome { + .spinner-large { + margin:20px auto 0; + text-align:center; + } + p { + text-align:center; + font-size:14px; + } + } .track { width:70px; diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index e5f6a7bd4..bb8760dc2 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -357,7 +357,7 @@ class ApiMusicSessionsController < ApiController end def track_sync - @tracks = MusicSessionManager.new.sync_tracks(@music_session, params[:client_id], params[:tracks], params[:backing_tracks]) + @tracks = MusicSessionManager.new.sync_tracks(@music_session, params[:client_id], params[:tracks], params[:backing_tracks], params[:metronome_open]) unless @tracks.kind_of? Array # we have to do this because api_session_detail_url will fail with a bad @tracks diff --git a/web/app/views/api_music_sessions/show.rabl b/web/app/views/api_music_sessions/show.rabl index c81cf9ff6..8149352d0 100644 --- a/web/app/views/api_music_sessions/show.rabl +++ b/web/app/views/api_music_sessions/show.rabl @@ -45,7 +45,7 @@ else child(:connections => :participants) { collection @music_sessions, :object_root => false - attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id + attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id, :metronome_open node :user do |connection| { :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state } diff --git a/web/app/views/clients/_session.html.slim b/web/app/views/clients/_session.html.slim index a873900fa..eb7541100 100644 --- a/web/app/views/clients/_session.html.slim +++ b/web/app/views/clients/_session.html.slim @@ -143,4 +143,9 @@ script#template-option type="text/template" script#template-genre-option type="text/template" option value="{value}" - ="{label}" \ No newline at end of file + ="{label}" + +script#template-pending-metronome type="text/template" + .pending-metronome + .spinner-large + p Your metronome is synchronizing. diff --git a/web/lib/music_session_manager.rb b/web/lib/music_session_manager.rb index 706b41d83..ac10e6d20 100644 --- a/web/lib/music_session_manager.rb +++ b/web/lib/music_session_manager.rb @@ -140,10 +140,10 @@ class MusicSessionManager < BaseManager Notification.send_session_depart(active_music_session, connection.client_id, user, recordingId) end - def sync_tracks(active_music_session, client_id, new_tracks, backing_tracks) + def sync_tracks(active_music_session, client_id, new_tracks, backing_tracks, metronome_open) tracks = nil active_music_session.with_lock do # VRFS-1297 - tracks = Track.sync(client_id, new_tracks, backing_tracks) + tracks = Track.sync(client_id, new_tracks, backing_tracks, metronome_open) active_music_session.tick_track_changes end Notification.send_tracks_changed(active_music_session)