* 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:
parent
0d53309cd5
commit
7ab7bfd795
|
|
@ -125,3 +125,4 @@ scores_mod_connections2.sql
|
|||
track_download_counts.sql
|
||||
scores_mod_users2.sql
|
||||
user_bio.sql
|
||||
track_changes_counter.sql
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def joining_session?
|
||||
return joining_session
|
||||
joining_session
|
||||
end
|
||||
|
||||
def can_join_music_session
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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",
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,9 @@
|
|||
|
||||
function heartbeatAck(header, payload) {
|
||||
lastHeartbeatAckTime = new Date();
|
||||
|
||||
context.JK.CurrentSessionModel.trackChanges(header, payload);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue