* VRFS-2922 - show spinner for pending metronome

This commit is contained in:
Seth Call 2015-03-12 21:53:23 -05:00
parent 5fa37abfb3
commit 7c73e2ab5c
14 changed files with 143 additions and 33 deletions

View File

@ -261,3 +261,4 @@ add_jam_track_bitrates.sql
jam_track_importer.sql
jam_track_pro_licensing_update.sql
jam_track_redeemed.sql
connection_metronome.sql

View File

@ -0,0 +1 @@
ALTER TABLE connections ADD COLUMN metronome_open BOOLEAN NOT NULL DEFAULT FALSE;

View File

@ -89,7 +89,7 @@ module JamRuby
udp_reachable_value = udp_reachable.nil? ? 'udp_reachable' : udp_reachable
sql =<<SQL
UPDATE connections SET (channel_id, aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time, udp_reachable, gateway, is_network_testing) = ('#{channel_id}', '#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time}, #{udp_reachable_value}, '#{gateway}', FALSE)
UPDATE connections SET (channel_id, aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time, udp_reachable, gateway, is_network_testing, metronome_open) = ('#{channel_id}', '#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time}, #{udp_reachable_value}, '#{gateway}', FALSE, FALSE)
WHERE
client_id = '#{conn.client_id}'
RETURNING music_session_id

View File

@ -21,6 +21,7 @@ module JamRuby
has_many :backing_tracks, :class_name => "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

View File

@ -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 = []

View File

@ -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

View File

@ -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) {
@ -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();

View File

@ -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;

View File

@ -14,9 +14,28 @@
// take all necessary arguments to complete its work.
context.JK.TrackHelpers = {
getTracks: function(jamClient, groupId) {
var tracks = [];
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 = [];
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 = [];

View File

@ -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;

View File

@ -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

View File

@ -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 }

View File

@ -144,3 +144,8 @@ script#template-option type="text/template"
script#template-genre-option type="text/template"
option value="{value}"
="{label}"
script#template-pending-metronome type="text/template"
.pending-metronome
.spinner-large
p Your metronome is synchronizing.

View File

@ -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)