* VRFS-1297, VRFS-1305, VRFS-293, VRFS-950, VRFS-641 - track changes added to help frontend better understand when it needs to poke backend, and refresh state

This commit is contained in:
Seth Call 2014-03-03 16:13:23 -06:00
parent 0d53309cd5
commit 7ab7bfd795
28 changed files with 431 additions and 188 deletions

View File

@ -125,3 +125,4 @@ scores_mod_connections2.sql
track_download_counts.sql
scores_mod_users2.sql
user_bio.sql
track_changes_counter.sql

View File

@ -0,0 +1,2 @@
ALTER TABLE music_sessions ADD COLUMN track_changes_counter INTEGER DEFAULT 0;
ALTER TABLE connections ADD COLUMN joined_session_at timestamp without time zone DEFAULT NULL;

View File

@ -35,6 +35,7 @@ message ClientMessage {
SESSION_JOIN = 190;
SESSION_DEPART = 195;
MUSICIAN_SESSION_JOIN = 196;
TRACKS_CHANGED = 197;
// recording notifications
MUSICIAN_RECORDING_SAVED = 200;
@ -109,6 +110,7 @@ message ClientMessage {
optional SessionJoin session_join = 190;
optional SessionDepart session_depart = 195;
optional MusicianSessionJoin musician_session_join = 196;
optional TracksChanged tracks_changed = 197;
// recording notifications
optional MusicianRecordingSaved musician_recording_saved = 200;
@ -286,6 +288,7 @@ message SessionJoin {
optional string session_id = 1;
optional string photo_url = 2;
optional string msg = 3;
optional int32 track_changes_counter = 4;
}
message SessionDepart {
@ -293,6 +296,12 @@ message SessionDepart {
optional string photo_url = 2;
optional string msg = 3;
optional string recording_id = 4;
optional int32 track_changes_counter = 5;
}
message TracksChanged {
optional string session_id = 1;
optional int32 track_changes_counter = 2;
}
message MusicianSessionJoin {
@ -447,6 +456,7 @@ message Heartbeat {
// target: client
// sent from server to client in response to a Heartbeat
message HeartbeatAck {
optional int32 track_changes_counter = 1;
}
// route_to: client

View File

@ -53,6 +53,7 @@ module JamRuby
music_session_id_expression = 'NULL'
unless reconnect_music_session_id.nil?
music_session_id_expression = "(CASE WHEN music_session_id='#{reconnect_music_session_id}' THEN music_session_id ELSE NULL END)"
joined_session_at_expression = "(CASE WHEN music_session_id='#{reconnect_music_session_id}' THEN NOW() ELSE NULL END)"
end
if ip_address
@ -97,7 +98,7 @@ module JamRuby
end
sql =<<SQL
UPDATE connections SET (aasm_state, updated_at, music_session_id) = ('#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression})
UPDATE connections SET (aasm_state, updated_at, music_session_id, joined_session_at) = ('#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression})
WHERE
client_id = '#{conn.client_id}'
RETURNING music_session_id
@ -373,6 +374,7 @@ SQL
connection.music_session_id = music_session_id
connection.as_musician = as_musician
connection.joining_session = true
connection.joined_session_at = Time.now
associate_tracks(connection, tracks)
connection.save
@ -408,7 +410,7 @@ SQL
end
# can throw exception if the session is deleted just before this
conn.exec("UPDATE connections SET music_session_id = NULL, as_musician = NULL WHERE client_id = $1 AND user_id =$2", [client_id, user_id]) do |result|
conn.exec("UPDATE connections SET music_session_id = NULL, joined_session_at = NULL, as_musician = NULL WHERE client_id = $1 AND user_id =$2", [client_id, user_id]) do |result|
if result.cmd_tuples == 1
@log.debug("disassociated music_session with connection for client_id=#{client_id}, user_id=#{user_id}")

View File

@ -136,8 +136,10 @@ module JamRuby
end
# create a heartbeat ack
def heartbeat_ack()
heartbeat_ack = Jampb::HeartbeatAck.new
def heartbeat_ack(track_changes_counter)
heartbeat_ack = Jampb::HeartbeatAck.new(
:track_changes_counter => track_changes_counter,
)
Jampb::ClientMessage.new(
:type => ClientMessage::Type::HEARTBEAT_ACK,
@ -366,11 +368,12 @@ module JamRuby
)
end
def session_join(session_id, photo_url, msg)
def session_join(session_id, photo_url, msg, track_changes_counter)
join = Jampb::SessionJoin.new(
:session_id => session_id,
:photo_url => photo_url,
:msg => msg
:msg => msg,
:track_changes_counter => track_changes_counter
)
Jampb::ClientMessage.new(
@ -380,12 +383,13 @@ module JamRuby
)
end
def session_depart(session_id, photo_url, msg, recording_id = nil)
def session_depart(session_id, photo_url, msg, recording_id, track_changes_counter)
left = Jampb::SessionDepart.new(
:session_id => session_id,
:photo_url => photo_url,
:msg => msg,
:recording_id => recording_id
:recording_id => recording_id,
:track_changes_counter => track_changes_counter
)
Jampb::ClientMessage.new(
@ -395,6 +399,21 @@ module JamRuby
)
end
def tracks_changed(session_id, track_changes_counter)
tracks_changed = Jampb::TracksChanged.new(
:session_id => session_id,
:track_changes_counter => track_changes_counter
)
Jampb::ClientMessage.new(
:type => ClientMessage::Type::TRACKS_CHANGED,
:route_to => CLIENT_TARGET,
:tracks_changed => tracks_changed
)
end
def musician_session_join(receiver_id, session_id, photo_url, msg, notification_id, created_at)
musician_session_join = Jampb::MusicianSessionJoin.new(
:session_id => session_id,

View File

@ -61,7 +61,7 @@ module JamRuby
end
def joining_session?
return joining_session
joining_session
end
def can_join_music_session

View File

@ -260,6 +260,11 @@ module JamRuby
description
end
def tick_track_changes
self.track_changes_counter += 1
self.save!(:validate => false)
end
private
def require_at_least_one_genre

View File

@ -427,6 +427,7 @@ module JamRuby
join_request.id,
music_session.id,
music_session.creator.photo_url,
notification_msg,
notification.id,
notification.created_at.to_s
)
@ -441,13 +442,14 @@ module JamRuby
msg = @@message_factory.session_join(
music_session.id,
user.photo_url,
notification_msg
notification_msg,
music_session.track_changes_counter
)
@@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => connection.client_id})
end
def send_session_depart(music_session, client_id, user, recordingId = nil)
def send_session_depart(music_session, client_id, user, recordingId)
notification_msg = format_msg(NotificationTypes::SESSION_DEPART, user)
@ -455,12 +457,21 @@ module JamRuby
music_session.id,
user.photo_url,
notification_msg,
recordingId
recordingId,
music_session.track_changes_counter
)
@@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id})
end
def send_tracks_changed(music_session)
msg = @@message_factory.tracks_changed(
music_session.id, music_session.track_changes_counter
)
@@mq_router.server_publish_to_session(music_session, msg)
end
def send_musician_session_join(music_session, connection, user)
if music_session.musician_access || music_session.fan_access

View File

@ -77,7 +77,7 @@ module JamRuby
connection_tracks.each do |connection_track|
tracks.each do |track|
if track[:id] == connection_track.id || track[:client_track_id] == connection_track.client_track_id;
if track[:id] == connection_track.id || track[:client_track_id] == connection_track.client_track_id
to_delete.delete(connection_track)
to_add.delete(track)
# don't update connection_id or client_id; it's unknown what would happen if these changed mid-session
@ -86,13 +86,16 @@ module JamRuby
connection_track.client_track_id = track[:client_track_id]
instruments << track[:instrument_id]
result.push(connection_track)
if connection_track.save
result.push(connection_track)
next
else
result = connection_track
raise ActiveRecord::Rollback
end
end
end
end

View File

@ -8,13 +8,11 @@ describe GetWork do
it "get_work_1" do
x = GetWork.get_work(1)
puts x.inspect
x.should be_nil
end
it "get_work_list_1" do
x = GetWork.get_work_list(1)
puts x.inspect
x.should eql([])
end
end

View File

@ -74,12 +74,21 @@ describe Track do
it "updates a single track using .id to correlate" do
track.id.should_not be_nil
connection.tracks.length.should == 1
begin
ActiveRecord::Base.record_timestamps = false
track.updated_at = 1.days.ago
track.save!
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}])
tracks.length.should == 1
found = tracks[0]
found.id.should == track.id
found.sound.should == 'mono'
found.client_track_id.should == 'client_guid_new'
found.updated_at.should_not == track.updated_at
end
it "updates a single track using .client_track_id to correlate" do
@ -92,5 +101,23 @@ describe Track do
found.sound.should == 'mono'
found.client_track_id.should == track.client_track_id
end
it "does not touch updated_at when nothing changes" do
track.id.should_not be_nil
connection.tracks.length.should == 1
begin
ActiveRecord::Base.record_timestamps = false
track.updated_at = 1.days.ago
track.save!
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id}])
tracks.length.should == 1
found = tracks[0]
found.id.should == track.id
found.updated_at.should == track.updated_at
end
end
end

View File

@ -33,6 +33,7 @@
JOIN_REQUEST_REJECTED : "JOIN_REQUEST_REJECTED",
SESSION_JOIN : "SESSION_JOIN",
SESSION_DEPART : "SESSION_DEPART",
TRACKS_CHANGED : "TRACKS_CHANGED",
MUSICIAN_SESSION_JOIN : "MUSICIAN_SESSION_JOIN",
BAND_SESSION_JOIN : "BAND_SESSION_JOIN",

View File

@ -104,7 +104,7 @@
payload = message[messageType],
callbacks = server.dispatchTable[message.type];
if(message.type != context.JK.MessageType.HEARTBEAT_ACK) {
if(message.type != context.JK.MessageType.HEARTBEAT_ACK && message.type != context.JK.MessageType.PEER_MESSAGE) {
logger.log("server.onMessage:" + messageType + " payload:" + JSON.stringify(payload));
}
@ -134,7 +134,7 @@
var jsMessage = JSON.stringify(message);
if(message.type != context.JK.MessageType.HEARTBEAT) {
if(message.type != context.JK.MessageType.HEARTBEAT && message.type != context.JK.MessageType.PEER_MESSAGE) {
logger.log("server.send(" + jsMessage + ")");
}
if (server !== undefined && server.socket !== undefined && server.socket.send !== undefined) {
@ -163,9 +163,11 @@
* @param message the actual message
*/
server.sendP2PMessage = function(receiver_id, message) {
logger.log("P2P message from [" + server.clientID + "] to [" + receiver_id + "]: " + message);
//logger.log("P2P message from [" + server.clientID + "] to [" + receiver_id + "]: " + message);
console.time('sendP2PMessage');
var outgoing_msg = msg_factory.client_p2p_message(server.clientID, receiver_id, message);
server.send(outgoing_msg);
console.timeEnd('sendP2PMessage');
};
context.JK.JamServer = server;

View File

@ -231,11 +231,7 @@
// TODO: repeated in configureTrack.js
function _init() {
// load instrument array for populating listboxes, using client_id in instrument_map as ID
context.JK.listInstruments(app, function(instruments) {
$.each(instruments, function(index, val) {
instrument_array.push({"id": context.JK.server_to_client_instrument_map[val.description].client_id, "description": val.description});
});
});
instrument_array = context.JK.listInstruments();
}
this.initialize = function() {

View File

@ -779,20 +779,8 @@
}
function _init() {
var dialogBindings = {
'beforeShow' : function() {
return context.JK.verifyNotRecordingForTrackChange(app);
}
};
app.bindDialog('configure-audio', dialogBindings);
// load instrument array for populating listboxes, using client_id in instrument_map as ID
context.JK.listInstruments(app, function(instruments) {
$.each(instruments, function(index, val) {
instrument_array.push({"id": context.JK.server_to_client_instrument_map[val.description].client_id, "description": val.description});
});
});
instrument_array = context.JK.listInstruments();
originalVoiceChat = context.jamClient.TrackGetChatEnable() ? VOICE_CHAT.CHAT : VOICE_CHAT.NO_CHAT;
@ -818,11 +806,25 @@
}
}
this.initialize = function() {
events();
_init();
myTrackCount = myTracks.length;
};
function initialize () {
var dialogBindings = {
'beforeShow' : function() {
return context.JK.verifyNotRecordingForTrackChange(app);
}
};
app.bindDialog('configure-audio', dialogBindings);
events();
}
// should be called before opening
function refresh() {
_init();
myTrackCount = myTracks.length;
}
this.initialize = initialize;
this.refresh = refresh;
this.showMusicAudioPanel = showMusicAudioPanel;
this.showVoiceChatPanel = showVoiceChatPanel;

View File

@ -83,7 +83,7 @@
var OTHER = 'div#sessions-other';
// INVITATION
logger.debug("sessionCounts[CATEGORY.INVITATION.index]=" + sessionCounts[CATEGORY.INVITATION.index]);
//logger.debug("sessionCounts[CATEGORY.INVITATION.index]=" + sessionCounts[CATEGORY.INVITATION.index]);
if (sessionCounts[CATEGORY.INVITATION.index] === 0) {
priorVisible = false;
$(INVITATION).hide();
@ -98,7 +98,7 @@
$(FRIEND).removeClass('mt35');
}
logger.debug("sessionCounts[CATEGORY.FRIEND.index]=" + sessionCounts[CATEGORY.FRIEND.index]);
//logger.debug("sessionCounts[CATEGORY.FRIEND.index]=" + sessionCounts[CATEGORY.FRIEND.index]);
if (sessionCounts[CATEGORY.FRIEND.index] === 0) {
priorVisible = false;
$(FRIEND).hide();
@ -113,7 +113,7 @@
$(OTHER).removeClass('mt35');
}
logger.debug("sessionCounts[CATEGORY.OTHER.index]=" + sessionCounts[CATEGORY.OTHER.index]);
//logger.debug("sessionCounts[CATEGORY.OTHER.index]=" + sessionCounts[CATEGORY.OTHER.index]);
if (sessionCounts[CATEGORY.OTHER.index] === 0) {
$(OTHER).hide();
}

View File

@ -110,6 +110,9 @@
function heartbeatAck(header, payload) {
lastHeartbeatAckTime = new Date();
context.JK.CurrentSessionModel.trackChanges(header, payload);
}
/**

View File

@ -30,6 +30,7 @@
var claimedRecording = null;
var playbackControls = null;
var promptLeave = false;
var backendMixerAlertThrottleTimer = null;
var rest = context.JK.Rest();
@ -80,26 +81,26 @@
0: {"title": "", "message": ""}, // NO_EVENT,
1: {"title": "", "message": ""}, // BACKEND_ERROR: generic error - eg P2P message error
2: {"title": "", "message": ""}, // BACKEND_MIXER_CHANGE, - event that controls have been regenerated
3: {"title": "Packet Jitter", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // PACKET_JTR,
4: {"title": "Packet Loss", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // PACKET_LOSS
5: {"title": "Packet Late", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // PACKET_LATE,
6: {"title": "Packet Queue Depth", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // JTR_QUEUE_DEPTH,
7: {"title": "Network Jitter", "message": "Your network connection is currently experiencing network jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // NETWORK_JTR,
8: {"title": "Session Latency", "message": "The latency of your audio device combined with your Internet connection has become high enough to impact your session quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // NETWORK_PING,
3: {"title": "High Packet Jitter", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // PACKET_JTR,
4: {"title": "High Packet Loss", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // PACKET_LOSS
5: {"title": "High Packet Late", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // PACKET_LATE,
6: {"title": "Large Jitter Queue", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // JTR_QUEUE_DEPTH,
7: {"title": "High Network Jitter", "message": "Your network connection is currently experiencing network jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // NETWORK_JTR,
8: {"title": "High Session Latency", "message": "The latency of your audio device combined with your Internet connection has become high enough to impact your session quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // NETWORK_PING,
9: {"title": "Bandwidth Throttled", "message": "The available bandwidth on your network has diminished, and this may impact your audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // BITRATE_THROTTLE_WARN,
10:{"title": "Low Bandwidth", "message": "The available bandwidth on your network has become too low, and this may impact your audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // BANDWIDTH_LOW
// IO related events
11:{"title": "Input Rate", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // INPUT_IO_RATE
12:{"title": "Input Jitter", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // INPUT_IO_JTR,
13:{"title": "Output Rate", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // OUTPUT_IO_RATE
14:{"title": "Output Jitter", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // OUTPUT_IO_JTR,
11:{"title": "Variable Input Rate", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // INPUT_IO_RATE
12:{"title": "High Input Jitter", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // INPUT_IO_JTR,
13:{"title": "Variable Output Rate", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // OUTPUT_IO_RATE
14:{"title": "High Output Jitter", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // OUTPUT_IO_JTR,
// CPU load related
15: { "title": "CPU Utilization High", "message": "The CPU of your computer is unable to keep up with the current processing load, and this may impact your audio quality. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>." }, // CPU_LOAD
16: {"title": "Decode Violations", "message": ""}, // DECODE_VIOLATIONS,
17: {"title": "", "message": ""}, // LAST_THRESHOLD
18: {"title": "Wifi Use Alert", "message": ""}, // WIFI_NETWORK_ALERT, //user or peer is using wifi
18: {"title": "Wifi Alert", "message": ""}, // WIFI_NETWORK_ALERT, //user or peer is using wifi
19: {"title": "No Audio Configuration", "message": "You cannot join the session because you do not have a valid audio configuration."}, // NO_VALID_AUDIO_CONFIG,
20: {"title": "Audio Device Not Present", "message": ""}, // AUDIO_DEVICE_NOT_PRESENT, // the audio device is not connected
21: {"title": "", "message": ""}, // RECORD_PLAYBACK_STATE, // record/playback events have occurred
@ -123,7 +124,8 @@
//indicates problem with user computer stack or network itself (wifi, antivirus etc)
36: {"title": "LAN High Latency", "message": "Your local network is adding considerable latency. For troubleshooting tips, <a href='https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems'>click here</a>."}, // LOCAL_NETWORK_LATENCY_HIGH,
37: {"title": "", "message": ""}, // RECORDING_CLOSE, //update and remove tracks from front-end
38: {"title": "", "message": ""} // LAST_ALERT
38: {"title": "No Audio Sent", "message": ""}, // PEER_REPORTS_NO_AUDIO_RECV, //update and remove tracks from front-end
39: {"title": "", "message": ""} // LAST_ALERT
};
@ -137,10 +139,33 @@
shareDialog.initialize(context.JK.FacebookHelperInstance);
}
function alertCallback(type, text) {
function timeCallback() {
var start = new Date();
setTimeout(function() {
var timed = new Date().getTime() - start.getTime();
if(timed > 250) {
logger.warn("SLOW AlERT_CALLBACK. type: %o text: %o time: %o", type, text, timed);
}
}, 1);
}
timeCallback();
console.log("alert callback", type, text);
if (type === 2) { // BACKEND_MIXER_CHANGE
logger.debug("BACKEND_MIXER_CHANGE alert. reason:" + text);
logger.debug("BACKEND_MIXER_CHANGE alert. reason:" + text);
if(sessionModel.id() && text == "RebuildAudioIoControl") {
// the backend will send these events rapid-fire back to back.
// the server can still perform correctly, but it is nicer to wait 100 ms to let them all fall through
if(backendMixerAlertThrottleTimer) {clearTimeout(backendMixerAlertThrottleTimer);}
backendMixerAlertThrottleTimer = setTimeout(function() {
// 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);
@ -151,29 +176,17 @@
syncTrackRequest.id = sessionModel.id();
rest.putTrackSyncChange(syncTrackRequest)
.done(function() {
sessionModel.refreshCurrentSession();
})
.fail(function() {
app.notify({
"title": "Can't Sync Local Tracks",
"text": "The client is unable to sync local track information with the server. You should rejoin the session to ensure a good experience.",
"icon_url": "/assets/content/icon_alert_big.png"
});
})
}
else {
// this is wrong; we shouldn't be using the server to decide what tracks are shown
// however, we have to without a refactor, and if we wait a second, then it should be enough time
// for the client that initialed this to have made the change
// https://jamkazam.atlassian.net/browse/VRFS-854
setTimeout(function() {
sessionModel.refreshCurrentSession(); // XXX: race condition possible here; other client may not have updated server yet
}, 3000);
var start = new Date();
setTimeout(function() {
console.log("REBUILDMIXERCHANGE DONE: ", new Date().getTime() - start.getTime());
}, 1)
.done(function() {
})
.fail(function() {
app.notify({
"title": "Can't Sync Local Tracks",
"text": "The client is unable to sync local track information with the server. You should rejoin the session to ensure a good experience.",
"icon_url": "/assets/content/icon_alert_big.png"
});
})
}, 100);
}
}
else if (type === 19) { // NO_VALID_AUDIO_CONFIG
@ -196,6 +209,19 @@
}
});
}
else if (type === 26) {
var clientId = text;
var participant = sessionModel.getParticipant(clientId);
if(participant) {
app.notify({
"title": alert_type[type].title,
"text": participant.user.name + " is no longer sending audio.",
"icon_url": context.JK.resolveAvatarUrl(participant.user.photo_url)
});
var $track = $('div.track[client-id="' + clientId + '"]');
$('.disabled-track-overlay', $track).show();
}
}
else if (type === 27) { // WINDOW_CLOSE_BACKGROUND_MODE
// the window was closed; just attempt to nav to home, which will cause all the right REST calls to happen
promptLeave = false;
@ -557,6 +583,17 @@
return foundMixers;
}
function _userMusicInputMixerForClientId(clientId) {
var found = null;
$.each(mixers, function(index, mixer) {
if (mixer.group_id === ChannelGroupIds.UserMusicInputGroup && mixer.client_id == clientId) {
found = mixer;
return false;
}
});
return found;
}
// TODO FIXME - This needs to support multiple tracks for an individual
// client id and group.
function _mixerForClientId(clientId, groupIds, usedMixers) {
@ -639,17 +676,16 @@
context.JK.FaderHelpers.renderFader(faderId, faderOpts);
context.JK.FaderHelpers.subscribe(faderId, l2mChanged);
// initialize to middle (50%, 0dB) per Peter's request
context.JK.FaderHelpers.setFaderValue(faderId, 50);
context.jamClient.SessionSetMasterLocalMix(0);
var value = context.jamClient.SessionGetMasterLocalMix();
context.JK.FaderHelpers.setFaderValue(faderId, percentFromMixerValue(-80, 20, value));
}
/**
* This has a specialized jamClient call, so custom handler.
*/
function l2mChanged(faderId, newValue, dragging) {
var dbValue = context.JK.FaderHelpers.convertLinearToDb(newValue);
context.jamClient.SessionSetMasterLocalMix(dbValue);
//var dbValue = context.JK.FaderHelpers.convertLinearToDb(newValue);
context.jamClient.SessionSetMasterLocalMix(newValue - 80);
}
function _addVoiceChat() {
@ -688,8 +724,6 @@
var recordedTracks = sessionModel.recordedTracks();
console.log("recorded tracks=%o local_media=%o", recordedTracks, localMediaMixers);
if(recordedTracks && localMediaMixers.length == 0) {
// if we are the creator, then rather than raise an error, tell the server the recording is over.
// this shoudl only happen if we get temporarily disconnected by forced reload, which isn't a very normal scenario
@ -700,7 +734,6 @@
}
if(recordedTracks) {
$('.session-recording-name').text(sessionModel.getCurrentSession().claimed_recording.name);
var noCorrespondingTracks = false;
@ -775,7 +808,7 @@
trackData.muteClass = muteClass;
trackData.mixerId = mixer.id;
_addMediaTrack(index, trackData);
_addMediaTrack(trackData);
});
if(!noCorrespondingTracks && recordedTracks.length > 0) {
@ -850,15 +883,20 @@
trackData.gainPercent = gainPercent;
trackData.muteClass = muteClass;
trackData.mixerId = mixer.id;
trackData.noaudio = false;
context.jamClient.SessionSetUserName(participant.client_id,name);
} else { // No mixer to match, yet
lookingForMixers[track.id] = participant.client_id;
trackData.noaudio = true;
if (!(lookingForMixersTimer)) {
console.log("waiting for mixer to show up for track: " + track.id)
lookingForMixersTimer = context.setInterval(lookForMixers, 500);
}
}
_addTrack(index, trackData);
var allowDelete = myTrack && index > 0;
_addTrack(allowDelete, trackData);
// Show settings icons only for my tracks
if (myTrack) {
@ -890,6 +928,9 @@
// Set gain position
context.JK.FaderHelpers.setFaderValue(mixerId, gainPercent);
context.JK.FaderHelpers.subscribe(mixerId, faderChanged);
// associate the UserMusicInput mixer with tracks for this user
var musicInputMixer = _userMusicInputMixerForClientId(clientId);
if(musicInputMixer) $track.find('.track-connection').attr('mixer-id', musicInputMixer.id + '_connection');
}
// Function called on an interval when participants change. Mixers seem to
@ -917,11 +958,25 @@
mixer.range_low, mixer.range_high, mixer.volume_left);
var trackSelector = 'div.track[track-id="' + key + '"]';
connectTrackToMixer(trackSelector, key, mixer.id, gainPercent);
var $track = $('div.track[client-id="' + key + '"]');
var $track = $('div.track[client-id="' + clientId + '"]');
$track.find('.track-icon-mute').attr('mixer-id', mixer.id);
// hide overlay for all tracks associated with this client id (if one mixer is present, then all tracks are valid)
$('.disabled-track-overlay', $track).hide();
$('.track-connection', $track).removeClass('red').addClass('grey');
// Set mute state
_toggleVisualMuteControl($track.find('.track-icon-mute'), mixer.mute);
}
else {
// if 1 second has gone by and still no mixer, then we gray the participant's tracks
if(lookingForMixersCount == 2) {
var $track = $('div.track[client-id="' + clientId + '"]');
$('.disabled-track-overlay', $track).show();
$('.track-connection', $track).removeClass('green').addClass('red');
}
}
}
for (var i=0; i<keysToDelete.length; i++) {
@ -965,16 +1020,20 @@
}
}
function _addTrack(index, trackData) {
function _addTrack(allowDelete, trackData) {
var parentSelector = '#session-mytracks-container';
var $destination = $(parentSelector);
if (trackData.clientId !== app.clientId) {
console.log("ADDING REMOTE TRACK: noaudio", trackData.noaudio)
parentSelector = '#session-livetracks-container';
$destination = $(parentSelector);
$('.session-livetracks .when-empty').hide();
}
var template = $('#template-session-track').html();
var newTrack = $(context.JK.fillTemplate(template, trackData));
var audioOverlay = $('.disabled-track-overlay', newTrack);
audioOverlay.hide(); // always start with overlay hidden, and only show if no audio persists
$destination.append(newTrack);
// Render VU meters and gain fader
@ -983,7 +1042,7 @@
connectTrackToMixer(trackSelector, trackData.clientId, trackData.mixerId, gainPercent);
var $closeButton = $('#div-track-close', 'div[track-id="' + trackData.trackId + '"]');
if (index === 0) {
if (!allowDelete) {
$closeButton.hide();
}
else {
@ -995,7 +1054,7 @@
function _addMediaTrack(index, trackData) {
function _addMediaTrack(trackData) {
var parentSelector = '#session-recordedtracks-container';
var $destination = $(parentSelector);
$('.session-recordings .when-empty').hide();
@ -1065,6 +1124,7 @@
}
_updateVU(mixerId, vuVal);
} else if (eventName === 'connection_status') {
// Connection Quality Change
var connectionClass = 'green';
if (value < 7) {
@ -1074,9 +1134,15 @@
connectionClass = 'red';
}
var $connection = $('[mixer-id="' + mixerId + '_connection"]');
$connection.removeClass('green yellow red');
$connection.addClass(connectionClass);
var $connection = $('.track-connection[mixer-id="' + mixerId + '_connection"]');
if($connection.length == 0) {
logger.warn("there is connection status element found for mixerId: " + mixerId)
}
else {
$connection.removeClass('green yellow red');
$connection.addClass(connectionClass);
}
} else if (eventName === 'add' || eventName === 'remove') {
// TODO - _renderSession. Note I get streams of these in
@ -1417,6 +1483,7 @@
$('#open-a-recording').on('click', openRecording);
$('#session-invite-musicians').on('click', inviteMusicians);
$('#track-settings').click(function() {
configureTrackDialog.refresh();
configureTrackDialog.showVoiceChatPanel(true);
configureTrackDialog.showMusicAudioPanel(true);
});

View File

@ -59,7 +59,10 @@
var jsFunction = "JK.Callbacks.clientPingResponse";
var timeoutFunction = "JK.Callbacks.clientPingTimeout";
console.log("jamClient.TestLatency")
console.time('jamClient.TestLatency');
jamClient.TestLatency(clientID, jsFunction, timeoutFunction);
console.timeEnd('jamClient.TestLatency');
});
}

View File

@ -18,6 +18,10 @@
var requestingSessionRefresh = false;
var pendingSessionRefresh = false;
var recordingModel = new context.JK.RecordingModel(app, this, rest, context.jamClient);
var currentTrackChanges = 0;
// we track all the clientIDs of all the participants ever seen by this session, so that we can reliably convert a clientId from the backend into a username/avatar
var participantsEverSeen = {};
function id() {
return currentSession ? currentSession.id : null;
}
@ -83,10 +87,9 @@
recordingModel.reset();
client.JoinSession({ sessionID: sessionId });
refreshCurrentSession();
server.registerMessageCallback(context.JK.MessageType.SESSION_JOIN, refreshCurrentSession);
server.registerMessageCallback(context.JK.MessageType.SESSION_DEPART, refreshCurrentSession);
server.registerMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.registerMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
})
.fail(function() {
currentSessionId = null;
@ -98,10 +101,10 @@
function performLeaveSession(deferred) {
logger.debug("SessionModel.leaveCurrentSession()");
// TODO - sessionChanged will be called with currentSession = null
server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, refreshCurrentSession);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, refreshCurrentSession);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, refreshCurrentSession);
// TODO - sessionChanged will be called with currentSession = null\
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
//server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, refreshCurrentSession);
// leave the session right away without waiting on REST. Why? If you can't contact the server, or if it takes a long
@ -143,12 +146,26 @@
return deferred;
}
function trackChanges(header, payload) {
if(currentTrackChanges < payload.track_changes_counter) {
// we don't have the latest info. try and go get it
logger.debug("track_changes_counter = stale. refreshing...")
refreshCurrentSession();
}
else {
if(header.type != 'HEARTBEAT_ACK') {
// don't log if HEARTBEAT_ACK, or you will see this log all the time
logger.info("track_changes_counter = fresh. skipping refresh...", header, payload)
}
}
}
/**
* Refresh the current session, and participants.
*/
function refreshCurrentSession() {
// XXX use backend instead: https://jamkazam.atlassian.net/browse/VRFS-854
logger.debug("SessionModel.refreshCurrentSession(" + currentSessionId +")");
//logger.debug("SessionModel.refreshCurrentSession(" + currentSessionId +")");
refreshCurrentSessionRest(sessionChanged);
}
@ -165,7 +182,6 @@
* Notify subscribers that the current session has changed.
*/
function sessionChanged() {
logger.debug("SessionModel.sessionChanged()");
for (var subscriberId in subscribers) {
subscribers[subscriberId](currentSession);
}
@ -188,6 +204,7 @@
var url = "/api/sessions/" + currentSessionId;
if(requestingSessionRefresh) {
// if someone asks for a refresh while one is going on, we ask for another to queue up
logger.debug("queueing refresh");
pendingSessionRefresh = true;
}
else {
@ -196,19 +213,26 @@
type: "GET",
url: url,
success: function(response) {
sendClientParticipantChanges(currentSession, response);
updateCurrentSession(response);
if(callback != null) {
if(currentTrackChanges < response.track_changes_counter) {
logger.debug("updating current track changes from %o to %o", currentTrackChanges, response.track_changes_counter)
currentTrackChanges = response.track_changes_counter;
sendClientParticipantChanges(currentSession, response);
updateCurrentSession(response);
if(callback != null) {
callback();
}
}
else {
logger.info("ignoring refresh because we already have current: " + currentTrackChanges + ", seen: " + response.track_changes_counter);
}
},
error: function(jqXHR) { app.notifyServerError(jqXHR, "Unable to refresh session data") },
complete: function() {
requestingSessionRefresh = false;
if(pendingSessionRefresh) {
// and when the request is done, if we have a pending, fire t off again
// and when the request is done, if we have a pending, fire it off again
pendingSessionRefresh = false;
refreshCurrentSessionRest(null);
refreshCurrentSessionRest(sessionChanged);
}
}
});
@ -232,49 +256,72 @@
}
function sendClientParticipantChanges(oldSession, newSession) {
var joins = [], leaves = []; // Will hold JamClientParticipants
var joins = [], leaves = [], leaveJoins = []; // Will hold JamClientParticipants
var oldParticipants = []; // will be set to session.participants if session
var oldParticipantIds = [];
var oldParticipantIds = {};
var newParticipants = [];
var newParticipantIds = [];
var newParticipantIds = {};
if (oldSession && oldSession.participants) {
oldParticipants = oldSession.participants;
$.each(oldParticipants, function() {
oldParticipantIds.push(this.client_id);
oldParticipantIds[this.client_id] = this;
});
}
if (newSession && newSession.participants) {
newParticipants = newSession.participants;
$.each(newParticipants, function() {
newParticipantIds.push(this.client_id);
newParticipantIds[this.client_id] = this;
});
}
$.each(newParticipantIds, function(i,v) {
if ($.inArray(v, oldParticipantIds) === -1) {
// new participant id that's not in old participant ids: Join
joins.push(_toJamClientParticipant(newParticipants[i]));
$.each(newParticipantIds, function(client_id, participant) {
// grow the 'all participants seen' list
if(!(client_id in participantsEverSeen)) {
participantsEverSeen[client_id] = participant;
}
if(client_id in oldParticipantIds) {
// if the participant is here now, and here before, there is still a chance we missed a
// very fast leave/join. So check if joined_session_at is different
if(oldParticipantIds[client_id].joined_session_at != participant.joined_session_at) {
leaveJoins.push(_toJamClientParticipant(participant))
}
}
else {
// new participant id that's not in old participant ids: Join
joins.push(_toJamClientParticipant(participant));
}
});
$.each(oldParticipantIds, function(i,v) {
if ($.inArray(v, newParticipantIds) === -1) {
$.each(oldParticipantIds, function(client_id, participant) {
if (!(client_id in newParticipantIds)) {
// old participant id that's not in new participant ids: Leave
leaves.push(_toJamClientParticipant(oldParticipants[i]));
leaves.push(_toJamClientParticipant(participant));
}
});
$.each(joins, function(i,v) {
if (v.client_id != clientId) {
logger.debug("jamClient.ParticipantJoined", v.clientID)
client.ParticipantJoined(newSession, v);
}
});
$.each(leaves, function(i,v) {
if (v.client_id != clientId) {
logger.debug("jamClient.ParticipantLeft", v.clientID)
client.ParticipantLeft(newSession, v);
}
});
$.each(leaveJoins, function(i,v) {
if (v.client_id != clientId) {
logger.debug("participant had a rapid leave/join")
logger.debug("jamClient.ParticipantLeft", v.clientID)
client.ParticipantLeft(newSession, v);
logger.debug("jamClient.ParticipantJoined", v.clientID)
client.ParticipantJoined(newSession, v);
}
});
}
@ -292,30 +339,8 @@
function deleteTrack(sessionId, trackId) {
if (trackId) {
client.TrackSetCount(1);
client.TrackSaveAssignments();
/**
$.ajax({
type: "DELETE",
url: "/api/sessions/" + sessionId + "/tracks/" + trackId,
async: false,
success: function(response) {
// TODO: if in recording, more cleanup to do???
// update backend client (for now, only the second track can be removed)
client.TrackSetCount(1);
client.TrackSaveAssignments();
// refresh Session screen
refreshCurrentSession();
},
error: function(jqXHR, textStatus, errorThrown) {
logger.error("Error deleting track " + trackId);
}
});
*/
}
}
@ -454,10 +479,14 @@
this.getCurrentOrLastSession = function() {
return currentOrLastSession;
};
this.trackChanges = trackChanges;
this.getParticipant = function(clientId) {
return participantsEverSeen[clientId]
};
this.unsubscribe = function() {
server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, refreshCurrentSession);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, refreshCurrentSession);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, refreshCurrentSession);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
}
};

View File

@ -309,18 +309,14 @@
})
}
context.JK.listInstruments = function (app, callback) {
var url = "/api/instruments";
$.ajax({
type: "GET",
dataType: "json",
url: url,
success: function (response) {
callback(response);
},
error: app.ajaxError
// creates an array with entries like [{ id: "drums", description: "Drums"}, ]
context.JK.listInstruments = function() {
var instrumentArray = [];
$.each(context.JK.server_to_client_instrument_map, function(key, val) {
instrumentArray.push({"id": context.JK.server_to_client_instrument_map[key].client_id, "description": key});
});
};
return instrumentArray;
}
context.JK.showErrorDialog = function (app, msg, title) {
app.layout.showDialog('error-dialog');

View File

@ -267,13 +267,23 @@ table.vu td {
white-space:nowrap;
}
.track {
width:70px;
height:290px;
display:inline-block;
margin-right:8px;
position:relative;
background-color:#242323;
width:70px;
height:290px;
display:inline-block;
margin-right:8px;
position:relative;
background-color:#242323;
.disabled-track-overlay {
width:100%;
height:100%;
position:absolute;
background-color:#555;
opacity:0.5;
display:none;
}
}

View File

@ -4,7 +4,7 @@ class ApiMusicSessionsController < ApiController
# have to be signed in currently to see this screen
before_filter :api_signed_in_user, :except => [ :add_like ]
before_filter :lookup_session, only: [:show, :update, :delete, :claimed_recording_start, :claimed_recording_stop]
before_filter :lookup_session, only: [:show, :update, :delete, :claimed_recording_start, :claimed_recording_stop, :track_sync]
skip_before_filter :api_signed_in_user, only: [:perf_upload]
respond_to :json
@ -143,10 +143,10 @@ class ApiMusicSessionsController < ApiController
end
def track_sync
@tracks = Track.sync(params[:client_id], params[:tracks])
@tracks = MusicSessionManager.new.sync_tracks(@music_session, params[:client_id], params[:tracks])
unless @tracks.kind_of? Array
# we have to do this because api_session_detail_url will fail with a bad @music_session
# we have to do this because api_session_detail_url will fail with a bad @tracks
response.status = :unprocessable_entity
respond_with @tracks
else

View File

@ -1,6 +1,6 @@
object @music_session
attributes :id, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id
attributes :id, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter
node :genres do |item|
item.genres.map(&:description)
@ -20,14 +20,14 @@ end
child(:connections => :participants) {
collection @music_sessions, :object_root => false
attributes :ip_address, :client_id
attributes :ip_address, :client_id, :joined_session_at
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 }
end
child(:tracks => :tracks) {
attributes :id, :connection_id, :instrument_id, :sound, :client_track_id
attributes :id, :connection_id, :instrument_id, :sound, :client_track_id, :updated_at
}
}

View File

@ -166,7 +166,8 @@
<div class="track-icon-mute {muteClass}" control="mute" mixer-id="{mixerId}">
</div>
<!-- TODO - connection class from curly param -->
<div mixer-id="{mixerId}_connection" class="track-connection green">CONNECTION</div>
<div mixer-id="{mixerId}_connection" class="track-connection grey">CONNECTION</div>
<div class="disabled-track-overlay"></div>
</div>
</script>

View File

@ -227,6 +227,35 @@
window.jamClient = new JK.FakeJamClient(JK.app, p2pMessageFactory);
window.jamClient.SetFakeRecordingImpl(new JK.FakeJamClientRecordings(JK.app, jamClient, p2pMessageFactory));
}
else if(false) { // set to true to time long running bridge calls
var originalJamClient = window.jamClient;
var interceptedJamClient = {};
$.each(Object.keys(originalJamClient), function(i, key) {
if(key.indexOf('(') > -1) {
// this is a method. time it
var jsKey = key.substring(0, key.indexOf('('))
console.log("replacing " + jsKey)
interceptedJamClient[jsKey] = function() {
var original = originalJamClient[key]
var start = new Date();
var returnVal = original.apply(originalJamClient, arguments)
var time = new Date().getTime() - start.getTime();
if(time > 0) {
console.error(time + "ms jamClient." + jsKey);
}
return returnVal;
}
}
else {
// we need to intercept properties... but how?
}
});
window.jamClient = interceptedJamClient;
}
// Let's get things rolling...
if (JK.currentUserId) {

View File

@ -105,15 +105,16 @@ MusicSessionManager < BaseManager
music_session = MusicSession.find(music_session_id)
connection = ConnectionManager.new.join_music_session(user, client_id, music_session, as_musician, tracks)
music_session.with_lock do # VRFS-1297
music_session.tick_track_changes
connection = ConnectionManager.new.join_music_session(user, client_id, music_session, as_musician, tracks)
if connection.errors.any?
# rollback the transaction to make sure nothing is disturbed in the database
raise ActiveRecord::Rollback
else
# send out notification to queue to the rest of the session
# TODO: also this isn't necessarily a user leaving; it's a client leaving'
if connection.errors.any?
# rollback the transaction to make sure nothing is disturbed in the database
raise ActiveRecord::Rollback
end
end
end
unless connection.errors.any?
@ -142,11 +143,25 @@ MusicSessionManager < BaseManager
end
recordingId = nil
ConnectionManager.new.leave_music_session(user, connection, music_session) do
recording = music_session.stop_recording # stop any ongoing recording, if there is one
recordingId = recording.id unless recording.nil?
music_session.with_lock do # VRFS-1297
ConnectionManager.new.leave_music_session(user, connection, music_session) do
music_session.tick_track_changes
recording = music_session.stop_recording # stop any ongoing recording, if there is one
recordingId = recording.id unless recording.nil?
end
end
Notification.send_session_depart(music_session, connection.client_id, user, recordingId)
end
def sync_tracks(music_session, client_id, new_tracks)
tracks = nil
music_session.with_lock do # VRFS-1297
tracks = Track.sync(client_id, new_tracks)
music_session.tick_track_changes
end
Notification.send_tracks_changed(music_session)
tracks
end
end

View File

@ -355,7 +355,10 @@ module JamWebsockets
user = User.find_by_id(user_id) unless user_id.nil?
recording = music_session.stop_recording unless music_session.nil? # stop any ongoing recording, if there is one
recordingId = recording.id unless recording.nil?
}
music_session.with_lock do # VRFS-1297
music_session.tick_track_changes
end if music_session
}
end
Notification.send_session_depart(music_session, cid, user, recordingId) unless music_session.nil? || user.nil?
@ -444,7 +447,7 @@ module JamWebsockets
password = login.password if login.value_for_tag(2)
token = login.token if login.value_for_tag(3)
client_id = login.client_id if login.value_for_tag(4)
reconnect_music_session_id = login.client_id if login.value_for_tag(5)
reconnect_music_session_id = login.reconnect_music_session_id if login.value_for_tag(5)
@log.info("*** handle_login: token=#{token}; client_id=#{client_id}")
reconnected = false
@ -493,6 +496,9 @@ module JamWebsockets
unless context.nil? || music_session_upon_reentry.nil? || music_session_upon_reentry.destroyed?
recording = music_session_upon_reentry.stop_recording
recordingId = recording.id unless recording.nil?
music_session_upon_reentry.with_lock do # VRFS-1297
music_session_upon_reentry.tick_track_changes
end
send_depart = true
end
else
@ -550,19 +556,24 @@ module JamWebsockets
raise SessionError, 'context state is gone. please reconnect.'
else
connection = Connection.find_by_user_id_and_client_id(context.user.id, context.client.client_id)
track_changes_counter = nil
if connection.nil?
@log.warn "*** WARNING: unable to find connection due to heartbeat from client: #{context}; calling cleanup_client"
cleanup_client(client)
raise SessionError, 'connection state is gone. please reconnect.'
else
connection.touch
Connection.transaction do
music_session = MusicSession.select(:track_changes_counter).find_by_id(connection.music_session_id) if connection.music_session_id
track_changes_counter = music_session.track_changes_counter if music_session
connection.touch
end
ConnectionManager.active_record_transaction do |connection_manager|
connection_manager.reconnect(connection, connection.music_session_id, nil)
end if connection.stale?
end
heartbeat_ack = @message_factory.heartbeat_ack()
heartbeat_ack = @message_factory.heartbeat_ack(track_changes_counter)
send_to_client(client, heartbeat_ack)