VRFS-2884 - Update things in session and FTUE for default profile
This commit is contained in:
parent
821ca9d76a
commit
42dac058e1
|
|
@ -273,4 +273,5 @@ drop_position_unique_jam_track.sql
|
|||
recording_client_metadata.sql
|
||||
preview_support_mp3.sql
|
||||
jam_track_duration.sql
|
||||
sales.sql
|
||||
sales.sql
|
||||
show_whats_next_count.sql
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE users ADD COLUMN show_whats_next_count INTEGER NOT NULL DEFAULT 0;
|
||||
|
|
@ -24,11 +24,12 @@ module JamRuby
|
|||
validates :metronome_open, :inclusion => {:in => [true, false]}
|
||||
validates :as_musician, :inclusion => {:in => [true, false, nil]}
|
||||
validates :client_type, :inclusion => {:in => CLIENT_TYPES}
|
||||
validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true
|
||||
validates_numericality_of :last_jam_audio_latency, greater_than: 0, :allow_nil => true
|
||||
validate :can_join_music_session, :if => :joining_session?
|
||||
validate :user_or_latency_tester_present
|
||||
|
||||
after_save :require_at_least_one_track_when_in_session, :if => :joining_session?
|
||||
# this is no longer required with the new no-input profile
|
||||
#after_save :require_at_least_one_track_when_in_session, :if => :joining_session?
|
||||
after_create :did_create
|
||||
after_save :report_add_participant
|
||||
|
||||
|
|
@ -62,11 +63,11 @@ module JamRuby
|
|||
def state_message
|
||||
case self.aasm_state.to_sym
|
||||
when CONNECT_STATE
|
||||
'Connected'
|
||||
when STALE_STATE
|
||||
'Stale'
|
||||
'Connected'
|
||||
when STALE_STATE
|
||||
'Stale'
|
||||
else
|
||||
'Idle'
|
||||
'Idle'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ module JamRuby
|
|||
def joining_session?
|
||||
joining_session
|
||||
end
|
||||
|
||||
|
||||
def can_join_music_session
|
||||
|
||||
# puts "can_join_music_session: #{music_session_id} was #{music_session_id_was}" if music_session_id_changed?
|
||||
|
|
@ -183,8 +184,8 @@ module JamRuby
|
|||
end
|
||||
|
||||
def associate_tracks(tracks)
|
||||
self.tracks.clear()
|
||||
unless tracks.nil?
|
||||
self.tracks.clear()
|
||||
tracks.each do |track|
|
||||
t = Track.new
|
||||
t.instrument = Instrument.find(track["instrument_id"])
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ module JamRuby
|
|||
session_user_history.music_session_id = music_session_id
|
||||
session_user_history.user_id = user_id
|
||||
session_user_history.client_id = client_id
|
||||
session_user_history.instruments = tracks.map {|t| t[:instrument_id]}.join("|")
|
||||
session_user_history.instruments = tracks.map {|t| t[:instrument_id]}.join("|") if tracks
|
||||
session_user_history.save
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# one time init stuff for the /client view
|
||||
|
||||
|
||||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {};
|
||||
|
||||
context.JK.ClientInit = class ClientInit
|
||||
constructor: () ->
|
||||
@logger = context.JK.logger
|
||||
@gearUtils = context.JK.GearUtils
|
||||
|
||||
init: () =>
|
||||
if context.gon.isNativeClient
|
||||
this.nativeClientInit()
|
||||
|
||||
nativeClientInit: () =>
|
||||
@gearUtils.bootstrapDefaultPlaybackProfile();
|
||||
|
|
@ -9,6 +9,9 @@
|
|||
var $dialog = null;
|
||||
var $dontShowAgain = null;
|
||||
var $setupGearBtn = null;
|
||||
var $browserJamTrackBtn = null;
|
||||
var $jamTrackSection = null;
|
||||
var $jamTracksLimitedTime = null;
|
||||
|
||||
function handleStartAudioQualification() {
|
||||
|
||||
|
|
@ -45,6 +48,12 @@
|
|||
return false;
|
||||
})
|
||||
|
||||
$browserJamTrackBtn.click(function() {
|
||||
app.layout.closeDialog('getting-started')
|
||||
window.location = '/client#/jamtrack'
|
||||
return false;
|
||||
})
|
||||
|
||||
$('#getting-started-dialog a.facebook-invite').on('click', function (e) {
|
||||
invitationDialog.showFacebookDialog(e);
|
||||
});
|
||||
|
|
@ -59,13 +68,21 @@
|
|||
}
|
||||
|
||||
function beforeShow() {
|
||||
app.user().done(function(user) {
|
||||
var jamtrackRule = user.free_jamtrack ? 'has-free-jamtrack' : 'no-free-jamtrack'
|
||||
$jamTrackSection.removeClass('has-free-jamtrack').removeClass('no-free-jamtrack').addClass(jamtrackRule)
|
||||
if(user.free_jamtrack) {
|
||||
$jamTracksLimitedTime.removeClass('hidden')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
var showWhatsNext = !$dontShowAgain.is(':checked')
|
||||
app.user().done(function(user) {
|
||||
app.updateUserModel({show_whats_next: showWhatsNext, show_whats_next_count: user.show_whats_next_count + 1})
|
||||
})
|
||||
|
||||
if ($dontShowAgain.is(':checked')) {
|
||||
app.updateUserModel({show_whats_next: false})
|
||||
}
|
||||
}
|
||||
|
||||
function initializeButtons() {
|
||||
|
|
@ -84,6 +101,9 @@
|
|||
$dialog = $('#getting-started-dialog');
|
||||
$dontShowAgain = $dialog.find('#show_getting_started');
|
||||
$setupGearBtn = $dialog.find('.setup-gear-btn')
|
||||
$browserJamTrackBtn = $dialog.find('.browse-jamtrack');
|
||||
$jamTrackSection = $dialog.find('.get-a-free-jamtrack-section')
|
||||
$jamTracksLimitedTime = $dialog.find('.jamtracks-limited-time')
|
||||
|
||||
registerEvents();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
context.JK = context.JK || {};
|
||||
context.JK.SessionSettingsDialog = function(app, sessionScreen) {
|
||||
var logger = context.JK.logger;
|
||||
var gearUtils = context.JK.GearUtilsInstance;
|
||||
var $dialog;
|
||||
var $screen = $('#session-settings');
|
||||
var $selectedFilenames = $screen.find('#selected-filenames');
|
||||
|
|
@ -15,6 +16,8 @@
|
|||
|
||||
function beforeShow(data) {
|
||||
|
||||
var canPlayWithOthers = gearUtils.canPlayWithOthers();
|
||||
|
||||
context.JK.GenreSelectorHelper.render('#session-settings-genre');
|
||||
$dialog = $('[layout-id="session-settings"]');
|
||||
|
||||
|
|
@ -72,6 +75,10 @@
|
|||
context.JK.dropdown($('#session-settings-language'));
|
||||
context.JK.dropdown($('#session-settings-musician-access'));
|
||||
context.JK.dropdown($('#session-settings-fan-access'));
|
||||
|
||||
var easyDropDownState = canPlayWithOthers.canPlay ? 'enable' : 'disable'
|
||||
$('#session-settings-musician-access').easyDropDown(easyDropDownState)
|
||||
$('#session-settings-fan-access').easyDropDown(easyDropDownState)
|
||||
}
|
||||
|
||||
function saveSettings(evt) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.SinglePlayerProfileGuardDialog = class SinglePlayerProfileGuardDialog
|
||||
constructor: (@app) ->
|
||||
@rest = context.JK.Rest()
|
||||
@client = context.jamClient
|
||||
@logger = context.JK.logger
|
||||
@gearUtils = context.JK.GearUtilsInstance
|
||||
@screen = null
|
||||
@dialogId = 'single-player-profile-dialog';
|
||||
@dialog = null;
|
||||
|
||||
initialize:() =>
|
||||
dialogBindings = {
|
||||
'beforeShow' : @beforeShow,
|
||||
'afterShow' : @afterShow
|
||||
}
|
||||
|
||||
@dialog = $('[layout-id="' + @dialogId + '"]');
|
||||
@app.bindDialog(@dialogId, dialogBindings);
|
||||
@content = @dialog.find(".dialog-inner")
|
||||
@audioLatency = @dialog.find('.audio-latency')
|
||||
@btnPrivateSession = @dialog.find('.btn-private-session')
|
||||
@btnGearSetup = @dialog.find('.btn-gear-setup')
|
||||
|
||||
@btnPrivateSession.on('click', @onPrivateSessionChoice)
|
||||
@btnGearSetup.on('click', @onGearSetupChoice)
|
||||
|
||||
beforeShow:() =>
|
||||
@dialog.data('result', { choice: null})
|
||||
|
||||
|
||||
afterShow:() =>
|
||||
canPlayWithOthers = @gearUtils.canPlayWithOthers()
|
||||
|
||||
if canPlayWithOthers.isNoInputProfile
|
||||
@content.removeClass('high-latency').addClass('has-no-inputs')
|
||||
else
|
||||
@content.removeClass('has-no-input').addClass('high-latency')
|
||||
|
||||
latency = '?'
|
||||
if canPlayWithOthers.audioLatency?
|
||||
latency = canPlayWithOthers.audioLatency
|
||||
|
||||
@audioLatency.text("#{latency} milliseconds.")
|
||||
|
||||
onPrivateSessionChoice: () =>
|
||||
@dialog.data('result', { choice: 'private_session'})
|
||||
@app.layout.closeDialog(@dialogId)
|
||||
return false
|
||||
|
||||
onGearSetupChoice: () =>
|
||||
@dialog.data('result', { choice: 'gear_setup'})
|
||||
@app.layout.closeDialog(@dialogId)
|
||||
return false
|
||||
|
|
@ -204,8 +204,7 @@
|
|||
var user = app.user()
|
||||
if(user) {
|
||||
user.done(function(userProfile) {
|
||||
console.log("app.layout.getCurrentScreen() != 'checkoutOrderScreen'", app.layout.getCurrentScreen())
|
||||
if (userProfile.show_whats_next &&
|
||||
if (userProfile.show_whats_next && userProfile.show_whats_next_count < 10 &&
|
||||
window.location.pathname.indexOf(gon.client_path) == 0 &&
|
||||
window.location.pathname.indexOf('/checkout') == -1 &&
|
||||
!app.layout.isDialogShowing('getting-started'))
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@
|
|||
var metronomeBPM=false;
|
||||
var metronomeSound=false;
|
||||
var metronomeMeter=0;
|
||||
var backingTrackPath="";
|
||||
var backingTrackLoop=false;
|
||||
var backingTrackPath = "";
|
||||
var backingTrackLoop = false;
|
||||
var simulateNoInputs = false;
|
||||
|
||||
function dbg(msg) { logger.debug('FakeJamClient: ' + msg); }
|
||||
|
||||
|
|
@ -47,7 +48,13 @@
|
|||
function FTUEPageLeave() {}
|
||||
function FTUECancel() {}
|
||||
function FTUEGetMusicProfileName() {
|
||||
return "FTUEAttempt-1"
|
||||
|
||||
if(simulateNoInputs) {
|
||||
return "System Default (Playback Only)"
|
||||
}
|
||||
else {
|
||||
return "FTUEAttempt-1"
|
||||
}
|
||||
}
|
||||
function FTUESetMusicProfileName() {
|
||||
|
||||
|
|
@ -266,6 +273,10 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
function FTUECreateUpdatePlayBackProfile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function RegisterVolChangeCallBack(functionName) {
|
||||
dbg('RegisterVolChangeCallBack');
|
||||
}
|
||||
|
|
@ -444,6 +455,10 @@
|
|||
];
|
||||
var response = [];
|
||||
for (var i=0; i<mixerIds.length; i++) {
|
||||
|
||||
// for testing no inputs, set simulateNoInputs = true
|
||||
if(simulateNoInputs && i == 2) continue;
|
||||
|
||||
response.push({
|
||||
client_id: clientIds[i],
|
||||
group_id: groups[i],
|
||||
|
|
@ -1012,6 +1027,7 @@
|
|||
this.FTUELoadAudioConfiguration = FTUELoadAudioConfiguration;
|
||||
this.FTUEClearChannelAssignments = FTUEClearChannelAssignments;
|
||||
this.FTUEClearChatInput = FTUEClearChatInput;
|
||||
this.FTUECreateUpdatePlayBackProfile = FTUECreateUpdatePlayBackProfile;
|
||||
|
||||
// Session
|
||||
this.SessionAddTrack = SessionAddTrack;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
context.JK = context.JK || {};
|
||||
|
||||
context.JK.CreateScheduledSession = function(app) {
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var gearUtils = context.JK.GearUtilsInstance;
|
||||
var sessionUtils = context.JK.SessionUtils;
|
||||
var logger = context.JK.logger;
|
||||
var rest = JK.Rest();
|
||||
|
|
@ -597,7 +597,9 @@
|
|||
|
||||
if(willOptionStartSession()) {
|
||||
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
var shouldVerifyNetwork = createSessionSettings.musician_access.value != 'only-rsvp';
|
||||
|
||||
gearUtils.guardAgainstInvalidConfiguration(app, shouldVerifyNetwork)
|
||||
.fail(function() {
|
||||
$btn.removeClass('disabled')
|
||||
app.notify(
|
||||
|
|
@ -908,6 +910,13 @@
|
|||
createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_QUICK_START %>';
|
||||
}
|
||||
|
||||
function optionRequiresMultiplayerProfile() {
|
||||
return createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_START_SCHEDULED%>' ||
|
||||
createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_IMMEDIATE %>' ||
|
||||
createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_RSVP %>' ||
|
||||
createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_SCHEDULE_FUTURE %>';
|
||||
}
|
||||
|
||||
function next(event) {
|
||||
if(willOptionStartSession()) {
|
||||
if(!context.JK.guardAgainstBrowser(app)) {
|
||||
|
|
@ -915,6 +924,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
if(optionRequiresMultiplayerProfile()) {
|
||||
if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var valid = beforeMoveStep();
|
||||
if (!valid) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@
|
|||
var $screen = null;
|
||||
var $mixModeDropdown = null;
|
||||
var $templateMixerModeChange = null;
|
||||
|
||||
var $myTracksNoTracks = null;
|
||||
var $otherAudioContainer = null;
|
||||
var $myTracksContainer = null;
|
||||
var $liveTracksContainer = null;
|
||||
|
|
@ -120,6 +122,9 @@
|
|||
var $liveTracks = null;
|
||||
var $audioTracks = null;
|
||||
var $fluidTracks = null;
|
||||
var $voiceChat = null;
|
||||
var $openFtue = null;
|
||||
var $tracksHolder = null;
|
||||
|
||||
var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
var muteBothMasterAndPersonalGroups = [ChannelGroupIds.AudioInputMusicGroup, ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
|
|
@ -196,53 +201,85 @@
|
|||
// body-scoped drag handlers can go active
|
||||
screenActive = true;
|
||||
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
.fail(function() {
|
||||
promptLeave = false;
|
||||
window.location = '/client#/home'
|
||||
})
|
||||
.done(function(){
|
||||
var result = sessionUtils.SessionPageEnter();
|
||||
rest.getSessionHistory(data.id)
|
||||
.done(function(musicSession) {
|
||||
|
||||
gearUtils.guardAgainstActiveProfileMissing(app, result)
|
||||
.fail(function(data) {
|
||||
var singlePlayerCheckOK = true;
|
||||
// to know whether we are allowed to be in this session, we have to check if we are the creator when checking against single player functionality
|
||||
if(musicSession.user_id != context.JK.currentUserId) {
|
||||
|
||||
var canPlay = context.JK.guardAgainstSinglePlayerProfile(app, function () {
|
||||
promptLeave = false;
|
||||
if(data && data.reason == 'handled') {
|
||||
if(data.nav == 'BACK') {
|
||||
window.history.go(-1);
|
||||
}
|
||||
else {
|
||||
window.location = data.nav;
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/home';
|
||||
}
|
||||
})
|
||||
.done(function(){
|
||||
});
|
||||
|
||||
sessionModel.waitForSessionPageEnterDone()
|
||||
.done(function(userTracks) {
|
||||
singlePlayerCheckOK = canPlay.canPlay;
|
||||
}
|
||||
if(singlePlayerCheckOK) {
|
||||
|
||||
context.JK.CurrentSessionModel.setUserTracks(userTracks);
|
||||
var shouldVerifyNetwork = musicSession.musician_access;
|
||||
gearUtils.guardAgainstInvalidConfiguration(app, shouldVerifyNetwork)
|
||||
.fail(function() {
|
||||
promptLeave = false;
|
||||
window.location = '/client#/home'
|
||||
})
|
||||
.done(function(){
|
||||
var result = sessionUtils.SessionPageEnter();
|
||||
|
||||
initializeSession();
|
||||
})
|
||||
.fail(function(data) {
|
||||
if(data == "timeout") {
|
||||
context.JK.alertSupportedNeeded('The audio system has not reported your configured tracks in a timely fashion.')
|
||||
}
|
||||
else if(data == 'session_over') {
|
||||
// do nothing; session ended before we got the user track info. just bail
|
||||
}
|
||||
else {
|
||||
contetx.JK.alertSupportedNeeded('Unable to determine configured tracks due to reason: ' + data)
|
||||
}
|
||||
gearUtils.guardAgainstActiveProfileMissing(app, result)
|
||||
.fail(function(data) {
|
||||
promptLeave = false;
|
||||
if(data && data.reason == 'handled') {
|
||||
if(data.nav == 'BACK') {
|
||||
window.history.go(-1);
|
||||
}
|
||||
else {
|
||||
window.location = data.nav;
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/home';
|
||||
}
|
||||
})
|
||||
.done(function(){
|
||||
|
||||
sessionModel.waitForSessionPageEnterDone()
|
||||
.done(function(userTracks) {
|
||||
|
||||
context.JK.CurrentSessionModel.setUserTracks(userTracks);
|
||||
|
||||
initializeSession();
|
||||
})
|
||||
.fail(function(data) {
|
||||
if(data == "timeout") {
|
||||
context.JK.alertSupportedNeeded('The audio system has not reported your configured tracks in a timely fashion.')
|
||||
}
|
||||
else if(data == 'session_over') {
|
||||
// do nothing; session ended before we got the user track info. just bail
|
||||
}
|
||||
else {
|
||||
context.JK.alertSupportedNeeded('Unable to determine configured tracks due to reason: ' + data)
|
||||
}
|
||||
promptLeave = false;
|
||||
window.location = '/client#/home'
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
if(canPlay.dialog) {
|
||||
canPlay.dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||
if(data.canceled) {
|
||||
promptLeave = false;
|
||||
window.location = '/client#/home'
|
||||
});
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function notifyWithUserInfo(title , text, clientId) {
|
||||
|
|
@ -635,7 +672,6 @@
|
|||
function renderSession() {
|
||||
$myTracksContainer.empty();
|
||||
$('.session-track').remove(); // Remove previous tracks
|
||||
var $voiceChat = $('#voice-chat');
|
||||
$voiceChat.hide();
|
||||
_updateMixers();
|
||||
_renderTracks();
|
||||
|
|
@ -933,7 +969,6 @@
|
|||
if(voiceChatMixers) {
|
||||
var mixer = voiceChatMixers.mixer;
|
||||
|
||||
var $voiceChat = $('#voice-chat');
|
||||
$voiceChat.show();
|
||||
$voiceChat.attr('mixer-id', mixer.id);
|
||||
var $voiceChatGain = $voiceChat.find('.voicechat-gain');
|
||||
|
|
@ -1654,79 +1689,87 @@
|
|||
|
||||
var myTrack = app.clientId == participant.client_id;
|
||||
|
||||
// special case; if it's me and I have no tracks, show info about this sort of use of the app
|
||||
if (myTrack && participant.tracks.length == 0) {
|
||||
$tracksHolder.addClass('no-local-tracks')
|
||||
}
|
||||
else {
|
||||
$tracksHolder.removeClass('no-local-tracks')
|
||||
}
|
||||
|
||||
// loop through all tracks for each participant
|
||||
$.each(participant.tracks, function(index, track) {
|
||||
var instrumentIcon = context.JK.getInstrumentIcon45(track.instrument_id);
|
||||
var photoUrl = context.JK.resolveAvatarUrl(participant.user.photo_url);
|
||||
$.each(participant.tracks, function (index, track) {
|
||||
var instrumentIcon = context.JK.getInstrumentIcon45(track.instrument_id);
|
||||
var photoUrl = context.JK.resolveAvatarUrl(participant.user.photo_url);
|
||||
|
||||
// Default trackData to participant + no Mixer state.
|
||||
var trackData = {
|
||||
trackId: track.id,
|
||||
connection_id: track.connection_id,
|
||||
client_track_id: track.client_track_id,
|
||||
client_resource_id: track.client_resource_id,
|
||||
clientId: participant.client_id,
|
||||
name: name,
|
||||
instrumentIcon: instrumentIcon,
|
||||
avatar: photoUrl,
|
||||
latency: "good",
|
||||
gainPercent: 0,
|
||||
muteClass: 'muted',
|
||||
mixerId: "",
|
||||
avatarClass: 'avatar-med',
|
||||
preMasteredClass: "",
|
||||
myTrack: myTrack
|
||||
};
|
||||
// Default trackData to participant + no Mixer state.
|
||||
var trackData = {
|
||||
trackId: track.id,
|
||||
connection_id: track.connection_id,
|
||||
client_track_id: track.client_track_id,
|
||||
client_resource_id: track.client_resource_id,
|
||||
clientId: participant.client_id,
|
||||
name: name,
|
||||
instrumentIcon: instrumentIcon,
|
||||
avatar: photoUrl,
|
||||
latency: "good",
|
||||
gainPercent: 0,
|
||||
muteClass: 'muted',
|
||||
mixerId: "",
|
||||
avatarClass: 'avatar-med',
|
||||
preMasteredClass: "",
|
||||
myTrack: myTrack
|
||||
};
|
||||
|
||||
var mixerData = findMixerForTrack(participant.client_id, track, myTrack)
|
||||
var mixer = mixerData.mixer;
|
||||
var vuMixer = mixerData.vuMixer;
|
||||
var muteMixer = mixerData.muteMixer;
|
||||
var oppositeMixer = mixerData.oppositeMixer;
|
||||
var mixerData = findMixerForTrack(participant.client_id, track, myTrack)
|
||||
var mixer = mixerData.mixer;
|
||||
var vuMixer = mixerData.vuMixer;
|
||||
var muteMixer = mixerData.muteMixer;
|
||||
var oppositeMixer = mixerData.oppositeMixer;
|
||||
|
||||
|
||||
|
||||
if (mixer && oppositeMixer) {
|
||||
myTrack = (mixer.group_id === ChannelGroupIds.AudioInputMusicGroup);
|
||||
if(!myTrack) {
|
||||
// it only makes sense to track 'audio established' for tracks that don't belong to you
|
||||
sessionModel.setAudioEstablished(participant.client_id, true);
|
||||
}
|
||||
|
||||
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;
|
||||
trackData.vuMixerId = vuMixer.id;
|
||||
trackData.oppositeMixer = oppositeMixer;
|
||||
trackData.muteMixerId = muteMixer.id;
|
||||
trackData.noaudio = false;
|
||||
trackData.group_id = mixer.group_id;
|
||||
context.jamClient.SessionSetUserName(participant.client_id,name);
|
||||
|
||||
} else { // No mixer to match, yet
|
||||
lookingForMixers.push({track: track, clientId: participant.client_id})
|
||||
trackData.noaudio = true;
|
||||
if (!(lookingForMixersTimer)) {
|
||||
logger.debug("waiting for mixer to show up for track: " + track.id)
|
||||
lookingForMixersTimer = context.setInterval(lookForMixers, 500);
|
||||
}
|
||||
if (mixer && oppositeMixer) {
|
||||
myTrack = (mixer.group_id === ChannelGroupIds.AudioInputMusicGroup);
|
||||
if (!myTrack) {
|
||||
// it only makes sense to track 'audio established' for tracks that don't belong to you
|
||||
sessionModel.setAudioEstablished(participant.client_id, true);
|
||||
}
|
||||
|
||||
var allowDelete = myTrack && index > 0;
|
||||
_addTrack(allowDelete, trackData, mixer, oppositeMixer);
|
||||
|
||||
// Show settings icons only for my tracks
|
||||
if (myTrack) {
|
||||
myTracks.push(trackData);
|
||||
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;
|
||||
trackData.vuMixerId = vuMixer.id;
|
||||
trackData.oppositeMixer = oppositeMixer;
|
||||
trackData.muteMixerId = muteMixer.id;
|
||||
trackData.noaudio = false;
|
||||
trackData.group_id = mixer.group_id;
|
||||
context.jamClient.SessionSetUserName(participant.client_id, name);
|
||||
|
||||
} else { // No mixer to match, yet
|
||||
lookingForMixers.push({track: track, clientId: participant.client_id})
|
||||
trackData.noaudio = true;
|
||||
if (!(lookingForMixersTimer)) {
|
||||
logger.debug("waiting for mixer to show up for track: " + track.id)
|
||||
lookingForMixersTimer = context.setInterval(lookForMixers, 500);
|
||||
}
|
||||
}
|
||||
|
||||
var allowDelete = myTrack && index > 0;
|
||||
_addTrack(allowDelete, trackData, mixer, oppositeMixer);
|
||||
|
||||
// Show settings icons only for my tracks
|
||||
if (myTrack) {
|
||||
myTracks.push(trackData);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
configureTrackDialog = new context.JK.ConfigureTrackDialog(app, myTracks, sessionId, sessionModel);
|
||||
|
|
@ -1879,14 +1922,14 @@
|
|||
if (!(mixer.stereo)) { // mono track
|
||||
if (mixerId.substr(-4) === "_vul") {
|
||||
// Do the left
|
||||
selector = $('#tracks [mixer-id="' + pureMixerId + '_vul"]');
|
||||
selector = $tracksHolder.find('[mixer-id="' + pureMixerId + '_vul"]');
|
||||
context.JK.VuHelpers.updateVU(selector, value);
|
||||
// Do the right
|
||||
selector = $('#tracks [mixer-id="' + pureMixerId + '_vur"]');
|
||||
selector = $tracksHolder.find('[mixer-id="' + pureMixerId + '_vur"]');
|
||||
context.JK.VuHelpers.updateVU(selector, value);
|
||||
} // otherwise, it's a mono track, _vur event - ignore.
|
||||
} else { // stereo track
|
||||
selector = $('#tracks [mixer-id="' + mixerId + '"]');
|
||||
selector = $tracksHolder.find('[mixer-id="' + mixerId + '"]');
|
||||
context.JK.VuHelpers.updateVU(selector, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -3025,11 +3068,16 @@
|
|||
return true;
|
||||
}
|
||||
|
||||
function showFTUEWhenNoInputs( ) {
|
||||
//app.afterFtue = function() { window.location.reload };
|
||||
app.layout.startNewFtue();
|
||||
}
|
||||
|
||||
function events() {
|
||||
$('#session-leave').on('click', sessionLeave);
|
||||
$('#session-resync').on('click', sessionResync);
|
||||
$('#session-contents').on("click", '[action="delete"]', deleteSession);
|
||||
$('#tracks').on('click', 'div[control="mute"]', toggleMute);
|
||||
$tracksHolder.on('click', 'div[control="mute"]', toggleMute);
|
||||
$('#recording-start-stop').on('click', startStopRecording);
|
||||
$('#open-a-recording').on('click', openRecording);
|
||||
$('#open-a-jamtrack').on('click', openJamTrack);
|
||||
|
|
@ -3038,11 +3086,24 @@
|
|||
$('#session-invite-musicians').on('click', inviteMusicians);
|
||||
$('#session-invite-musicians2').on('click', inviteMusicians);
|
||||
$('#track-settings').click(function() {
|
||||
|
||||
if(gearUtils.isNoInputProfile()) {
|
||||
// show FTUE
|
||||
showFTUEWhenNoInputs();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
configureTrackDialog.refresh();
|
||||
configureTrackDialog.showVoiceChatPanel(true);
|
||||
configureTrackDialog.showMusicAudioPanel(true);
|
||||
}
|
||||
});
|
||||
|
||||
$openFtue.click(function() {
|
||||
showFTUEWhenNoInputs();
|
||||
return false;
|
||||
})
|
||||
|
||||
$closePlaybackRecording.on('click', closeOpenMedia);
|
||||
$(playbackControls)
|
||||
.on('pause', onPause)
|
||||
|
|
@ -3083,6 +3144,8 @@
|
|||
$mixModeDropdown = $screen.find('select.monitor-mode')
|
||||
$templateMixerModeChange = $('#template-mixer-mode-change');
|
||||
$otherAudioContainer = $('#session-recordedtracks-container');
|
||||
$myTracksNoTracks = $('#session-mytracks-notracks')
|
||||
$openFtue = $screen.find('.open-ftue-no-tracks')
|
||||
$myTracksContainer = $('#session-mytracks-container')
|
||||
$liveTracksContainer = $('#session-livetracks-container');
|
||||
$closePlaybackRecording = $('#close-playback-recording')
|
||||
|
|
@ -3093,7 +3156,9 @@
|
|||
$myTracks = $screen.find('.session-mytracks');
|
||||
$liveTracks = $screen.find('.session-livetracks');
|
||||
$audioTracks = $screen.find('.session-recordings');
|
||||
$fluidTracks = $screen.find('.session-fluidtracks')
|
||||
$fluidTracks = $screen.find('.session-fluidtracks');
|
||||
$voiceChat = $screen.find('#voice-chat');
|
||||
$tracksHolder = $screen.find('#tracks')
|
||||
|
||||
events();
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
var ALERT_TYPES = context.JK.ALERT_TYPES;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var MIX_MODES = context.JK.MIX_MODES;
|
||||
var gearUtils = context.JK.GearUtilsInstance;
|
||||
|
||||
var userTracks = null; // comes from the backend
|
||||
var clientId = client.clientID;
|
||||
|
|
@ -213,7 +214,8 @@
|
|||
|
||||
// see if we already have tracks; if so, we need to run with these
|
||||
var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
if(inputTracks.length > 0) {
|
||||
|
||||
if(inputTracks.length > 0 || gearUtils.isNoInputProfile() ) {
|
||||
logger.debug("on page enter, tracks are already available")
|
||||
sessionPageEnterDeferred.resolve(inputTracks);
|
||||
var deferred = sessionPageEnterDeferred;
|
||||
|
|
|
|||
|
|
@ -136,18 +136,20 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
.fail(function() {
|
||||
app.notify(
|
||||
{ title: "Unable to Join Session",
|
||||
text: "You can only join a session once you have working audio gear and a tested internet connection."
|
||||
});
|
||||
})
|
||||
.done(function() {
|
||||
if (successCallback) {
|
||||
successCallback();
|
||||
}
|
||||
});
|
||||
if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay) {
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
.fail(function() {
|
||||
app.notify(
|
||||
{ title: "Unable to Join Session",
|
||||
text: "You can only join a session once you have working audio gear and a tested internet connection."
|
||||
});
|
||||
})
|
||||
.done(function() {
|
||||
if (successCallback) {
|
||||
successCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sessionUtils.joinSession = function(sessionId) {
|
||||
|
|
|
|||
|
|
@ -1111,7 +1111,7 @@
|
|||
|
||||
context.JK.guardAgainstBrowser = function(app, args) {
|
||||
if(!gon.isNativeClient) {
|
||||
logger.debug("guarding against normal browser on screen thaht requires native client")
|
||||
logger.debug("guarding against normal browser on screen that requires native client")
|
||||
app.layout.showDialog('launch-app-dialog', args)
|
||||
.one(EVENTS.DIALOG_CLOSED, function() {
|
||||
if(args && args.goHome) {
|
||||
|
|
@ -1124,6 +1124,111 @@
|
|||
return true;
|
||||
}
|
||||
|
||||
context.JK.guardAgainstSinglePlayerProfile = function(app, beforeCallback) {
|
||||
|
||||
var canPlayWithOthers = context.JK.GearUtilsInstance.canPlayWithOthers();
|
||||
|
||||
if(!canPlayWithOthers.canPlay) {
|
||||
logger.debug("guarding against single player profile")
|
||||
|
||||
var $dialog = app.layout.showDialog('single-player-profile-dialog');
|
||||
|
||||
// so that callers can check dialog result
|
||||
canPlayWithOthers.dialog = $dialog;
|
||||
|
||||
// allow callers to take action before default behavior
|
||||
if(beforeCallback) {
|
||||
$dialog.one(EVENTS.DIALOG_CLOSED, beforeCallback);
|
||||
}
|
||||
|
||||
$dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||
|
||||
if(!data.canceled) {
|
||||
if(data.result.choice == 'private_session') {
|
||||
var data = {
|
||||
createType: 'quick-start',
|
||||
timezone: {},
|
||||
recurring_mode: {},
|
||||
language: {},
|
||||
band: {},
|
||||
musician_access: {},
|
||||
fans_access: {},
|
||||
rsvp_slots: [],
|
||||
open_rsvps: false
|
||||
};
|
||||
|
||||
context.JK.privateSessionSettings(data)
|
||||
|
||||
context.JK.createSession(app, data)
|
||||
.done(function(response) {
|
||||
var sessionId = response.id;
|
||||
|
||||
context.JK.GA.trackSessionCount(true, true, 0);
|
||||
|
||||
// we redirect to the session screen, which handles the REST call to POST /participants.
|
||||
logger.debug("joining session screen: " + sessionId)
|
||||
context.location = '/client#/session/' + sessionId;
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
logger.debug("unable to schedule a private session")
|
||||
app.notifyServerError(jqXHR, "Unable to schedule a private session");
|
||||
})
|
||||
}
|
||||
else if(data.result.choice == 'gear_setup') {
|
||||
window.location = '/client#/account/audio'
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error("unknown choice: " + data.result.choice)
|
||||
alert("unknown choice: " + data.result.choice)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return canPlayWithOthers;
|
||||
}
|
||||
|
||||
context.JK.createSession = function(app, data) {
|
||||
|
||||
// auto pick an 'other' instrument
|
||||
var otherId = context.JK.server_to_client_instrument_map.Other.server_id; // get server ID
|
||||
var otherInstrumentInfo = context.JK.instrument_id_to_instrument[otherId]; // get display name
|
||||
var beginnerLevel = 1; // default to beginner
|
||||
var instruments = [ {id: otherId, name: otherInstrumentInfo.display, level: beginnerLevel} ];
|
||||
$.each(instruments, function(index, instrument) {
|
||||
var slot = {};
|
||||
slot.instrument_id = instrument.id;
|
||||
slot.proficiency_level = instrument.level;
|
||||
slot.approve = true;
|
||||
data.rsvp_slots.push(slot);
|
||||
});
|
||||
|
||||
data.isUnstructuredRsvp = true;
|
||||
|
||||
return rest.createScheduledSession(data)
|
||||
}
|
||||
|
||||
context.JK.privateSessionSettings = function(createSessionSettings) {
|
||||
createSessionSettings.genresValues = ['Pop'];
|
||||
createSessionSettings.genres = ['pop'];
|
||||
createSessionSettings.timezone = 'Central Time (US & Canada),America/Chicago'
|
||||
createSessionSettings.name = "Private Test Session";
|
||||
createSessionSettings.description = "Private session set up just to test things out in the session interface by myself.";
|
||||
createSessionSettings.notations = [];
|
||||
createSessionSettings.language = 'eng'
|
||||
createSessionSettings.legal_policy = 'Standard';
|
||||
createSessionSettings.musician_access = false
|
||||
createSessionSettings.fan_access = false
|
||||
createSessionSettings.fan_chat = false
|
||||
createSessionSettings.approval_required = false
|
||||
createSessionSettings.legal_terms = true
|
||||
createSessionSettings.recurring_mode = 'once';
|
||||
createSessionSettings.start = new Date().toDateString() + ' ' + context.JK.formatUtcTime(new Date(), false);
|
||||
createSessionSettings.duration = "60";
|
||||
createSessionSettings.open_rsvps = false
|
||||
createSessionSettings.rsvp_slots = [];
|
||||
}
|
||||
/*
|
||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
|
|
|
|||
|
|
@ -176,6 +176,10 @@
|
|||
wizard.setBackState(enabled);
|
||||
}
|
||||
|
||||
function moveToNext() {
|
||||
wizard.moveToNext();
|
||||
}
|
||||
|
||||
function setChosenInputs(_inputs) {
|
||||
inputs = _inputs;
|
||||
}
|
||||
|
|
@ -222,6 +226,7 @@
|
|||
this.getChosenInputs = getChosenInputs;
|
||||
this.setNextState = setNextState;
|
||||
this.setBackState = setBackState;
|
||||
this.moveToNext = moveToNext;
|
||||
this.initialize = initialize;
|
||||
this.createFTUEProfile = createFTUEProfile;
|
||||
this.getWizard = function() {return wizard; }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
var logger = context.JK.logger;
|
||||
var networkTest = new context.JK.NetworkTest(app);
|
||||
var $step = null;
|
||||
|
||||
// if not null and with in say 5 seconds, then the user is 'NEXT'ing too quickly. slow them down
|
||||
var clickFastTime = null;
|
||||
|
||||
function getLastNetworkFailAnalytics() {
|
||||
return networkTest.getLastNetworkFailure();
|
||||
|
|
@ -36,13 +37,29 @@
|
|||
initializeBackButtonState();
|
||||
}
|
||||
function initializeNextButtonState() {
|
||||
dialog.setNextState(networkTest.hasScoredNetworkSuccessfully() && !networkTest.isScoring());
|
||||
dialog.setNextState(!networkTest.isScoring());
|
||||
}
|
||||
|
||||
function initializeBackButtonState() {
|
||||
dialog.setBackState(!networkTest.isScoring());
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
// if we don't have a valid score, and if it's been less than 5 seconds since we've shown this step, slow the user down
|
||||
if (context.jamClient.GetNetworkTestScore() < 1 && userIsFastNexting()) {
|
||||
context.JK.Banner.showYesNo({
|
||||
html: "By clicking NEXT and skipping the test, you won't be able to play online in real-time sessions with others. Is this OK?",
|
||||
yes: function() {
|
||||
dialog.moveToNext();
|
||||
}});
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function handleHelp() {
|
||||
return "https://jamkazam.desk.com/customer/portal/articles/1716139-what-to-do-if-you-cannot-pass-the-network-test"
|
||||
//return "https://jamkazam.desk.com/customer/portal/articles/1599969-first-time-setup---step-6---test-your-network";
|
||||
|
|
@ -57,6 +74,16 @@
|
|||
networkTest.haltScoring();
|
||||
networkTest.cancel();
|
||||
updateButtons();
|
||||
watchForFastNexting();
|
||||
}
|
||||
|
||||
// fast nexting is a someone hitting next very quickly
|
||||
function watchForFastNexting() {
|
||||
clickFastTime = new Date();
|
||||
}
|
||||
|
||||
function userIsFastNexting() {
|
||||
return new Date().getTime() - clickFastTime.getTime() < 5000
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
|
|
@ -77,6 +104,7 @@
|
|||
this.handleHelp = handleHelp;
|
||||
this.newSession = newSession;
|
||||
this.beforeHide = beforeHide;
|
||||
this.handleNext = handleNext;
|
||||
this.beforeShow = beforeShow;
|
||||
this.initialize = initialize;
|
||||
this.getLastNetworkFailAnalytics = getLastNetworkFailAnalytics;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
var $templateDeviceNotValid = null;
|
||||
var $resyncStatus = null;
|
||||
var $resyncStatusText = null;
|
||||
var $latencyScoreBox = null;
|
||||
var $highLatencyNotice = null;
|
||||
|
||||
|
||||
var operatingSystem = null;
|
||||
|
|
@ -579,6 +581,11 @@
|
|||
function initializeResync() {
|
||||
$resyncBtn.unbind('click').click(function () {
|
||||
|
||||
if($highLatencyNotice) {
|
||||
$highLatencyNotice.btOff()
|
||||
$highLatencyNotice = null;
|
||||
}
|
||||
|
||||
scheduleRescanSystem(function() {
|
||||
if (getSelectedInputs().length > 0 && getSelectedOutputs().length == 2) {
|
||||
logger.debug("after rescan, ready to attempt score")
|
||||
|
|
@ -946,6 +953,21 @@
|
|||
queueUpdateDeviceList = false;
|
||||
updateDeviceList();
|
||||
}
|
||||
|
||||
if(!data.validLatencyScore) {
|
||||
if (selectedDeviceInfo.input.info.type.indexOf('Win32_asio') > -1) {
|
||||
prodUserAboutHighLatency($latencyScoreBox, 'asio')
|
||||
}
|
||||
else if (selectedDeviceInfo.output.info.type.indexOf('Win32_asio') > -1) {
|
||||
prodUserAboutHighLatency($latencyScoreBox, 'asio')
|
||||
}
|
||||
else if (selectedDeviceInfo.input.info.type == 'MacOSX_builtin' || selectedDeviceInfo.output.info.type == 'MacOSX_builtin') {
|
||||
prodUserAboutHighLatency($latencyScoreBox, 'macosx-builtin')
|
||||
}
|
||||
else {
|
||||
prodUserAboutHighLatency($latencyScoreBox, 'generic')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLastAudioTestFailAnalytics() {
|
||||
|
|
@ -962,6 +984,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
function prodUserAboutHighLatency($btn, additional) {
|
||||
|
||||
setTimeout(function() {
|
||||
$highLatencyNotice = context.JK.prodBubble($btn, 'high-latency-notice', {additional: additional}, {duration: 20000, width:'400px', positions:['top']});
|
||||
}, 300)
|
||||
}
|
||||
|
||||
function prodUserToTweakASIOSettings($btn) {
|
||||
setTimeout(function() {
|
||||
context.JK.prodBubble($btn, 'tweak-asio-settings', {}, {positions:['top']});
|
||||
|
|
@ -972,19 +1001,11 @@
|
|||
renderScoringStopped();
|
||||
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
|
||||
|
||||
if(data.reason == "latency") {
|
||||
if(data.reason == "io") {
|
||||
|
||||
console.log("selectedDeviceInfo", selectedDeviceInfo)
|
||||
if(selectedDeviceInfo.input.info.type.indexOf('Win32_asio') > -1) {
|
||||
prodUserToTweakASIOSettings($asioInputControlBtn)
|
||||
}
|
||||
else if(selectedDeviceInfo.output.info.type.indexOf('Win32_asio') > -1) {
|
||||
prodUserToTweakASIOSettings($asioOutputControlBtn)
|
||||
}
|
||||
|
||||
storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.latency, data.latencyScore);
|
||||
}
|
||||
else if(data.reason = "io") {
|
||||
//storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.latency, data.latencyScore);
|
||||
|
||||
if(data.ioTarget == 'bad') {
|
||||
storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.ioTarget, data.ioTargetScore);
|
||||
}
|
||||
|
|
@ -1210,6 +1231,7 @@
|
|||
$instructions = $step.find('.instructions');
|
||||
$resyncStatus = $step.find('.resync-status');
|
||||
$resyncStatusText = $step.find('.resynctext');
|
||||
$latencyScoreBox = $step.find('.latency-score-section')
|
||||
operatingSystem = context.JK.GetOSAsString();
|
||||
frameBuffers.initialize($knobs);
|
||||
$(frameBuffers)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
var GEAR_TEST_INVALIDATED_ASYNC = "gear_test.async_invalidated"; // happens when backend alerts us device is invalid
|
||||
|
||||
function isGoodFtue() {
|
||||
return validLatencyScore && validIOScore && !asynchronousInvalidDevice;
|
||||
return validIOScore && !asynchronousInvalidDevice;
|
||||
}
|
||||
|
||||
function processIOScore(io) {
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
|
||||
// now base the overall IO score based on both values.
|
||||
|
||||
$self.triggerHandler(GEAR_TEST_IO_DONE, {std:std, median:median, io:io, aggregrateIOClass: aggregrateIOClass, medianIOClass : medianIOClass, stdIOClass: stdIOClass})
|
||||
$self.triggerHandler(GEAR_TEST_IO_DONE, {std:std, median:median, io:io, aggregrateIOClass: aggregrateIOClass, medianIOClass : medianIOClass, stdIOClass: stdIOClass, validLatencyScore: validLatencyScore})
|
||||
//renderIOScore(std, median, io, aggregrateIOClass, medianIOClass, stdIOClass);
|
||||
|
||||
if(aggregrateIOClass == "bad") {
|
||||
|
|
@ -103,10 +103,10 @@
|
|||
scoring = false;
|
||||
|
||||
if(isGoodFtue()) {
|
||||
$self.triggerHandler(GEAR_TEST_DONE)
|
||||
$self.triggerHandler(GEAR_TEST_DONE, {validLatencyScore: validLatencyScore})
|
||||
}
|
||||
else {
|
||||
$self.triggerHandler(GEAR_TEST_FAIL, {reason:'io', ioTarget: medianIOClass, ioTargetScore: median, ioVariance: stdIOClass, ioVarianceScore: std});
|
||||
$self.triggerHandler(GEAR_TEST_FAIL, {reason:'io', ioTarget: medianIOClass, ioTargetScore: median, ioVariance: stdIOClass, ioVarianceScore: std, validLatencyScore: validLatencyScore});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,11 +182,10 @@
|
|||
|
||||
updateScoreReport(latency, refocused);
|
||||
|
||||
// if there was a valid latency score, go on to the next step
|
||||
if (validLatencyScore) {
|
||||
if (true || validLatencyScore) {
|
||||
$self.triggerHandler(GEAR_TEST_IO_START);
|
||||
// reuse valid IO score if this is on refocus
|
||||
if(refocused && validIOScore) {
|
||||
if(false && (refocused && validIOScore)) {
|
||||
processIOScore(ioScore);
|
||||
}
|
||||
else {
|
||||
|
|
@ -215,12 +214,12 @@
|
|||
}
|
||||
else {
|
||||
scoring = false;
|
||||
$self.triggerHandler(GEAR_TEST_FAIL, {reason:'latency', latencyScore: latencyScore.latency})
|
||||
$self.triggerHandler(GEAR_TEST_FAIL, {reason:'latency', validLatencyScore: validLatencyScore, latencyScore: latencyScore.latency})
|
||||
}
|
||||
})
|
||||
.fail(function(ftueSaveResult) {
|
||||
scoring = false;
|
||||
$self.triggerHandler(GEAR_TEST_FAIL, {reason:'invalid_configuration', data: ftueSaveResult})
|
||||
$self.triggerHandler(GEAR_TEST_FAIL, {reason:'invalid_configuration', validLatencyScore: validLatencyScore, data: ftueSaveResult})
|
||||
})
|
||||
}, 250);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
var VOICE_CHAT = context.JK.VOICE_CHAT;
|
||||
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var SYSTEM_DEFAULT_PLAYBACK_ONLY = 'System Default (Playback Only)';
|
||||
|
||||
|
||||
context.JK.GearUtilsInstance = gearUtils;
|
||||
|
||||
|
|
@ -28,12 +30,42 @@
|
|||
return channel.assignment == ASSIGNMENT.CHAT || channel.assignment == ASSIGNMENT.OUTPUT || channel.assignment > 0;
|
||||
}
|
||||
|
||||
// to play with others, you have to have inputs,
|
||||
// as well have a score below 20 ms
|
||||
gearUtils.canPlayWithOthers = function(profile) {
|
||||
|
||||
gearUtils.createProfileName = function(deviceInfo, chatName) {
|
||||
var isNoInputProfile = gearUtils.isNoInputProfile(profile);
|
||||
var expectedLatency = context.jamClient.FTUEGetExpectedLatency();
|
||||
var audioLatency = expectedLatency ? expectedLatency.latency : null;
|
||||
var highLatency = audioLatency > 20;
|
||||
var networkScore = context.jamClient.GetNetworkTestScore();
|
||||
var badNetworkScore = networkScore < 2;
|
||||
|
||||
return {
|
||||
canPlay: !isNoInputProfile && !highLatency,
|
||||
isNoInputProfile: isNoInputProfile,
|
||||
badNetworkScore: badNetworkScore,
|
||||
highLatency: highLatency,
|
||||
audioLatency: audioLatency,
|
||||
networkScore: networkScore,
|
||||
}
|
||||
}
|
||||
|
||||
gearUtils.isNoInputProfile = function(profile) {
|
||||
if (profile === undefined) {
|
||||
profile = context.jamClient.FTUEGetMusicProfileName();
|
||||
}
|
||||
|
||||
if(profile == SYSTEM_DEFAULT_PLAYBACK_ONLY) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
gearUtils.createProfileName = function (deviceInfo, chatName) {
|
||||
var isSameInOut = deviceInfo.input.id == deviceInfo.output.id;
|
||||
|
||||
var name = null;
|
||||
if(isSameInOut) {
|
||||
if (isSameInOut) {
|
||||
name = "In/Out: " + deviceInfo.input.info.displayName;
|
||||
}
|
||||
else {
|
||||
|
|
@ -45,19 +77,19 @@
|
|||
}
|
||||
|
||||
|
||||
gearUtils.selectedDeviceInfo = function(audioInputDeviceId, audioOutputDeviceId, deviceInformation) {
|
||||
gearUtils.selectedDeviceInfo = function (audioInputDeviceId, audioOutputDeviceId, deviceInformation) {
|
||||
|
||||
|
||||
if(!audioInputDeviceId) {
|
||||
if (!audioInputDeviceId) {
|
||||
logger.debug("gearUtils.selectedDeviceInfo: no active input device");
|
||||
return null;
|
||||
}
|
||||
if(!audioOutputDeviceId) {
|
||||
if (!audioOutputDeviceId) {
|
||||
logger.debug("gearUtils.selectedDeviceInfo: no active output device");
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!deviceInformation) {
|
||||
if (!deviceInformation) {
|
||||
deviceInformation = gearUtils.loadDeviceInfo();
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +113,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
gearUtils.loadDeviceInfo = function() {
|
||||
gearUtils.loadDeviceInfo = function () {
|
||||
|
||||
var operatingSystem = context.JK.GetOSAsString();
|
||||
// should return one of:
|
||||
|
|
@ -128,6 +160,10 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (device.name == "JamKazam Virtual Input") {
|
||||
return;
|
||||
}
|
||||
|
||||
var deviceInfo = {};
|
||||
|
||||
deviceInfo.id = device.guid;
|
||||
|
|
@ -145,22 +181,22 @@
|
|||
return loadedDevices;
|
||||
}
|
||||
|
||||
gearUtils.updateDefaultBuffers = function(selectedDeviceInfo, frameBuffers) {
|
||||
gearUtils.updateDefaultBuffers = function (selectedDeviceInfo, frameBuffers) {
|
||||
function hasWDMAssociated() {
|
||||
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')
|
||||
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')
|
||||
}
|
||||
|
||||
function hasASIOAssociated() {
|
||||
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_asio' || selectedDeviceInfo.output.info.type == 'Win32_asio')
|
||||
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_asio' || selectedDeviceInfo.output.info.type == 'Win32_asio')
|
||||
}
|
||||
|
||||
// handle specific framesize settings
|
||||
if(hasWDMAssociated() || hasASIOAssociated()) {
|
||||
if (hasWDMAssociated() || hasASIOAssociated()) {
|
||||
var framesize = frameBuffers.selectedFramesize();
|
||||
|
||||
if(framesize == 2.5) {
|
||||
if (framesize == 2.5) {
|
||||
// if there is a WDM device, start off at 1/1 due to empirically observed issues with 0/0
|
||||
if(hasWDMAssociated()) {
|
||||
if (hasWDMAssociated()) {
|
||||
logger.debug("setting default buffers to 1/1");
|
||||
frameBuffers.setBufferIn('1');
|
||||
frameBuffers.setBufferOut('1');
|
||||
|
|
@ -172,7 +208,7 @@
|
|||
frameBuffers.setBufferOut('0');
|
||||
}
|
||||
}
|
||||
else if(framesize == 5) {
|
||||
else if (framesize == 5) {
|
||||
logger.debug("setting default buffers to 3/2");
|
||||
frameBuffers.setBufferIn('3');
|
||||
frameBuffers.setBufferOut('2');
|
||||
|
|
@ -193,7 +229,7 @@
|
|||
context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
|
||||
}
|
||||
|
||||
gearUtils.ftueSummary = function(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated) {
|
||||
gearUtils.ftueSummary = function (operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated) {
|
||||
return {
|
||||
os: operatingSystem,
|
||||
version: context.jamClient.ClientUpdateVersion(),
|
||||
|
|
@ -203,7 +239,7 @@
|
|||
validLatencyScore: gearTest.isValidLatencyScore(),
|
||||
validIOScore: gearTest.isValidIOScore(),
|
||||
latencyScore: gearTest.getLatencyScore(),
|
||||
ioScore : gearTest.getIOScore(),
|
||||
ioScore: gearTest.getIOScore(),
|
||||
},
|
||||
audioParameters: {
|
||||
frameSize: frameBuffers.selectedFramesize(),
|
||||
|
|
@ -221,21 +257,21 @@
|
|||
* This is to provide a unified view of FTUEGetAllAudioConfigurations & FTUEGetGoodAudioConfigurations
|
||||
* @returns an array of profiles, where each profile is: {id: profile-name, good: boolean, class: 'bad' | 'good', current: boolean }
|
||||
*/
|
||||
gearUtils.getProfiles = function() {
|
||||
gearUtils.getProfiles = function () {
|
||||
var all = context.jamClient.FTUEGetAllAudioConfigurations();
|
||||
var good = context.jamClient.FTUEGetGoodAudioConfigurations();
|
||||
var current = context.jamClient.LastUsedProfileName();
|
||||
|
||||
var profiles = [];
|
||||
context._.each(all, function(item) {
|
||||
context._.each(all, function (item) {
|
||||
|
||||
profiles.push({id: item, good: false, class:'bad', current: current == item})
|
||||
profiles.push({id: item, good: false, class: 'bad', current: current == item})
|
||||
});
|
||||
|
||||
if(good) {
|
||||
for(var i = 0; i < good.length; i++) {
|
||||
for(var j = 0; j < profiles.length; j++) {
|
||||
if(good[i] == profiles[j].id) {
|
||||
if (good) {
|
||||
for (var i = 0; i < good.length; i++) {
|
||||
for (var j = 0; j < profiles.length; j++) {
|
||||
if (good[i] == profiles[j].id) {
|
||||
profiles[j].good = true;
|
||||
profiles[j].class = 'good';
|
||||
break;
|
||||
|
|
@ -246,21 +282,21 @@
|
|||
|
||||
return profiles;
|
||||
}
|
||||
gearUtils.postDiagnostic = function(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated) {
|
||||
gearUtils.postDiagnostic = function (operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated) {
|
||||
rest.createDiagnostic({
|
||||
type: 'GEAR_SELECTION',
|
||||
data: {
|
||||
client_type: context.JK.clientType(),
|
||||
client_id:
|
||||
context.JK.JamServer.clientID,
|
||||
summary:gearUtils.ftueSummary(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated)}
|
||||
client_id: context.JK.JamServer.clientID,
|
||||
summary: gearUtils.ftueSummary(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// complete list of possibly chatInputs, whether currently assigned as the chat channel or not
|
||||
// each item should be {id: channelId, name: channelName, assignment: channel assignment}
|
||||
|
||||
gearUtils.getChatInputs = function(){
|
||||
gearUtils.getChatInputs = function () {
|
||||
|
||||
var musicPorts = jamClient.FTUEGetChannels();
|
||||
//var chatsOnCurrentDevice = context.jamClient.FTUEGetChatInputs(true);
|
||||
|
|
@ -273,11 +309,11 @@
|
|||
|
||||
var deDupper = {};
|
||||
|
||||
context._.each(musicPorts.inputs, function(input) {
|
||||
context._.each(musicPorts.inputs, function (input) {
|
||||
|
||||
var chatInput = {id: input.id, name: input.name, assignment:input.assignment};
|
||||
if(!deDupper[input.id]) {
|
||||
if(input.assignment <= 0) {
|
||||
var chatInput = {id: input.id, name: input.name, assignment: input.assignment};
|
||||
if (!deDupper[input.id]) {
|
||||
if (input.assignment <= 0) {
|
||||
chatInputs.push(chatInput);
|
||||
deDupper[input.id] = chatInput;
|
||||
}
|
||||
|
|
@ -295,9 +331,9 @@
|
|||
}
|
||||
})*/
|
||||
|
||||
context._.each(chatsOnOtherDevices, function(chatChannelName, chatChannelId) {
|
||||
context._.each(chatsOnOtherDevices, function (chatChannelName, chatChannelId) {
|
||||
var chatInput = {id: chatChannelId, name: chatChannelName, assignment: null};
|
||||
if(!deDupper[chatInput.id]) {
|
||||
if (!deDupper[chatInput.id]) {
|
||||
var assignment = context.jamClient.TrackGetAssignment(chatChannelId, true);
|
||||
chatInput.assignment = assignment;
|
||||
|
||||
|
|
@ -309,11 +345,11 @@
|
|||
return chatInputs;
|
||||
}
|
||||
|
||||
gearUtils.isChannelAvailableForChat = function(chatChannelId, musicPorts) {
|
||||
gearUtils.isChannelAvailableForChat = function (chatChannelId, musicPorts) {
|
||||
var result = true;
|
||||
context._.each(musicPorts.inputs, function(inputChannel) {
|
||||
context._.each(musicPorts.inputs, function (inputChannel) {
|
||||
// if the channel is currently assigned to a track, it not unassigned
|
||||
if(inputChannel.id == chatChannelId && (inputChannel.assignment > 0)) {
|
||||
if (inputChannel.id == chatChannelId && (inputChannel.assignment > 0)) {
|
||||
result = false;
|
||||
return false; // break
|
||||
}
|
||||
|
|
@ -324,13 +360,13 @@
|
|||
|
||||
// if the user has a good user network score, immediately returns with a resolved deferred object.
|
||||
// if not, the user will have the network test dialog prompted... once it's closed, then you'll be told reject() if score is still bad, or resolve() if now good
|
||||
gearUtils.guardAgainstBadNetworkScore = function(app) {
|
||||
gearUtils.guardAgainstBadNetworkScore = function (app) {
|
||||
var deferred = new $.Deferred();
|
||||
|
||||
if (!gearUtils.validNetworkScore()) {
|
||||
// invalid network test score. They have to score to move on
|
||||
app.layout.showDialog('network-test').one(EVENTS.DIALOG_CLOSED, function() {
|
||||
if(gearUtils.validNetworkScore()) {
|
||||
app.layout.showDialog('network-test').one(EVENTS.DIALOG_CLOSED, function () {
|
||||
if (gearUtils.validNetworkScore()) {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
|
|
@ -346,19 +382,19 @@
|
|||
|
||||
// XXX this isn't quite right... it needs to check if a good device is *active*
|
||||
// but seen too many problems so far with the backend not reporting any profile active
|
||||
gearUtils.hasGoodActiveProfile = function(verifyTracks) {
|
||||
gearUtils.hasGoodActiveProfile = function (verifyTracks) {
|
||||
var hasOneConfigureDevice = context.JK.hasOneConfiguredDevice();
|
||||
logger.debug("hasGoodActiveProfile: " + hasOneConfigureDevice ? "devices='has at least one configured device' " : "devices='has no configured device' ")
|
||||
return hasOneConfigureDevice;
|
||||
}
|
||||
|
||||
// if the user does not have any profiles, show the FTUE
|
||||
gearUtils.guardAgainstInvalidGearConfiguration = function(app) {
|
||||
gearUtils.guardAgainstInvalidGearConfiguration = function (app) {
|
||||
var deferred = new $.Deferred();
|
||||
|
||||
if (context.jamClient.FTUEGetAllAudioConfigurations().length == 0) {
|
||||
app.layout.showDialog('gear-wizard').one(EVENTS.DIALOG_CLOSED, function() {
|
||||
if(gearUtils.hasGoodActiveProfile() && gearUtils.validNetworkScore()) {
|
||||
app.layout.showDialog('gear-wizard').one(EVENTS.DIALOG_CLOSED, function () {
|
||||
if (gearUtils.hasGoodActiveProfile() && gearUtils.validNetworkScore()) {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
|
|
@ -373,27 +409,27 @@
|
|||
return deferred;
|
||||
}
|
||||
|
||||
gearUtils.guardAgainstActiveProfileMissing = function(app, backendInfo) {
|
||||
gearUtils.guardAgainstActiveProfileMissing = function (app, backendInfo) {
|
||||
|
||||
|
||||
var deferred = new $.Deferred();
|
||||
logger.debug("guardAgainstActiveProfileMissing: backendInfo %o", backendInfo);
|
||||
if(backendInfo.error && backendInfo['reason'] == 'no_profile' && context.jamClient.FTUEGetAllAudioConfigurations().length > 0) {
|
||||
if (backendInfo.error && backendInfo['reason'] == 'no_profile' && context.jamClient.FTUEGetAllAudioConfigurations().length > 0) {
|
||||
// if the backend says we have no_profile, but we have profiles , send them to the audio profile screen
|
||||
// this should be a very rare path
|
||||
deferred.reject({reason:'handled', nav: '/client#/account/audio'});
|
||||
deferred.reject({reason: 'handled', nav: '/client#/account/audio'});
|
||||
context.JK.Banner.showAlert('No Active Profile', 'We\'ve sent you to the audio profile screen to remedy the fact that you have no active audio profile. Please select ACTIVATE on an existing profile, or select ADD NEW GEAR to add a new profile.');
|
||||
}
|
||||
else if (backendInfo.error && backendInfo['reason'] == 'device_failure') {
|
||||
app.layout.showDialog('audio-profile-invalid-dialog')
|
||||
.one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||
if(!data.result || data.result == 'cancel') {
|
||||
deferred.reject({reason:'handled', nav: 'BACK'});
|
||||
.one(EVENTS.DIALOG_CLOSED, function (e, data) {
|
||||
if (!data.result || data.result == 'cancel') {
|
||||
deferred.reject({reason: 'handled', nav: 'BACK'});
|
||||
}
|
||||
else if(data.result == 'configure_gear'){
|
||||
deferred.reject({reason:'handled', nav: '/client#/account/audio'});
|
||||
else if (data.result == 'configure_gear') {
|
||||
deferred.reject({reason: 'handled', nav: '/client#/account/audio'});
|
||||
}
|
||||
else if(data.result == 'session') {
|
||||
else if (data.result == 'session') {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
|
|
@ -409,43 +445,49 @@
|
|||
}
|
||||
|
||||
// tests both device config, and network score
|
||||
gearUtils.guardAgainstInvalidConfiguration = function(app) {
|
||||
gearUtils.guardAgainstInvalidConfiguration = function (app, verifyNetworkScore) {
|
||||
var deferred = new $.Deferred();
|
||||
gearUtils.guardAgainstInvalidGearConfiguration(app)
|
||||
.fail(function() {
|
||||
.fail(function () {
|
||||
deferred.reject();
|
||||
})
|
||||
.done(function() {
|
||||
gearUtils.guardAgainstBadNetworkScore(app)
|
||||
.fail(function() {
|
||||
deferred.reject();
|
||||
})
|
||||
.done(function() {
|
||||
deferred.resolve();
|
||||
})
|
||||
.done(function () {
|
||||
if(verifyNetworkScore) {
|
||||
gearUtils.guardAgainstBadNetworkScore(app)
|
||||
.fail(function () {
|
||||
deferred.reject();
|
||||
})
|
||||
.done(function () {
|
||||
deferred.resolve();
|
||||
})
|
||||
}
|
||||
else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
||||
gearUtils.skipNetworkTest = function() {
|
||||
gearUtils.skipNetworkTest = function () {
|
||||
context.jamClient.SetNetworkTestScore(gearUtils.SKIPPED_NETWORK_TEST);
|
||||
gearUtils.skippedNetworkTest = true;
|
||||
}
|
||||
|
||||
gearUtils.isNetworkTestSkipped = function() {
|
||||
gearUtils.isNetworkTestSkipped = function () {
|
||||
return gearUtils.skippedNetworkTest;
|
||||
}
|
||||
|
||||
gearUtils.validNetworkScore = function() {
|
||||
gearUtils.validNetworkScore = function () {
|
||||
return gearUtils.skippedNetworkTest || context.jamClient.GetNetworkTestScore() >= 2;
|
||||
}
|
||||
|
||||
gearUtils.isRestartingAudio = function() {
|
||||
gearUtils.isRestartingAudio = function () {
|
||||
return !!reloadAudioTimeout;
|
||||
}
|
||||
|
||||
gearUtils.scheduleAudioRestart = function(location, initial_delay, beforeScan, afterScan, cancelScan) {
|
||||
gearUtils.scheduleAudioRestart = function (location, initial_delay, beforeScan, afterScan, cancelScan) {
|
||||
|
||||
logger.debug("scheduleAudioRestart: (from " + location + ")")
|
||||
|
||||
|
|
@ -453,40 +495,42 @@
|
|||
|
||||
function clearAudioReloadTimer() {
|
||||
|
||||
if(!cancellable) {return;}
|
||||
if (!cancellable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(cancelScan) {
|
||||
if (cancelScan) {
|
||||
cancelScan();
|
||||
}
|
||||
else if(afterScan) {
|
||||
else if (afterScan) {
|
||||
afterScan(true);
|
||||
}
|
||||
|
||||
clearTimeout(reloadAudioTimeout);
|
||||
reloadAudioTimeout = null;
|
||||
currentAudioRestartLocation = null;
|
||||
currentAudioRestartLocation = null;
|
||||
cancellable = false;
|
||||
}
|
||||
|
||||
// refresh timer if outstanding
|
||||
if(reloadAudioTimeout) {
|
||||
if (reloadAudioTimeout) {
|
||||
logger.debug("scheduleAudioRestart: clearing timeout (from " + location + ")")
|
||||
clearTimeout(reloadAudioTimeout);
|
||||
}
|
||||
|
||||
currentAudioRestartLocation = location;
|
||||
|
||||
if(beforeScan) {
|
||||
if (beforeScan) {
|
||||
beforeScan();
|
||||
}
|
||||
|
||||
reloadAudioTimeout = setTimeout(function() {
|
||||
reloadAudioTimeout = setTimeout(function () {
|
||||
logger.debug("scheduleAudioRestart: rescan beginning (from " + location + ")")
|
||||
reloadAudioTimeout = null;
|
||||
currentAudioRestartLocation = null;
|
||||
cancellable = false;
|
||||
|
||||
if(afterScan) {
|
||||
if (afterScan) {
|
||||
afterScan(false);
|
||||
}
|
||||
}, initial_delay ? initial_delay : 5000);
|
||||
|
|
@ -494,4 +538,45 @@
|
|||
return clearAudioReloadTimer;
|
||||
}
|
||||
|
||||
gearUtils.bootstrapDefaultPlaybackProfile = function () {
|
||||
|
||||
var profiles = gearUtils.getProfiles();
|
||||
|
||||
var foundSystemDefaultPlaybackOnly = false
|
||||
context._.each(profiles, function (profile) {
|
||||
if (profile.id == SYSTEM_DEFAULT_PLAYBACK_ONLY) {
|
||||
foundSystemDefaultPlaybackOnly = true
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
if (!foundSystemDefaultPlaybackOnly) {
|
||||
logger.debug("creating system default profile (playback only")
|
||||
if(!gearUtils.createDefaultPlaybackOnlyProfile()) {
|
||||
logger.error("unable to create the default playback profile!");
|
||||
}
|
||||
}
|
||||
}
|
||||
gearUtils.createDefaultPlaybackOnlyProfile = function () {
|
||||
|
||||
var eMixerInputSampleRate = {
|
||||
JAMKAZAM_AUTO_SR: 0,
|
||||
USE_DEVICE_DEFAULT_SR: 1,
|
||||
PREFER_44: 2,
|
||||
PREFER_48: 3,
|
||||
PREFER_96: 4
|
||||
}
|
||||
|
||||
// null//upgrade protect
|
||||
if(context.jamClient.FTUECreateUpdatePlayBackProfile) {
|
||||
return context.jamClient.FTUECreateUpdatePlayBackProfile(SYSTEM_DEFAULT_PLAYBACK_ONLY,
|
||||
eMixerInputSampleRate.JAMKAZAM_AUTO_SR,
|
||||
0, // buffering
|
||||
false); // start audio
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
@ -69,11 +69,15 @@
|
|||
if(result === false) {return false;}
|
||||
}
|
||||
|
||||
moveToNext();
|
||||
return false;
|
||||
}
|
||||
|
||||
function moveToNext() {
|
||||
previousStep = step;
|
||||
step = step + 1;
|
||||
|
||||
moveToStep();
|
||||
return false;
|
||||
}
|
||||
|
||||
function help() {
|
||||
|
|
@ -238,6 +242,7 @@
|
|||
this.getNextButton = getNextButton;
|
||||
this.setNextState = setNextState;
|
||||
this.setBackState = setBackState;
|
||||
this.moveToNext = moveToNext;
|
||||
this.getCurrentStep = getCurrentStep;
|
||||
this.getCurrentWizardStep = getCurrentWizardStep;
|
||||
this.onCloseDialog = onCloseDialog;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ body.jam, body.web, .dialog{
|
|||
}
|
||||
}
|
||||
|
||||
.help-high-latency-notice {
|
||||
width:400px;
|
||||
}
|
||||
|
||||
.help-hover-recorded-tracks, .help-hover-stream-mix, .help-hover-recorded-backing-tracks {
|
||||
|
||||
font-size:12px;
|
||||
|
|
|
|||
|
|
@ -210,6 +210,18 @@
|
|||
$otheraudio-minwidth:195px;
|
||||
$otheraudio-open-minwidth:230px;
|
||||
|
||||
#session-mytracks-notracks {
|
||||
display:none;
|
||||
|
||||
p {
|
||||
font-size:14px;
|
||||
white-space:normal;
|
||||
margin:10px 10px 0 0;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.session-mytracks {
|
||||
padding-left:15px;
|
||||
float:left;
|
||||
|
|
@ -251,6 +263,12 @@
|
|||
.recording-controls {
|
||||
min-width:230px;
|
||||
}
|
||||
|
||||
#recording-start-stop {
|
||||
@include border-radius(4px);
|
||||
padding-left:5px;
|
||||
padding-right:5px;
|
||||
}
|
||||
}
|
||||
|
||||
.session-recordings {
|
||||
|
|
@ -358,6 +376,25 @@
|
|||
#tracks {
|
||||
margin-top:12px;
|
||||
overflow:auto;
|
||||
|
||||
&.no-local-tracks {
|
||||
|
||||
#session-mytracks-notracks {
|
||||
display:block;
|
||||
}
|
||||
|
||||
#session-mytracks-container {
|
||||
display:none;
|
||||
}
|
||||
|
||||
#recording-start-stop {
|
||||
display:none;
|
||||
}
|
||||
|
||||
#session-invite-musicians {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.track-empty a {
|
||||
|
|
|
|||
|
|
@ -429,8 +429,12 @@
|
|||
|
||||
}
|
||||
|
||||
.instructions {
|
||||
height: 228px !important;
|
||||
}
|
||||
|
||||
.network-test-results {
|
||||
height: 248px !important;
|
||||
height: 228px !important;
|
||||
@include border_box_sizing;
|
||||
&.testing {
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,25 @@
|
|||
}
|
||||
|
||||
|
||||
.get-a-free-jamtrack-section {
|
||||
|
||||
&.has-free-jamtrack {
|
||||
h2.get-a-free-jamtrack {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
margin-top:-7px;
|
||||
}
|
||||
}
|
||||
|
||||
&.no-free-jamtrack {
|
||||
h2.browse-jamtracks {
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ftue-inner table a {
|
||||
text-decoration:none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
#single-player-profile-dialog {
|
||||
|
||||
.dialog-inner {
|
||||
|
||||
&.high-latency {
|
||||
.high-latency {
|
||||
display:block
|
||||
}
|
||||
}
|
||||
|
||||
&.has-no-inputs {
|
||||
.has-no-inputs {
|
||||
display:block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.audio-latency {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin:20px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height:125%;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +46,7 @@ class ApiUsersController < ApiController
|
|||
@user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments)
|
||||
@user.update_genres(params[:genres].nil? ? [] : params[:genres]) if params.has_key?(:genres)
|
||||
@user.show_whats_next = params[:show_whats_next] if params.has_key?(:show_whats_next)
|
||||
@user.show_whats_next_count = params[:show_whats_next_count] if params.has_key?(:show_whats_next_count)
|
||||
@user.subscribe_email = params[:subscribe_email] if params.has_key?(:subscribe_email)
|
||||
@user.biography = params[:biography] if params.has_key?(:biography)
|
||||
@user.mod_merge(params[:mods]) if params[:mods]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ end
|
|||
|
||||
# give back more info if the user being fetched is yourself
|
||||
if @user == current_user
|
||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :subscribe_email, :auth_twitter, :new_notifications
|
||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications
|
||||
|
||||
node :geoiplocation do |user|
|
||||
geoiplocation = current_user.geoiplocation
|
||||
|
|
|
|||
|
|
@ -30,6 +30,29 @@ script type="text/template" id="template-help-can-move-on"
|
|||
script type="text/template" id="template-help-tweak-asio-settings"
|
||||
| Click here to try faster ASIO settings.
|
||||
|
||||
script type="text/template" id="template-help-high-latency-notice"
|
||||
.help-high-latency-notice
|
||||
| {% if(data.additional == 'asio') { %}
|
||||
p.gear-specific-latency-notice Tip: click the ASIO SETTINGS button to try faster ASIO settings.
|
||||
p
|
||||
| If you are unable to get your audio gear latency below 20 milliseconds, you can click NEXT to proceed through setup with a high-latency audio profile. This will allow you to play with JamTracks and backing tracks, but not play with others.
|
||||
p
|
||||
a href="https://jamkazam.desk.com/customer/portal/articles/1520627-my-audio-gear-won-t-pass-latency-or-i-o-tests" rel="external" Click here
|
||||
| for more troubleshooting tips to speed up your audio gear setup.
|
||||
| {% } else if(data.additional == 'macosx-builtin') { %}
|
||||
p.gear-specific-latency-notice Tip: Insert your headphones on a Mac to bring your latency down, and click the RESYNC button to try again.
|
||||
p
|
||||
| If you are unable to get your audio gear latency below 20 milliseconds, you can click NEXT to proceed through setup with a high-latency audio profile. This will allow you to play with JamTracks and backing tracks, but not play with others.
|
||||
p
|
||||
a href="https://jamkazam.desk.com/customer/portal/articles/1520627-my-audio-gear-won-t-pass-latency-or-i-o-tests" rel="external" Click here
|
||||
| for more troubleshooting tips to speed up your audio gear setup.
|
||||
| {% } else { %}
|
||||
p.general-info
|
||||
| Your computer and interface are processing audio too slowly to play online in real-time sessions with other musicians over the Internet. You may click NEXT to proceed through setup to play alone in sessions with JamTracks or backing tracks, or if you want to improve your speed score to play online,
|
||||
a href="https://jamkazam.desk.com/customer/portal/articles/1520627-my-audio-gear-won-t-pass-latency-or-i-o-tests" rel="external" click here
|
||||
| for a troubleshooting article.
|
||||
| {% } %}
|
||||
|
||||
script type="text/template" id="template-help-session-plus-musicians"
|
||||
| Plus any interested JamKazam musicians that I approve.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.network-test
|
||||
.help-text In this step, you will test your router and Internet connection to ensure that you can play in online sessions, and to see how many musicians can be in a session with you based on your internet connection.
|
||||
.help-text In this step, you will test your router and Internet connection to ensure that you can play in online sessions, and to see how many musicians can be in a session with you based on your internet connection. If you don't want to play online in real-time sessions, you can click NEXT to skip this step.
|
||||
.wizard-step-content
|
||||
.wizard-step-column
|
||||
%h2 Instructions
|
||||
|
|
|
|||
|
|
@ -40,6 +40,12 @@
|
|||
span
|
||||
| Settings
|
||||
.session-tracks-scroller
|
||||
#session-mytracks-notracks
|
||||
p.notice
|
||||
| You have not set up any inputs for your instrument or vocals.
|
||||
| If you want to hear yourself play through the JamKazam app,
|
||||
| and let the app mix your live playing with JamTracks, or with other musicians in online sessions,
|
||||
a.open-ftue-no-tracks href='#' click here now.
|
||||
#session-mytracks-container
|
||||
#voice-chat.voicechat[style="display:none;" mixer-id=""]
|
||||
.voicechat-label
|
||||
|
|
|
|||
|
|
@ -249,8 +249,6 @@
|
|||
var jamtrackScreen = new JK.JamTrackScreen(JK.app);
|
||||
jamtrackScreen.initialize();
|
||||
|
||||
|
||||
|
||||
var jamtrackLanding = new JK.JamTrackLanding(JK.app);
|
||||
jamtrackLanding.initialize();
|
||||
|
||||
|
|
@ -299,6 +297,9 @@
|
|||
var allSyncsDialog = new JK.AllSyncsDialog(JK.app);
|
||||
allSyncsDialog.initialize();
|
||||
|
||||
var singlePlayerProfileGuardDialog = new JK.SinglePlayerProfileGuardDialog(JK.app);
|
||||
singlePlayerProfileGuardDialog.initialize();
|
||||
|
||||
// do a client update early check upon initialization
|
||||
JK.ClientUpdateInstance.check()
|
||||
|
||||
|
|
@ -312,6 +313,9 @@
|
|||
var jamServer = new JK.JamServer(JK.app, function(event_type) {JK.app.activeElementEvent(event_type)});
|
||||
jamServer.initialize();
|
||||
|
||||
var clientInit = new JK.ClientInit();
|
||||
clientInit.init();
|
||||
|
||||
// latency_tester does not want to be here - redirect it
|
||||
if(window.jamClient.getOperatingMode && window.jamClient.getOperatingMode() == "server") {
|
||||
window.location = "/latency_tester";
|
||||
|
|
|
|||
|
|
@ -37,3 +37,4 @@
|
|||
= render 'dialogs/openBackingTrackDialog'
|
||||
= render 'dialogs/loginRequiredDialog'
|
||||
= render 'dialogs/jamtrackPaymentHistoryDialog'
|
||||
= render 'dialogs/singlePlayerProfileGuard'
|
||||
|
|
@ -36,16 +36,24 @@
|
|||
a href="#" class="google-invite"
|
||||
= image_tag "content/icon_google.png", {:align=>"absmiddle", :height => 26, :width => 26 }
|
||||
span Google+
|
||||
.column.get-a-free-jamtrack-section
|
||||
h2.get-a-free-jamtrack.hidden GET A FREE JAMTRACK
|
||||
h2.browse-jamtracks.hidden CHECK OUT JAMTRACKS
|
||||
.blurb
|
||||
| JamTracks are the best way to play with your favorite music. Unlike traditional backing tracks,
|
||||
| they are complete multitrack recordings, with fully isolated tracks for each part. 
|
||||
span.jamtracks-limited-time.hidden For a limited time, you can get your first JamTrack free.
|
||||
| Check it out!
|
||||
.action-button
|
||||
a.button-orange.browse-jamtrack rel="external" href="#" LEARN MORE
|
||||
br clear="both"
|
||||
.row.find-connect
|
||||
.column
|
||||
h2 CREATE A "REAL" SESSION
|
||||
.blurb
|
||||
| You can create a session to start immediately and hope others join, but this doesn’t work well. It’s better
|
||||
to schedule a session and invite friends or the community to join you. Watch a video to learn how, then
|
||||
schedule your first session!
|
||||
| You can create sessions that start immediately and see who joins, or you can schedule sessions, invite friends, and others from the community, and manage RSVPs. Learn how.
|
||||
.action-button
|
||||
a.button-orange rel="external" href="https://www.youtube.com/watch?v=EZZuGcDUoWk" WATCH VIDEO
|
||||
br clear="both"
|
||||
.row.find-connect
|
||||
.column
|
||||
h2 FIND SESSIONS TO JOIN
|
||||
.blurb
|
||||
|
|
@ -53,14 +61,6 @@
|
|||
to learn about how to find and select good sessions to join.
|
||||
.action-button
|
||||
a.button-orange.setup-gear rel="external" href="https://www.youtube.com/watch?v=xWponSJo-GU" WATCH VIDEO
|
||||
|
||||
.column
|
||||
h2 CONNECT WITH MUSICIANS
|
||||
.blurb
|
||||
| To play more music, tap into our growing
|
||||
community to connect with other musicians. Watch this video for tips on how to do this.
|
||||
.action-button
|
||||
a.button-orange rel="external" href="https://www.youtube.com/watch?v=4KWklSZZxRc" WATCH VIDEO
|
||||
br clear="both"
|
||||
.row.full.learn-more
|
||||
.column
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
.dialog.dialog-overlay-sm layout='dialog' layout-id='single-player-profile-dialog' id='single-player-profile-dialog'
|
||||
.content-head
|
||||
= image_tag "content/icon_alert.png", {:width => 24, :height => 24, :class => 'content-icon' }
|
||||
h1 Application Notice
|
||||
.dialog-inner
|
||||
|
||||
p.high-latency.hidden
|
||||
| Your audio profile has a latency score of
|
||||
span.audio-latency
|
||||
br
|
||||
br
|
||||
| This is too high to play with others in real-time. However, you can play with JamTracks and backing tracks by yourself in a private session, or go to the gear setup wizard and add a new audio profile with lower latency.
|
||||
|
||||
p.has-no-inputs.hidden
|
||||
| You are currently using the default system profile, which has no audio inputs.
|
||||
br
|
||||
br
|
||||
| With this profile, you can't play with others in real-time. However, you can play with JamTracks and backing tracks by yourself in a private session, or go to the gear setup wizard and add a new audio profile that uses your gear.
|
||||
.right.action-buttons
|
||||
a.button-grey.btn-cancel href='#' layout-action="cancel" CANCEL
|
||||
a.button-grey.btn-gear-setup href="/client#/account/audio" GO TO GEAR SETUP
|
||||
a.button-orange.btn-private-session href="#" PRIVATE SESSION
|
||||
|
|
@ -10,8 +10,7 @@ describe "Home Screen", :js => true, :type => :feature, :capybara_feature => tru
|
|||
Capybara.default_wait_time = 10
|
||||
end
|
||||
|
||||
let(:user) { FactoryGirl.create(:user, :show_whats_next => true) }
|
||||
|
||||
let(:user) { FactoryGirl.create(:user, show_whats_next: true, has_redeemable_jamtrack: true) }
|
||||
|
||||
describe "in normal browser" do
|
||||
before(:each) do
|
||||
|
|
@ -24,6 +23,36 @@ describe "Home Screen", :js => true, :type => :feature, :capybara_feature => tru
|
|||
find('#getting-started-dialog .setup-gear-btn').trigger('click')
|
||||
should have_selector('p', text: 'To configure your audio gear, you must use the JamKazam application.')
|
||||
end
|
||||
|
||||
it "should show jam track browsing page" do
|
||||
find('#getting-started-dialog span.jamtracks-limited-time')
|
||||
find('#getting-started-dialog h2.get-a-free-jamtrack')
|
||||
expect(page).to have_selector('#getting-started-dialog .browse-jamtracks', visible: false)
|
||||
|
||||
find('#getting-started-dialog a.browse-jamtrack').trigger('click')
|
||||
should have_selector('h1', text: 'jamtracks')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "in normal browser with redeemed jamtrack" do
|
||||
let(:redeemed_user) { FactoryGirl.create(:user, show_whats_next: true, has_redeemable_jamtrack: false) }
|
||||
|
||||
before(:each) do
|
||||
sign_in_poltergeist redeemed_user
|
||||
visit "/client"
|
||||
should have_selector('h1', text: 'getting started')
|
||||
end
|
||||
|
||||
it "should show jam track browsing page" do
|
||||
find('#getting-started-dialog h2.browse-jamtracks')
|
||||
expect(page).to have_selector('#getting-started-dialog h2.get-a-free-jamtrack', visible: false)
|
||||
expect(page).to have_selector('#getting-started-dialog span.jamtracks-limited-time', visible: false)
|
||||
|
||||
find('#getting-started-dialog .browse-jamtrack').trigger('click')
|
||||
should have_selector('h1', text: 'jamtracks')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "in native client" do
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ describe "Active Music Session API ", :type => :api do
|
|||
JSON.parse(last_response.body)["errors"]["genre"].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
it "should error with no track specified" do
|
||||
it "should not error with no track specified" do
|
||||
original_count = ActiveMusicSession.all().length
|
||||
|
||||
client = FactoryGirl.create(:connection, :user => user, :ip_address => "1.1.1.1")
|
||||
|
|
@ -320,10 +320,7 @@ describe "Active Music Session API ", :type => :api do
|
|||
music_session = JSON.parse(last_response.body)
|
||||
post "/api/sessions/#{music_session["id"]}/participants.json", { :client_id => client.client_id, :as_musician => true, :tracks => []}.to_json, "CONTENT_TYPE" => 'application/json'
|
||||
|
||||
JSON.parse(last_response.body)["errors"]["tracks"].should == [ValidationMessages::SELECT_AT_LEAST_ONE]
|
||||
|
||||
# check that the transaction was rolled back
|
||||
ActiveMusicSession.all().length.should == original_count
|
||||
last_response.status.should eq(201)
|
||||
end
|
||||
|
||||
it "should error with invalid track specified" do
|
||||
|
|
|
|||
Loading…
Reference in New Issue