diff --git a/web/app/assets/javascripts/dialog/openJamTrackDialog.js b/web/app/assets/javascripts/dialog/openJamTrackDialog.js index 5ac306595..b3d485876 100644 --- a/web/app/assets/javascripts/dialog/openJamTrackDialog.js +++ b/web/app/assets/javascripts/dialog/openJamTrackDialog.js @@ -77,6 +77,7 @@ // tell the server we are about to start a recording rest.openJamTrack({id: context.JK.CurrentSessionModel.id(), jam_track_id: jamTrack.id}) .done(function(response) { + context.jamClient.JamTrackStopPlay(); var result = context.jamClient.JamTrackPlay('t'); logger.debug("JamTrackPlay response: %o", result); diff --git a/web/app/assets/javascripts/download_jamtrack.js.coffee b/web/app/assets/javascripts/download_jamtrack.js.coffee new file mode 100644 index 000000000..75e684bc6 --- /dev/null +++ b/web/app/assets/javascripts/download_jamtrack.js.coffee @@ -0,0 +1,11 @@ +$ = jQuery +context = window +context.JK ||= {}; + +context.JK.DownloadJamTrack = class SyncViewer + constructor: (@app) -> + @EVENTS = context.JK.EVENTS + @rest = context.JK.Rest() + + init: () => + @root = $($('#template-download-jamtrack').html()) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index e355d7cd0..c1c41357d 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -87,7 +87,9 @@ "UserMusicInputGroup": 7, "UserChatInputGroup": 8, "PeerAudioInputMusicGroup": 9, - "PeerMediaTrackGroup": 10 + "PeerMediaTrackGroup": 10, + "JamTrackGroup": 11, + "MetronomeGroup": 12 }; function beforeShow(data) { @@ -599,6 +601,20 @@ return foundMixers; } + function _mixersForGroupIds(groupIds, mixMode) { + var foundMixers = []; + var mixers = mixMode == MIX_MODES.MASTER ? masterMixers : personalMixers; + $.each(mixers, function(index, mixer) { + var groupIdLen = groupIds.length; + for (var i = 0; i < groupIdLen; i++) { + if ( mixer.group_id === groupIds[i]) { + foundMixers.push(mixer); + } + } + }); + return foundMixers; + } + function _getMyVoiceChatMixers() { var mixers = _mixersForGroupId(ChannelGroupIds.AudioInputChatGroup, sessionModel.getMixMode()); @@ -796,8 +812,8 @@ function _renderLocalMediaTracks() { - // first gather all master mode media mixers and peer media mixers - var localMediaMixers = _mixersForGroupId(ChannelGroupIds.MediaTrackGroup, MIX_MODES.MASTER); + // local media mixers come in different groups (MediaTrack, JamTrack, Metronome), but peer mixers are always PeerMediaTrackGroup + var localMediaMixers = _mixersForGroupIds([ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup], MIX_MODES.MASTER); var peerLocalMediaMixers = _mixersForGroupId(ChannelGroupIds.PeerMediaTrackGroup, MIX_MODES.MASTER); // with mixer info, we use these to decide what kind of tracks are open in the backend @@ -820,7 +836,7 @@ var metronomeTrackMixers = []; var adhocTrackMixers = []; - + console.log("_renderLocalMediaTracks", localMediaMixers) function groupByType(mixers) { context._.each(mixers, function(mixer) { var mediaType = mixer.media_type; @@ -869,7 +885,99 @@ } function renderJamTracks(jamTrackMixers) { - logger.error("do not know how to draw jam tracks yet") + log.debug("rendering jam tracks") + var jamTracks = sessionModel.jamTracks(); + + // pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer) + // if it's a locally opened track (JamTrackGroup), then we can say this person is the opener + var isOpener = jamTrackMixers[0].group_id == ChannelGroupIds.JamTrackGroup; + + // using the server's info in conjuction with the client's, draw the recording tracks + if(jamTracks) { + $('.session-recording-name').text(sessionModel.getCurrentSession().jam_track.name); + + var noCorrespondingTracks = false; + $.each(jamTrackMixers, function(index, mixer) { + var preMasteredClass = ""; + // find the track or tracks that correspond to the mixer + var correspondingTracks = [] + console.log("mixer", mixer) + $.each(jamTracks, function(i, jamTrack) { + if(mixer.id.indexOf("L") == 0) { + if(mixer.id.substring(1) == jamTrack.id) { + correspondingTracks.push(jamTrack); + } + else { + // this should not be possible + alert("Invalid state: the recorded track had neither persisted_track_id or persisted_client_id"); + } + } + }); + + if(correspondingTracks.length == 0) { + noCorrespondingTracks = true; + app.notify({ + title: "Unable to Open JamTrack", + text: "Could not correlate server and client tracks", + icon_url: "/assets/content/icon_alert_big.png"}); + return false; + } + + // prune found recorded tracks + jamTracks = $.grep(jamTracks, function(value) { + return $.inArray(value, correspondingTracks) < 0; + }); + + var oneOfTheTracks = correspondingTracks[0]; + var instrumentIcon = context.JK.getInstrumentIcon45(oneOfTheTracks.instrument_id); + var photoUrl = "/assets/content/icon_recording.png"; + + var name = oneOfTheTracks.part + if (!name) { + name = oneOfTheTracks.instrument; + } + + // Default trackData to participant + no Mixer state. + var trackData = { + trackId: oneOfTheTracks.id, + clientId: oneOfTheTracks.client_id, + name: name, + instrumentIcon: instrumentIcon, + avatar: photoUrl, + latency: "good", + gainPercent: 0, + muteClass: 'muted', + mixerId: "", + avatarClass : 'avatar-recording', + preMasteredClass: "" + }; + + var gainPercent = percentFromMixerValue( + mixer.range_low, mixer.range_high, mixer.volume_left); + var muteClass = "enabled"; + if (mixer.mute) { + muteClass = "muted"; + } + trackData.gainPercent = gainPercent; + trackData.muteClass = muteClass; + trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) + trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) + + if(sessionModel.isPersonalMixMode() || !isOpener) { + trackData.mediaControlsDisabled = true; + trackData.mediaTrackOpener = isOpener; + } + _addRecordingTrack(trackData); + }); + + if(!noCorrespondingTracks && jamTracks.length > 0) { + logger.error("unable to find all jam tracks against client tracks"); + app.notify({title:"All tracks not found", + text: "Some tracks in the jam tracks are not present in the playback", + icon_url: "/assets/content/icon_alert_big.png"}) + } + } } function renderMetronomeTracks(metronomeTrackMixers) { @@ -881,15 +989,6 @@ // get the server's info for the recording var recordedTracks = sessionModel.recordedTracks(); - if(recordedTracks && recordingMixers.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 - if(sessionModel.getCurrentSession().claimed_recording_initiator_id == context.JK.userMe.id) { - closeRecording(); - return; - } - } - // pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between Local vs Peer) // if it's a locally opened track (MediaTrackGroup), then we can say this person is the opener @@ -1834,7 +1933,7 @@ if(sessionModel.recordedTracks()) { closeRecording(); } - else if(sessionModel.jamTrack()) { + else if(sessionModel.jamTracks()) { closeJamTrack(); } else { diff --git a/web/app/assets/javascripts/sessionModel.js b/web/app/assets/javascripts/sessionModel.js index 0dd38f007..9b7f034fe 100644 --- a/web/app/assets/javascripts/sessionModel.js +++ b/web/app/assets/javascripts/sessionModel.js @@ -78,6 +78,15 @@ } } + function jamTracks() { + if(currentSession && currentSession.jam_track) { + return currentSession.jam_track.tracks + } + else { + return null; + } + } + function creatorId() { if(!currentSession) { throw "creator is not known" @@ -709,6 +718,7 @@ this.start = start; this.setUserTracks = setUserTracks; this.recordedTracks = recordedTracks; + this.jamTracks = jamTracks; this.participants = participants; this.joinSession = joinSession; this.leaveCurrentSession = leaveCurrentSession; diff --git a/web/app/assets/stylesheets/client/downloadJamTrack.css.scss b/web/app/assets/stylesheets/client/downloadJamTrack.css.scss new file mode 100644 index 000000000..1cfe42004 --- /dev/null +++ b/web/app/assets/stylesheets/client/downloadJamTrack.css.scss @@ -0,0 +1,5 @@ +@import "client/common"; + +.download-jamtrack { + +} \ No newline at end of file diff --git a/web/app/views/clients/_download_jamtrack_templates.html.slim b/web/app/views/clients/_download_jamtrack_templates.html.slim new file mode 100644 index 000000000..bf5831cb4 --- /dev/null +++ b/web/app/views/clients/_download_jamtrack_templates.html.slim @@ -0,0 +1,2 @@ +script type="text/template" id='template-download-jamtrack' + .download-jamtrack diff --git a/web/app/views/clients/_session.html.erb b/web/app/views/clients/_session.html.erb index 900079c8f..377ec043d 100644 --- a/web/app/views/clients/_session.html.erb +++ b/web/app/views/clients/_session.html.erb @@ -103,7 +103,7 @@