diff --git a/db/manifest b/db/manifest
index 5a9ba3bbd..0a8041934 100755
--- a/db/manifest
+++ b/db/manifest
@@ -368,4 +368,5 @@ retailers.sql
second_ed.sql
second_ed_v2.sql
retailers_v2.sql
-retailer_interest.sql
\ No newline at end of file
+retailer_interest.sql
+connection_role.sql
\ No newline at end of file
diff --git a/db/up/connection_role.sql b/db/up/connection_role.sql
new file mode 100644
index 000000000..754df6635
--- /dev/null
+++ b/db/up/connection_role.sql
@@ -0,0 +1,2 @@
+ALTER TABLE connections ADD COLUMN client_role VARCHAR;
+ALTER TABLE connections ADD COLUMN parent_client_id VARCHAR;
\ No newline at end of file
diff --git a/ruby/lib/jam_ruby/connection_manager.rb b/ruby/lib/jam_ruby/connection_manager.rb
index 92d960b22..92aea6228 100644
--- a/ruby/lib/jam_ruby/connection_manager.rb
+++ b/ruby/lib/jam_ruby/connection_manager.rb
@@ -402,7 +402,7 @@ SQL
music_session.creator
end
- def join_music_session(user, client_id, music_session, as_musician, tracks, audio_latency, video_sources=nil)
+ def join_music_session(user, client_id, music_session, as_musician, tracks, audio_latency, client_role = nil, parent_client_id = nil, video_sources=nil)
connection = nil
ConnectionManager.active_record_transaction do |connection_manager|
@@ -418,7 +418,7 @@ SQL
raise JamPermissionError, "wrong user_id associated with connection #{client_id}"
end
- connection.join_the_session(music_session, as_musician, tracks, user, audio_latency, video_sources)
+ connection.join_the_session(music_session, as_musician, tracks, user, audio_latency, client_role, parent_client_id, video_sources)
JamRuby::MusicSessionUserHistory.join_music_session(user.id, music_session.id, client_id)
# connection.music_session_id = music_session.id
# connection.as_musician = as_musician
diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb
index dd809d35f..41a8ebfa5 100644
--- a/ruby/lib/jam_ruby/models/active_music_session.rb
+++ b/ruby/lib/jam_ruby/models/active_music_session.rb
@@ -501,7 +501,7 @@ module JamRuby
[music_sessions, user_scores]
end
- def self.participant_create(user, music_session_id, client_id, as_musician, tracks, audio_latency, video_sources=nil)
+ def self.participant_create(user, music_session_id, client_id, as_musician, tracks, audio_latency, client_role = nil, parent_client_id = nil, video_sources=nil)
music_session = MusicSession.find(music_session_id)
# USERS ARE ALREADY IN SESSION
@@ -514,7 +514,7 @@ module JamRuby
active_music_session.with_lock do # VRFS-1297
active_music_session.tick_track_changes
# VRFS-3986
- connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency, video_sources)
+ connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency, client_role, parent_client_id, video_sources)
if connection.errors.any?
# rollback the transaction to make sure nothing is disturbed in the database
@@ -573,7 +573,7 @@ module JamRuby
# auto-join this user into the newly created session
as_musician = true
- connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency, video_sources)
+ connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency, client_role, parent_client_id, video_sources)
unless connection.errors.any?
user.update_progression_field(:first_music_session_at)
diff --git a/ruby/lib/jam_ruby/models/connection.rb b/ruby/lib/jam_ruby/models/connection.rb
index 18f250616..8bd75a4a6 100644
--- a/ruby/lib/jam_ruby/models/connection.rb
+++ b/ruby/lib/jam_ruby/models/connection.rb
@@ -176,11 +176,13 @@ module JamRuby
true
end
- def join_the_session(music_session, as_musician, tracks, user, audio_latency, videos=nil)
+ def join_the_session(music_session, as_musician, tracks, user, audio_latency, client_role = nil, parent_client_id = nil, videos=nil)
self.music_session_id = music_session.id
self.as_musician = as_musician == true # this is deliberate; otherwise we create a warning in one our tests that passes 'blarg' (rails warning about casting strings to false)
self.joining_session = true
self.joined_session_at = Time.now
+ self.client_role = client_role
+ self.parent_client_id = parent_client_id
associate_tracks(tracks) unless tracks.nil?
associate_videos(videos) unless videos.nil?
self.save
diff --git a/ruby/lib/jam_ruby/models/recording.rb b/ruby/lib/jam_ruby/models/recording.rb
index 9c87bf6f8..dbfd2e01e 100644
--- a/ruby/lib/jam_ruby/models/recording.rb
+++ b/ruby/lib/jam_ruby/models/recording.rb
@@ -272,7 +272,9 @@ module JamRuby
music_session.connections.each do |connection|
connection.tracks.each do |track|
- recording.recorded_tracks << RecordedTrack.create_from_track(track, recording)
+ if connection.client_role != 'child'
+ recording.recorded_tracks << RecordedTrack.create_from_track(track, recording)
+ end
end
connection.video_sources.each do |video|
diff --git a/web/app/assets/javascripts/dialog/localRecordingsDialog.js b/web/app/assets/javascripts/dialog/localRecordingsDialog.js
index 2402c0023..dbca1c4c2 100644
--- a/web/app/assets/javascripts/dialog/localRecordingsDialog.js
+++ b/web/app/assets/javascripts/dialog/localRecordingsDialog.js
@@ -65,6 +65,8 @@
return;
}
+ console.log("GetLocalRecordingState", localResults)
+
$.each(claimedRecordings, function(index, claimedRecording) {
var options = {
diff --git a/web/app/assets/javascripts/dialog/recordingFinishedDialog.js b/web/app/assets/javascripts/dialog/recordingFinishedDialog.js
index 97d746144..04c3a602d 100644
--- a/web/app/assets/javascripts/dialog/recordingFinishedDialog.js
+++ b/web/app/assets/javascripts/dialog/recordingFinishedDialog.js
@@ -10,6 +10,8 @@
var $dialog = null;
var $saveVideoCheckbox = null
var $uploadToYoutube = null
+ var timeout = null
+ var CLIENT_ROLE = context.JK.CLIENT_ROLE
function resetForm() {
// remove all display errors
@@ -44,6 +46,47 @@
resetForm();
+ if(context.jamClient.getClientParentChildRole() == CLIENT_ROLE.CHILD) {
+
+ logger.debug("child client; launching preview after xfer");
+ $('#recording-finished-dialog span.nowait').addClass('hidden')
+ $('#recording-finished-dialog span.pleasewait').removeClass('hidden')
+ $('#recording-finished-dialog .preview-area').css('visibility', 'hidden')
+ $('#recording-finished-dialog form').css('visibility', 'hidden')
+ waitForMixTransfer()
+ }
+ else {
+ console.log("normal client; launching preview immediately")
+ $('#recording-finished-dialog span.pleasewait').addClass('hidden')
+ $('#recording-finished-dialog span.nowait').removeClass('hidden')
+ $('#recording-finished-dialog .preview-area').css('visibility', 'visible')
+ $('#recording-finished-dialog form').css('visibility', 'visible')
+ launchPreview();
+ }
+
+ }
+
+
+ function waitForMixTransfer() {
+ timeout = setTimeout(function() {
+ console.log("checking for file transfer", window.RecordingStore.mixTransferred)
+
+ if(window.RecordingStore.mixTransferred) {
+ $('#recording-finished-dialog span.pleasewait').addClass('hidden')
+ $('#recording-finished-dialog span.nowait').removeClass('hidden')
+ $('#recording-finished-dialog .preview-area').css('visibility', 'visible')
+ $('#recording-finished-dialog form').css('visibility', 'visible')
+ timeout = null
+ launchPreview()
+ }
+ else {
+ waitForMixTransfer();
+ }
+
+ }, 1000)
+ }
+
+ function launchPreview() {
var parentSelector = '#recording-finished-dialog div.genre-selector';
context.JK.GenreSelectorHelper.render(parentSelector);
@@ -117,10 +160,12 @@
playbackControls.startMonitor();
}
}
-
}
-
function afterHide() {
+ if(timeout) {
+ clearTimeout(timeout)
+ timeout = null
+ }
if(recording && recording.video) {
var name = $('#recording-finished-dialog form input[name=name]').val();
name = name.replace(/[^A-Za-z0-9\-\ ]/g, '');
diff --git a/web/app/assets/javascripts/playbackControls.js b/web/app/assets/javascripts/playbackControls.js
index 1ad2b3aea..43f8c02d3 100644
--- a/web/app/assets/javascripts/playbackControls.js
+++ b/web/app/assets/javascripts/playbackControls.js
@@ -496,7 +496,10 @@
monitoring = false;
logger.debug("playbackControl.stopMonitor")
if (monitorPlaybackTimeout != null) {
- clearTimeout(monitorPlaybackTimeout);
+ if(clearTimeout) {
+ clearTimeout(monitorPlaybackTimeout);
+ }
+
monitorPlaybackTimeout = null;
}
}
diff --git a/web/app/assets/javascripts/react-components/JamBlasterScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/JamBlasterScreen.js.jsx.coffee
index 1a62c0ce1..b6467f523 100644
--- a/web/app/assets/javascripts/react-components/JamBlasterScreen.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/JamBlasterScreen.js.jsx.coffee
@@ -249,7 +249,7 @@ JamBlasterActions = @JamBlasterActions
audio: () ->
`
diff --git a/web/app/assets/javascripts/react-components/SessionStatsHover.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionStatsHover.js.jsx.coffee
index 3eeac6bc1..f0c331233 100644
--- a/web/app/assets/javascripts/react-components/SessionStatsHover.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/SessionStatsHover.js.jsx.coffee
@@ -143,7 +143,7 @@ StatsInfo = {
audio = @state.stats?.audio
aggregateTag = null
- if aggregate?
+ if aggregate? && !this.props.myTrack
if aggregate.latency
aggregateStats.push(@stat(aggregate, 'aggregate', 'Tot Latency', 'latency', Math.round(aggregate.latency)))
@@ -173,10 +173,16 @@ StatsInfo = {
audio_type = 'WDM'
else if audio_long.indexOf('core') > -1
audio_type = 'CoreAudio'
+ else if audio_long.indexOf('alsa') > -1
+ audio_type = 'JamBlaster'
audioStats.push(@stat(audio, 'audio', 'Gear Driver', 'audio_in_type', audio_type))
if audio.framesize?
framesize = '?'
- if audio.framesize == 2.5
+ if audio.framesize == 1.0
+ framesize = '1 ms'
+ else if audio.framesize == 2.0
+ framesize = '1 ms'
+ else if audio.framesize == 2.5
framesize = '2.5 ms'
else if audio.framesize == 5
framesize = '5 ms'
@@ -185,7 +191,7 @@ StatsInfo = {
audioStats.push(@stat(audio, 'audio', 'Frame Size', 'framesize', framesize))
networkTag = null
- if network?
+ if network? && !this.props.myTrack
if network.ping?
networkStats.push(@stat(network, 'network', 'Latency', 'ping', (network.ping / 2).toFixed(1) + ' ms'))
if network.audiojq_median?
@@ -238,7 +244,11 @@ StatsInfo = {
onStatsChanged: (stats) ->
stats = window.SessionStatsStore.stats
if stats?
- clientStats = stats[@props.participant.client_id]
+ if stats.parent?
+ # if we have a parent, then use stats from the JamBlaster (parent), not ourselves. Otherwise we'll get bad stats (no Audio etc)
+ clientStats = stats.parent[@props.participant.client_id]
+ else
+ clientStats = stats[@props.participant.client_id]
else
clientStats = null
@setState({stats: clientStats})
diff --git a/web/app/assets/javascripts/react-components/SessionTrackGain.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionTrackGain.js.jsx.coffee
index 000d176c7..aa2781b65 100644
--- a/web/app/assets/javascripts/react-components/SessionTrackGain.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/SessionTrackGain.js.jsx.coffee
@@ -8,6 +8,7 @@ MIX_MODES = context.JK.MIX_MODES
propTypes: {
gainType: React.PropTypes.string
+ controlGroup: React.PropTypes.string
}
getInitialState: () ->
@@ -22,12 +23,11 @@ MIX_MODES = context.JK.MIX_MODES
mixers = @state.mixers.mixer
-
# if this is a media track, jam track , or media category, affect volume of both mixer and opposing mixer
if @state.mixers.mixer.group_id == ChannelGroupIds.MediaTrackGroup || @state.mixers.mixer.group_id == ChannelGroupIds.JamTrackGroup || ((@state.mixers.mixer.group_id == ChannelGroupIds.MonitorCatGroup || @state.mixers.mixer.group_id == ChannelGroupIds.MasterCatGroup) && @state.mixers.mixer.name == CategoryGroupIds.MediaTrack)
- MixerActions.faderChanged(data, [@state.mixers.mixer, @state.mixers.oppositeMixer], @props.gainType)
+ MixerActions.faderChanged(data, [@state.mixers.mixer, @state.mixers.oppositeMixer], @props.gainType, @props.controlGroup)
else
- MixerActions.faderChanged(data, mixers, @props.gainType)
+ MixerActions.faderChanged(data, mixers, @props.gainType, @props.controlGroup)
render: () ->
# mixer can be a single item or array
diff --git a/web/app/assets/javascripts/react-components/actions/MixerActions.js.coffee b/web/app/assets/javascripts/react-components/actions/MixerActions.js.coffee
index 68c71dfba..cbb7916cc 100644
--- a/web/app/assets/javascripts/react-components/actions/MixerActions.js.coffee
+++ b/web/app/assets/javascripts/react-components/actions/MixerActions.js.coffee
@@ -14,4 +14,5 @@ context = window
metronomeChanged: {}
deadUserRemove: {}
missingPeerMixer: {}
+ clientsWithAudio: {}
})
diff --git a/web/app/assets/javascripts/react-components/actions/RecordingActions.js.coffee b/web/app/assets/javascripts/react-components/actions/RecordingActions.js.coffee
index f6b111ac9..ad49fc0ca 100644
--- a/web/app/assets/javascripts/react-components/actions/RecordingActions.js.coffee
+++ b/web/app/assets/javascripts/react-components/actions/RecordingActions.js.coffee
@@ -11,4 +11,5 @@ context = window
abortedRecording: {}
openRecordingControls: {}
recordingControlsClosed: {}
+ mixTransferred: {}
})
\ No newline at end of file
diff --git a/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee b/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee
index aa28215d6..a475caad5 100644
--- a/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee
+++ b/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee
@@ -8,7 +8,7 @@ MIX_MODES = context.JK.MIX_MODES;
@MixerHelper = class MixerHelper
- constructor: (@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixMode) ->
+ constructor: (@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @clientsWithAudioOverride, @mixMode) ->
@mixMode = MIX_MODES.PERSONAL # TODO - remove mixMode from MixerHelper? Or at least stop using it in most functions
@app = @session.app
@mixersByResourceId = {}
@@ -622,13 +622,12 @@ MIX_MODES = context.JK.MIX_MODES;
return mixerPair.personal
- findMixerForTrack: (client_id, track, myTrack, mode = MIX_MODES.PERSONAL) ->
+ findMixerForTrack: (client_id, track, myTrack, mode) ->
mixer = null # what is the best mixer for this track/client ID?
oppositeMixer = null # what is the corresponding mixer in the opposite mode?
vuMixer = null
muteMixer = null
-
if myTrack
# when it's your track, look it up by the backend resource ID
mixer = @getMixerByTrackId(track.client_track_id, mode)
@@ -674,7 +673,7 @@ MIX_MODES = context.JK.MIX_MODES;
oppositeMixer = oppositeMixers[ChannelGroupIds.UserMusicInputGroup][0]
if !oppositeMixer
- logger.warn("unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer", mixer, @personalMixers )
+ logger.warn("unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer", mixer, @personalMixers)
when MIX_MODES.PERSONAL
mixers = @groupedMixersForClientId(client_id, [ ChannelGroupIds.UserMusicInputGroup], {}, MIX_MODES.PERSONAL)
@@ -693,6 +692,8 @@ MIX_MODES = context.JK.MIX_MODES;
logger.error("personaol: found remote mixer that was not of groupID: PeerAudioInputMusicGroup", client_id, track.client_track_id, mixer)
#vuMixer = oppositeMixer; # for personal mode, use the PeerAudioInputMusicGroup's VUs
+ else
+ logger.error("no UserMusicInputGroup for client_id #{client_id} in PERSONAL mode", mixers)
{
mixer: mixer,
@@ -729,26 +730,43 @@ MIX_MODES = context.JK.MIX_MODES;
originalVolume
- faderChanged: (data, mixers, gainType) ->
+ faderChanged: (data, mixers, gainType, controlGroup) ->
mixers = [mixers] unless $.isArray(mixers)
originalVolume = @getOriginalVolume(mixers, gainType)
- for mixer in mixers
- broadcast = !(data.dragging) # If fader is still dragging, don't broadcast
- mixer = @fillTrackVolumeObject(mixer.id, mixer.mode, broadcast)
+ if controlGroup?
+ mixers = [mixers[0]]
- relative = gainType == 'music' && (mixer.name == CategoryGroupIds.UserMedia || mixer.name == CategoryGroupIds.MediaTrack)
+ for mixer in mixers
+ broadcast = !(data.dragging) # If fader is still dragging, don't broadcast
+ mixer = @fillTrackVolumeObject(mixer.id, mixer.mode, broadcast)
- @setMixerVolume(mixer, data.percentage, relative, originalVolume)
+ relative = gainType == 'music' && (mixer.name == CategoryGroupIds.UserMedia || mixer.name == CategoryGroupIds.MediaTrack)
- # keep state of mixer in sync with backend
- mixer = @getMixer(mixer.id, mixer.mode)
- mixer.volume_left = context.trackVolumeObject.volL
+ @setMixerVolume(mixer, data.percentage, relative, originalVolume, controlGroup)
- #if groupId == ChannelGroupIds.UserMusicInputGroup
- # # there may be other mixers with this same ID in the case of a Peer Music Stream, so update them as well
- # context.JK.FaderHelpers.setFaderValue(mixerId, data.percentage)
+ # keep state of mixer in sync with backend
+ mixer = @getMixer(mixer.id, mixer.mode)
+ mixer.volume_left = context.trackVolumeObject.volL
+
+ else
+
+ for mixer in mixers
+ broadcast = !(data.dragging) # If fader is still dragging, don't broadcast
+ mixer = @fillTrackVolumeObject(mixer.id, mixer.mode, broadcast)
+
+ relative = gainType == 'music' && (mixer.name == CategoryGroupIds.UserMedia || mixer.name == CategoryGroupIds.MediaTrack)
+
+ @setMixerVolume(mixer, data.percentage, relative, originalVolume)
+
+ # keep state of mixer in sync with backend
+ mixer = @getMixer(mixer.id, mixer.mode)
+ mixer.volume_left = context.trackVolumeObject.volL
+
+ #if groupId == ChannelGroupIds.UserMusicInputGroup
+ # # there may be other mixers with this same ID in the case of a Peer Music Stream, so update them as well
+ # context.JK.FaderHelpers.setFaderValue(mixerId, data.percentage)
initGain: (mixer) ->
if $.isArray(mixer)
@@ -791,7 +809,7 @@ MIX_MODES = context.JK.MIX_MODES;
mixer = @getMixer(mixer.id, mixer.mode)
mixer.loop = context.trackVolumeObject.loop
- setMixerVolume: (mixer, volumePercent, relative, originalVolume) ->
+ setMixerVolume: (mixer, volumePercent, relative, originalVolume, controlGroup) ->
###
// The context.trackVolumeObject has been filled with the mixer values
// that go with mixerId, and the range of that mixer
@@ -821,7 +839,15 @@ MIX_MODES = context.JK.MIX_MODES;
else
context.trackVolumeObject.volL = newVolume
context.trackVolumeObject.volR = newVolume
- context.jamClient.SessionSetControlState(mixer.id, mixer.mode);
+ if controlGroup?
+
+ if mixer.mode == MIX_MODES.PERSONAL
+ controlGroupsArg = 0
+ else
+ controlGroupsArg = 1
+ context.jamClient.setSessionMixerCategoryPlayoutState(controlGroup == 'music', controlGroupsArg);
+ else
+ context.jamClient.SessionSetControlState(mixer.id, mixer.mode);
percentFromMixerValue: (min, max, value) ->
try
diff --git a/web/app/assets/javascripts/react-components/landing/RedeemGiftCardPage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/RedeemGiftCardPage.js.jsx.coffee
index 57ca08d88..cfb102bc1 100644
--- a/web/app/assets/javascripts/react-components/landing/RedeemGiftCardPage.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/landing/RedeemGiftCardPage.js.jsx.coffee
@@ -22,7 +22,7 @@ badCode = 'This is not a valid code. Please carefully re-enter the code and try
if errorText? && errorText.indexOf('already claimed') > -1
errorText = 'This card has already been claimed. If you believe this is in error, please email us at support@jamkazam.com to report this problem.'
-
+
buttonClassnames = classNames({'redeem-giftcard': true, 'button-orange': true, disabled: @state.processing || @state.done })
diff --git a/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee b/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee
index a25950505..6a6430b33 100644
--- a/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee
+++ b/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee
@@ -28,6 +28,12 @@ MIDI_TRACK = context.JK.MIDI_TRACK
if session.inSession()
participant = session.getParticipant(@app.clientId)
+ connStatsClientId = @app.clientId
+
+ if participant.client_role == 'child' && participant.parent_client_id?
+ participant.parent = session.getParticipant(participant.parent_client_id)
+ connStatsClientId = participant.parent_client_id
+
if participant
photoUrl = context.JK.resolveAvatarUrl(participant.user.photo_url);
@@ -79,7 +85,7 @@ MIDI_TRACK = context.JK.MIDI_TRACK
associatedVst = vst
break
- tracks.push({track: track, mixerFinder: mixerFinder, mixers: mixerData, hasMixer:hasMixer, name: name, trackName: trackName, instrumentIcon: instrumentIcon, photoUrl: photoUrl, clientId: participant.client_id, associatedVst: associatedVst})
+ tracks.push({track: track, mixerFinder: mixerFinder, mixers: mixerData, hasMixer:hasMixer, name: name, trackName: trackName, instrumentIcon: instrumentIcon, photoUrl: photoUrl, clientId: participant.client_id, associatedVst: associatedVst, connStatsClientId: connStatsClientId})
else
logger.warn("SessionMyTracks: unable to find participant")
diff --git a/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee b/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee
index 65bb1d115..f5b81df87 100644
--- a/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee
@@ -1,6 +1,7 @@
$ = jQuery
context = window
logger = context.JK.logger
+RecordingActions = @RecordingActions
SessionActions = @SessionActions
JamBlasterActions = @JamBlasterActions
@@ -27,6 +28,9 @@ JamBlasterActions = @JamBlasterActions
JamBlasterActions.pairState(map)
else if map.cmd == 'jamblaster_tracks_updated'
JamBlasterActions.jamblasterTracksUpdated()
+ else if map.cmd == 'file_xfer_from_parent'
+ if map.filename && map.filename.indexOf('RT-mix.wav') > -1
+ RecordingActions.mixTransferred()
}
)
diff --git a/web/app/assets/javascripts/react-components/stores/MixerStore.js.coffee b/web/app/assets/javascripts/react-components/stores/MixerStore.js.coffee
index d98600ca5..7518f8735 100644
--- a/web/app/assets/javascripts/react-components/stores/MixerStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/MixerStore.js.coffee
@@ -20,6 +20,7 @@ rest = context.JK.Rest()
checkingMissingPeers : {}
missingMixerPeers : {}
recheckTimeout : null
+ clientsWithAudioOverride : {}
init: ->
# Register with the app store to get @app
@@ -38,6 +39,7 @@ rest = context.JK.Rest()
this.listenTo(context.MixerActions.metronomeChanged, this.onMetronomeChanged)
this.listenTo(context.MixerActions.deadUserRemove, this.onDeadUserRemove)
this.listenTo(context.MixerActions.missingPeerMixer, this.onMissingPeerMixer)
+ this.listenTo(context.MixerActions.clientsWithAudio, this.onClientsWithAudio)
context.JK.HandleVolumeChangeCallback2 = @handleVolumeChangeCallback
context.JK.HandleMetronomeCallback2 = @handleMetronomeCallback
@@ -76,7 +78,7 @@ rest = context.JK.Rest()
# metroSound = args.sound
SessionActions.syncWithServer()
- @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixers?.mixMode || MIX_MODES.PERSONAL)
+ @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @clientsWithAudioOverride, @mixers?.mixMode || MIX_MODES.PERSONAL)
@issueChange()
@@ -132,7 +134,7 @@ rest = context.JK.Rest()
@masterMixers = context.jamClient.SessionGetAllControlState(true);
@personalMixers = context.jamClient.SessionGetAllControlState(false);
- @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixers?.mixMode || MIX_MODES.PERSONAL)
+ @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @clientsWithAudioOverride, @mixers?.mixMode || MIX_MODES.PERSONAL)
@issueChange()
@@ -146,9 +148,9 @@ rest = context.JK.Rest()
# simulate a state change to cause a UI redraw
@issueChange()
- onFaderChanged: (data, mixers, gainType) ->
+ onFaderChanged: (data, mixers, gainType, controlGroup) ->
- @mixers.faderChanged(data, mixers, gainType)
+ @mixers.faderChanged(data, mixers, gainType, controlGroup)
@issueChange()
@@ -171,7 +173,7 @@ rest = context.JK.Rest()
@metro.sound = sound
context.jamClient.SessionSetMetronome(@metro.tempo, @metro.sound, 1, 0);
- @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixers?.mixMode || MIX_MODES.PERSONAL)
+ @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @clientsWithAudioOverride, @mixers?.mixMode || MIX_MODES.PERSONAL)
@issueChange()
onDeadUserRemove: (clientId) ->
@@ -193,6 +195,9 @@ rest = context.JK.Rest()
@issueChange()
+ onClientsWithAudio: (clients) ->
+ @clientsWithAudioOverride = clients
+
onMissingPeerMixer: (clientId) ->
missingPeerAttempts = @missingMixerPeers[clientId]
@@ -219,7 +224,7 @@ rest = context.JK.Rest()
@masterMixers = context.jamClient.SessionGetAllControlState(true);
@personalMixers = context.jamClient.SessionGetAllControlState(false);
logger.debug("MixerStore: recheckForMixers")
- @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixers?.mixMode || MIX_MODES.PERSONAL)
+ @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @clientsWithAudioOverride, @mixers?.mixMode || MIX_MODES.PERSONAL)
@issueChange()
onInitGain: (mixer) ->
@@ -234,7 +239,7 @@ rest = context.JK.Rest()
logger.debug("MixerStore: onMixersChanged")
- @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixers?.mixMode || MIX_MODES.PERSONAL)
+ @mixers = new context.MixerHelper(@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @clientsWithAudioOverride, @mixers?.mixMode || MIX_MODES.PERSONAL)
SessionActions.mixersChanged.trigger(type, text, @mixers.getTrackInfo())
diff --git a/web/app/assets/javascripts/react-components/stores/RecordingStore.js.jsx.coffee b/web/app/assets/javascripts/react-components/stores/RecordingStore.js.jsx.coffee
index 682d8744e..70e49ee33 100644
--- a/web/app/assets/javascripts/react-components/stores/RecordingStore.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/stores/RecordingStore.js.jsx.coffee
@@ -33,10 +33,11 @@ BackendToFrontendFPS = {
this.trigger({isRecording: @recordingModel.isRecording()})
onStartRecording: (recordVideo, recordChat) ->
-
- frameRate = context.jamClient.GetCurrentVideoFrameRate() || 0;
-
- frameRate = BackendToFrontendFPS[frameRate]
+ frameRate = 0
+ if recordVideo
+ if context.jamClient.GetCurrentVideoFrameRate?
+ frameRate = context.jamClient.GetCurrentVideoFrameRate() || 0;
+ frameRate = BackendToFrontendFPS[frameRate]
NoVideoRecordActive = 0
WebCamRecordActive = 1
@@ -49,12 +50,14 @@ BackendToFrontendFPS = {
onStartingRecording: (details) ->
details.cause = 'starting'
+ @mixTransferred = false
this.trigger(details)
@popupRecordingControls() unless @recordingWindow?
onStartedRecording: (details) ->
details.cause = 'started'
+ @mixTransferred = false
this.trigger(details)
@popupRecordingControls() unless @recordingWindow?
@@ -92,6 +95,9 @@ BackendToFrontendFPS = {
logger.debug("recording controls closed")
@recordingWindow = null
+ onMixTransferred: () ->
+ @mixTransferred = true
+
popupRecordingControls: () ->
logger.debug("poupRecordingControls")
@recordingWindow = window.open("/popups/recording-controls", 'Recording', 'scrollbars=yes,toolbar=no,status=no,height=315,width=340')
diff --git a/web/app/assets/javascripts/react-components/stores/SessionStatsStore.js.coffee b/web/app/assets/javascripts/react-components/stores/SessionStatsStore.js.coffee
index 00439ff3c..30c8e2f26 100644
--- a/web/app/assets/javascripts/react-components/stores/SessionStatsStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/SessionStatsStore.js.coffee
@@ -6,6 +6,7 @@ EVENTS = context.JK.EVENTS
MIX_MODES = context.JK.MIX_MODES
SessionActions = @SessionActions
+MixerActions = @MixerActions
SessionStatThresholds = gon.session_stat_thresholds
NetworkThresholds = SessionStatThresholds.network
@@ -16,7 +17,9 @@ AggregateThresholds = SessionStatThresholds.aggregate
@SessionStatsStore = Reflux.createStore(
{
listenables: @SessionStatsActions
- rawStats: null
+ rawStats: null,
+ parentStats: null
+ clientsWithAudio: null
init: ->
# Register with the app store to get @app
@@ -24,8 +27,9 @@ AggregateThresholds = SessionStatThresholds.aggregate
onAppInit: (@app) ->
- onPushStats: (stats) ->
+ onPushStats: (stats, parentStats) ->
@rawStats = stats
+ @parentStats = parentStats
@changed()
classify: (holder, field, threshold) ->
@@ -65,17 +69,15 @@ AggregateThresholds = SessionStatThresholds.aggregate
else
holder[fieldLevel] = 'good'
-
- changed: () ->
- @stats = {}
-
+ classifyStats: (statBag) ->
+ container = {}
self = null
- for participant in @rawStats
+ for participant in statBag
if participant.id == @app.clientId
self = participant
break
- for participant in @rawStats
+ for participant in statBag
aggregate = {}
@@ -93,6 +95,9 @@ AggregateThresholds = SessionStatThresholds.aggregate
network = participant.network
if network?
+ if network.audio_bitrate_rx > 0 && network.audio_bitrate_tx > 0
+ @clientsWithAudio[participant.id] = true
+
@classify(network, 'audiojq_median', NetworkThresholds)
@classify(network, 'jitter_var', NetworkThresholds)
@classify(network, 'audio_bitrate_rx', NetworkThresholds)
@@ -151,8 +156,23 @@ AggregateThresholds = SessionStatThresholds.aggregate
else
participant.classification = 'unknown'
- @stats[participant.id] = participant
+ container[participant.id] = participant
+ return container
+
+ changed: () ->
+ @clientsWithAudio = {}
+ @stats = {}
+
+ @stats = @classifyStats(@rawStats)
+ if @parentStats
+ @stats.parent = @classifyStats(@parentStats)
+ else
+ @stats.parent = null
+
+ MixerActions.clientsWithAudio(@clientsWithAudio)
+
+ # see if we can reset noAudio
@trigger(@stats)
}
)
\ No newline at end of file
diff --git a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee
index 139c3b1d5..4c4b564ec 100644
--- a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee
@@ -728,8 +728,19 @@ ConfigureTracksActions = @ConfigureTracksActions
context.jamClient.SessionRegisterCallback("JK.HandleBridgeCallback2");
context.jamClient.RegisterRecordingCallbacks("JK.HandleRecordingStartResult", "JK.HandleRecordingStopResult", "JK.HandleRecordingStarted", "JK.HandleRecordingStopped", "JK.HandleRecordingAborted");
context.jamClient.SessionSetConnectionStatusRefreshRate(1000);
+ clientRole = context.jamClient.getClientParentChildRole();
+ parentClientId = context.jamClient.getParentClientId();
+ logger.debug("role when joining session: #{clientRole}, parent client id #{parentClientId}")
#context.JK.HelpBubbleHelper.jamtrackGuideSession($screen.find('li.open-a-jamtrack'), $screen)
+ if clientRole == 0
+ clientRole = 'child'
+ else if clientRole == 1
+ clientRole = 'parent'
+
+ if clientRole == '' || !clientRole
+ clientRole = null
+
# subscribe to events from the recording model
@recordingRegistration()
@@ -741,6 +752,8 @@ ConfigureTracksActions = @ConfigureTracksActions
as_musician: true,
tracks: @userTracks,
session_id: @currentSessionId,
+ client_role: clientRole,
+ parent_client_id: parentClientId
audio_latency: context.jamClient.FTUEGetExpectedLatency().latency
})
.done((response) =>
@@ -840,8 +853,11 @@ ConfigureTracksActions = @ConfigureTracksActions
@backendStatsInterval = window.setInterval((() => (@updateBackendStats())), 1000)
updateBackendStats: () ->
- connectionStats = window.jamClient.getConnectionDetail('')
- SessionStatsActions.pushStats(connectionStats)
+ connectionStats = window.jamClient.getConnectionDetail('', false)
+ parentConnectionStats = window.jamClient.getConnectionDetail('', true)
+ #console.log("CONNECTION STATES", connectionStats)
+ #console.log("PARENT STATES", parentConnectionStats)
+ SessionStatsActions.pushStats(connectionStats, parentConnectionStats)
trackChanges: (header, payload) ->
if @currentTrackChanges < payload.track_changes_counter
diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb
index 6ee432d4e..35d3111e2 100644
--- a/web/app/controllers/api_music_sessions_controller.rb
+++ b/web/app/controllers/api_music_sessions_controller.rb
@@ -297,7 +297,9 @@ class ApiMusicSessionsController < ApiController
params[:client_id],
params[:as_musician],
params[:tracks],
- params[:audio_latency]
+ params[:audio_latency],
+ params[:client_role],
+ params[:parent_client_id]
)
if @connection.errors.any?
diff --git a/web/app/views/api_music_sessions/show.rabl b/web/app/views/api_music_sessions/show.rabl
index 4fc73ea8a..2b931e40e 100644
--- a/web/app/views/api_music_sessions/show.rabl
+++ b/web/app/views/api_music_sessions/show.rabl
@@ -50,7 +50,7 @@ else
child(:connections => :participants) {
collection @music_sessions, :object_root => false
- attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id, :metronome_open, :is_jamblaster
+ attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id, :metronome_open, :is_jamblaster, :client_role, :parent_client_id
node :user do |connection|
{ :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state }
diff --git a/web/app/views/dialogs/_recordingFinishedDialog.html.haml b/web/app/views/dialogs/_recordingFinishedDialog.html.haml
index 2fadd425c..17f324423 100644
--- a/web/app/views/dialogs/_recordingFinishedDialog.html.haml
+++ b/web/app/views/dialogs/_recordingFinishedDialog.html.haml
@@ -4,8 +4,11 @@
= image_tag "content/recordbutton-off.png", {:height => 20, :width => 20, :class => 'content-icon'}
%h1 recording finished
.dialog-inner
- Fill out the fields below and click the "SAVE" button to save this recording to your library. If you do not want to
- keep the recording, click the "DISCARD" button.
+ %span.nowait
+ Fill out the fields below and click the "SAVE" button to save this recording to your library. If you do not want to
+ keep the recording, click the "DISCARD" button.
+ %span.pleasewait
+ Please wait while we transfer the necessary audio files from your JamBlaster to your client...
%br/
%br/
%form.left.w40.mr20
@@ -36,7 +39,7 @@
%input{:checked => "checked", :name => "is_public", :type => "checkbox"}/
%label{:for => "is_public"} Public Recording
/
<
- .left.w50.ml30
+ .left.w50.ml30.preview-area
Preview Recording:
\#{render "clients/play_controls"}
diff --git a/web/app/views/users/_user_dropdown.html.erb b/web/app/views/users/_user_dropdown.html.erb
index 31cd39683..3bb28d4b6 100644
--- a/web/app/views/users/_user_dropdown.html.erb
+++ b/web/app/views/users/_user_dropdown.html.erb
@@ -48,7 +48,7 @@
<% end %>
<% if @nativeClient && Rails.application.config.jamblaster_menu %>
-
<%= link_to "JamBlaster", '/client#/jamblaster' %>
+
<%= link_to "JamBlaster Settings", '/client#/jamblaster' %>
<% end %>
<% if current_user && current_user.musician? %>
<%= link_to "Band Setup", '/client#/band/setup/new' %>
diff --git a/websocket-gateway/lib/jam_websockets/router.rb b/websocket-gateway/lib/jam_websockets/router.rb
index 0899281c6..a2e329286 100644
--- a/websocket-gateway/lib/jam_websockets/router.rb
+++ b/websocket-gateway/lib/jam_websockets/router.rb
@@ -740,6 +740,10 @@ module JamWebsockets
ipv4_link_local = options["ipv4_link_local"]
ipv6_link_local = options["ipv6_link_local"]
+ # it's nice to have client_ids not flap in the wind, and we can do that with jamblasters
+ if jamblaster_serial_no && client_id.nil?
+ client_id = jamblaster_serial_no
+ end
# TESTING
#if jamblaster_serial_no.nil?
# jamblaster_serial_no = 'hi'