2012-10-06 16:36:05 +00:00
( function ( context , $ ) {
2012-12-07 00:28:48 +00:00
"use strict" ;
2012-10-06 16:36:05 +00:00
context . JK = context . JK || { } ;
context . JK . SessionScreen = function ( app ) {
2015-01-22 02:16:52 +00:00
var TEMPOS = context . JK . TEMPOS ;
2014-10-23 04:10:49 +00:00
var EVENTS = context . JK . EVENTS ;
2014-11-11 22:21:29 +00:00
var MIX _MODES = context . JK . MIX _MODES ;
var NAMED _MESSAGES = context . JK . NAMED _MESSAGES ;
2014-06-25 21:54:31 +00:00
var gearUtils = context . JK . GearUtils ;
2014-08-29 02:11:25 +00:00
var sessionUtils = context . JK . SessionUtils ;
2014-11-11 22:21:29 +00:00
var modUtils = context . JK . ModUtils ;
2012-10-14 15:48:56 +00:00
var logger = context . JK . logger ;
2014-02-23 04:41:42 +00:00
var self = this ;
2013-03-02 19:02:42 +00:00
var sessionModel = null ;
2012-10-29 15:10:02 +00:00
var sessionId ;
2012-10-22 02:55:05 +00:00
var tracks = { } ;
2013-05-15 05:59:09 +00:00
var myTracks = [ ] ;
2014-11-17 23:16:30 +00:00
var masterMixers = [ ] ;
var personalMixers = [ ] ;
2014-11-21 23:16:00 +00:00
var allMixers = { } ;
var mixersByResourceId = { } ;
var mixersByTrackId = { } ;
2013-05-22 05:03:34 +00:00
var configureTrackDialog ;
2013-05-23 12:46:40 +00:00
var addNewGearDialog ;
2014-01-05 03:47:23 +00:00
var localRecordingsDialog = null ;
2014-01-06 20:35:35 +00:00
var recordingFinishedDialog = null ;
2014-01-13 16:11:26 +00:00
var friendSelectorDialog = null ;
2014-01-14 06:12:00 +00:00
var inviteMusiciansUtil = null ;
2013-05-31 02:07:33 +00:00
var screenActive = false ;
2013-02-03 22:47:17 +00:00
var currentMixerRangeMin = null ;
var currentMixerRangeMax = null ;
2013-02-14 07:02:05 +00:00
var lookingForMixersCount = 0 ;
var lookingForMixersTimer = null ;
2014-11-21 23:16:00 +00:00
var lookingForMixers = [ ] ;
2013-11-03 20:55:55 +00:00
var $recordingTimer = null ;
var recordingTimerInterval = null ;
var startTimeDate = null ;
var startingRecording = false ; // double-click guard
2014-01-05 03:47:23 +00:00
var claimedRecording = null ;
2015-02-16 04:14:30 +00:00
var backing _track _path = null ;
2014-01-05 03:47:23 +00:00
var playbackControls = null ;
2014-02-23 04:41:42 +00:00
var promptLeave = false ;
2014-05-01 01:48:57 +00:00
var rateSessionDialog = null ;
2014-08-29 02:11:25 +00:00
var friendInput = null ;
var sessionPageDone = null ;
2015-02-12 20:05:25 +00:00
var metroTempo = 120 ;
var metroSound = "Beep" ;
2014-10-23 04:10:49 +00:00
var $recordingManagerViewer = null ;
var $screen = null ;
2014-11-09 15:13:22 +00:00
var $mixModeDropdown = null ;
2014-11-11 22:21:29 +00:00
var $templateMixerModeChange = null ;
2013-02-14 07:02:05 +00:00
2014-11-11 22:21:29 +00:00
var rest = context . JK . Rest ( ) ;
2013-09-10 02:07:12 +00:00
var RENDER _SESSION _DELAY = 750 ; // When I need to render a session, I have to wait a bit for the mixers to be there.
2013-02-05 05:10:37 +00:00
var defaultParticipant = {
2013-02-10 00:33:47 +00:00
tracks : [ {
instrument _id : "unknown"
} ] ,
2013-02-05 05:10:37 +00:00
user : {
first _name : 'Unknown' ,
last _name : 'User' ,
photo _url : null
}
} ;
2013-08-03 18:30:45 +00:00
// Be sure to copy/extend these instead of modifying in place
var trackVuOpts = {
vuType : "vertical" ,
lightCount : 13 ,
lightWidth : 3 ,
lightHeight : 17
} ;
// Must add faderId key to this
var trackFaderOpts = {
faderType : "vertical" ,
height : 83
} ;
2013-02-26 03:54:09 +00:00
// Recreate ChannelGroupIDs ENUM from C++
var ChannelGroupIds = {
"MasterGroup" : 0 ,
"MonitorGroup" : 1 ,
"AudioInputMusicGroup" : 2 ,
"AudioInputChatGroup" : 3 ,
"MediaTrackGroup" : 4 ,
"StreamOutMusicGroup" : 5 ,
"StreamOutChatGroup" : 6 ,
"UserMusicInputGroup" : 7 ,
"UserChatInputGroup" : 8 ,
2013-09-11 22:29:32 +00:00
"PeerAudioInputMusicGroup" : 9 ,
2015-01-09 21:15:12 +00:00
"PeerMediaTrackGroup" : 10 ,
"JamTrackGroup" : 11 ,
"MetronomeGroup" : 12
2013-02-26 03:54:09 +00:00
} ;
2013-02-05 05:10:37 +00:00
2012-10-29 15:10:02 +00:00
function beforeShow ( data ) {
sessionId = data . id ;
2014-08-29 02:11:25 +00:00
if ( ! sessionId ) {
window . location = '/client#/home' ;
}
2014-02-23 04:41:42 +00:00
promptLeave = true ;
2013-02-06 04:32:56 +00:00
$ ( '#session-mytracks-container' ) . empty ( ) ;
2013-11-03 20:55:55 +00:00
displayDoneRecording ( ) ; // assumption is that you can't join a recording session, so this should be safe
2014-02-07 05:57:31 +00:00
var shareDialog = new JK . ShareDialog ( context . JK . app , sessionId , "session" ) ;
shareDialog . initialize ( context . JK . FacebookHelperInstance ) ;
2012-10-29 15:10:02 +00:00
}
2012-10-29 00:37:59 +00:00
2014-04-09 17:25:52 +00:00
function beforeDisconnect ( ) {
return { freezeInteraction : true } ;
}
2014-03-03 22:13:23 +00:00
2014-03-01 23:01:45 +00:00
function initializeSession ( ) {
// Subscribe for callbacks on audio events
context . jamClient . SessionRegisterCallback ( "JK.HandleBridgeCallback" ) ;
context . jamClient . RegisterRecordingCallbacks ( "JK.HandleRecordingStartResult" , "JK.HandleRecordingStopResult" , "JK.HandleRecordingStarted" , "JK.HandleRecordingStopped" , "JK.HandleRecordingAborted" ) ;
context . jamClient . SessionSetConnectionStatusRefreshRate ( 1000 ) ;
// If you load this page directly, the loading of the current user
// is happening in parallel. We can't join the session until the
// current user has been completely loaded. Poll for the current user
// before proceeding with session joining.
function checkForCurrentUser ( ) {
if ( context . JK . userMe ) {
afterCurrentUserLoaded ( ) ;
} else {
context . setTimeout ( checkForCurrentUser , 100 ) ;
}
}
checkForCurrentUser ( ) ;
}
2012-10-06 16:36:05 +00:00
function afterShow ( data ) {
2013-05-31 02:07:33 +00:00
2014-06-26 02:50:20 +00:00
if ( ! context . JK . JamServer . connected ) {
promptLeave = false ;
app . notifyAlert ( "Not Connected" , 'To create or join a session, you must be connected to the server.' ) ;
window . location = '/client#/home'
return ;
}
2014-04-09 17:25:52 +00:00
2014-08-29 02:11:25 +00:00
// The SessionModel is a singleton.
// a client can only be in one session at a time,
// and other parts of the code want to know at any certain times
// about the current session, if any (for example, reconnect logic)
if ( context . JK . CurrentSessionModel ) {
2014-08-31 15:30:59 +00:00
context . JK . CurrentSessionModel . ensureEnded ( ) ;
2014-08-29 02:11:25 +00:00
}
2014-08-31 15:30:59 +00:00
2014-08-29 02:11:25 +00:00
context . JK . CurrentSessionModel = sessionModel = new context . JK . SessionModel (
context . JK . app ,
context . JK . JamServer ,
context . jamClient ,
self
) ;
2014-08-31 15:30:59 +00:00
sessionModel . start ( sessionId ) ;
2014-08-29 02:11:25 +00:00
// indicate that the screen is active, so that
// body-scoped drag handlers can go active
screenActive = true ;
2014-06-25 21:54:31 +00:00
gearUtils . guardAgainstInvalidConfiguration ( app )
. fail ( function ( ) {
promptLeave = false ;
window . location = '/client#/home'
} )
. done ( function ( ) {
2014-08-29 02:11:25 +00:00
var result = sessionUtils . SessionPageEnter ( ) ;
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 {
contetx . JK . alertSupportedNeeded ( 'Unable to determine configured tracks due to reason: ' + data )
}
promptLeave = false ;
window . location = '/client#/home'
} ) ;
} )
2014-06-25 21:54:31 +00:00
} )
2014-07-27 23:39:11 +00:00
2014-08-29 02:11:25 +00:00
2013-02-26 03:54:09 +00:00
}
2013-11-16 04:35:40 +00:00
function notifyWithUserInfo ( title , text , clientId ) {
sessionModel . findUserBy ( { clientId : clientId } )
. done ( function ( user ) {
app . notify ( {
"title" : title ,
"text" : user . name + " " + text ,
"icon_url" : context . JK . resolveAvatarUrl ( user . photo _url )
} ) ;
} )
. fail ( function ( ) {
app . notify ( {
"title" : title ,
"text" : 'Someone ' + text ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
}
2013-02-26 03:54:09 +00:00
function afterCurrentUserLoaded ( ) {
2014-08-29 02:11:25 +00:00
var sessionModel = context . JK . CurrentSessionModel ;
2013-08-31 13:54:11 +00:00
2013-11-03 20:55:55 +00:00
$ ( sessionModel . recordingModel )
. on ( 'startingRecording' , function ( e , data ) {
2013-11-16 04:35:40 +00:00
displayStartingRecording ( ) ;
} )
. on ( 'startedRecording' , function ( e , data ) {
2013-11-03 20:55:55 +00:00
if ( data . reason ) {
2013-11-16 04:35:40 +00:00
var reason = data . reason ;
var detail = data . detail ;
var title = "Could Not Start Recording" ;
if ( data . reason == 'client-no-response' ) {
notifyWithUserInfo ( title , 'did not respond to the start signal.' , detail ) ;
}
else if ( data . reason == 'empty-recording-id' ) {
app . notifyAlert ( title , "No recording ID specified." ) ;
}
else if ( data . reason == 'missing-client' ) {
notifyWithUserInfo ( title , 'could not be signalled to start recording.' , detail ) ;
}
else if ( data . reason == 'already-recording' ) {
2014-11-03 21:24:46 +00:00
app . notifyAlert ( title , 'Already recording. If this appears incorrect, try restarting JamKazam.' ) ;
2013-11-16 04:35:40 +00:00
}
else if ( data . reason == 'recording-engine-unspecified' ) {
notifyWithUserInfo ( title , 'had a problem writing recording data to disk.' , detail ) ;
}
else if ( data . reason == 'recording-engine-create-directory' ) {
notifyWithUserInfo ( title , 'had a problem creating a recording folder.' , detail ) ;
}
else if ( data . reason == 'recording-engine-create-file' ) {
notifyWithUserInfo ( title , 'had a problem creating a recording file.' , detail ) ;
}
else if ( data . reason == 'recording-engine-sample-rate' ) {
notifyWithUserInfo ( title , 'had a problem recording at the specified sample rate.' , detail ) ;
}
2014-01-05 03:47:23 +00:00
else if ( data . reason == 'rest' ) {
var jqXHR = detail [ 0 ] ;
app . notifyServerError ( jqXHR ) ;
}
2013-11-16 04:35:40 +00:00
else {
notifyWithUserInfo ( title , 'Error Reason: ' + reason ) ;
}
2013-11-03 20:55:55 +00:00
displayDoneRecording ( ) ;
}
2013-11-16 04:35:40 +00:00
else
{
displayStartedRecording ( ) ;
displayWhoCreated ( data . clientId ) ;
2013-11-03 20:55:55 +00:00
}
} )
. on ( 'stoppingRecording' , function ( e , data ) {
displayStoppingRecording ( data ) ;
} )
. on ( 'stoppedRecording' , function ( e , data ) {
if ( data . reason ) {
2014-05-19 23:49:02 +00:00
logger . warn ( "Recording Discarded: " , data ) ;
2013-11-03 20:55:55 +00:00
var reason = data . reason ;
2013-11-16 04:35:40 +00:00
var detail = data . detail ;
var title = "Recording Discarded" ;
2013-11-03 20:55:55 +00:00
if ( data . reason == 'client-no-response' ) {
2013-11-16 04:35:40 +00:00
notifyWithUserInfo ( title , 'did not respond to the stop signal.' , detail ) ;
2013-11-03 20:55:55 +00:00
}
2013-11-16 04:35:40 +00:00
else if ( data . reason == 'missing-client' ) {
notifyWithUserInfo ( title , 'could not be signalled to stop recording.' , detail ) ;
}
else if ( data . reason == 'empty-recording-id' ) {
app . notifyAlert ( title , "No recording ID specified." ) ;
}
else if ( data . reason == 'wrong-recording-id' ) {
app . notifyAlert ( title , "Wrong recording ID specified." ) ;
}
else if ( data . reason == 'not-recording' ) {
app . notifyAlert ( title , "Not currently recording." ) ;
}
else if ( data . reason == 'already-stopping' ) {
app . notifyAlert ( title , "Already stopping the current recording." ) ;
}
else if ( data . reason == 'start-before-stop' ) {
notifyWithUserInfo ( title , 'asked that we start a new recording; cancelling the current one.' , detail ) ;
}
else {
app . notifyAlert ( title , "Error reason: " + reason ) ;
}
2013-11-03 20:55:55 +00:00
displayDoneRecording ( ) ;
}
else {
displayDoneRecording ( ) ;
promptUserToSave ( data . recordingId ) ;
}
} )
2013-11-16 04:35:40 +00:00
. on ( 'abortedRecording' , function ( e , data ) {
var reason = data . reason ;
var detail = data . detail ;
2013-11-03 20:55:55 +00:00
2013-11-16 04:35:40 +00:00
var title = "Recording Cancelled" ;
2013-11-03 20:55:55 +00:00
2013-11-16 04:35:40 +00:00
if ( data . reason == 'client-no-response' ) {
notifyWithUserInfo ( title , 'did not respond to the start signal.' , detail ) ;
}
else if ( data . reason == 'missing-client' ) {
notifyWithUserInfo ( title , 'could not be signalled to start recording.' , detail ) ;
}
else if ( data . reason == 'populate-recording-info' ) {
notifyWithUserInfo ( title , 'could not synchronize with the server.' , detail ) ;
}
else if ( data . reason == 'recording-engine-unspecified' ) {
notifyWithUserInfo ( title , 'had a problem writing recording data to disk.' , detail ) ;
}
else if ( data . reason == 'recording-engine-create-directory' ) {
notifyWithUserInfo ( title , 'had a problem creating a recording folder.' , detail ) ;
}
else if ( data . reason == 'recording-engine-create-file' ) {
notifyWithUserInfo ( title , 'had a problem creating a recording file.' , detail ) ;
}
else if ( data . reason == 'recording-engine-sample-rate' ) {
notifyWithUserInfo ( title , 'had a problem recording at the specified sample rate.' , detail ) ;
}
else {
app . notifyAlert ( title , "Error reason: " + reason ) ;
}
displayDoneRecording ( ) ;
} )
2013-11-03 20:55:55 +00:00
2013-03-02 19:02:42 +00:00
sessionModel . subscribe ( 'sessionScreen' , sessionChanged ) ;
2013-08-31 13:54:11 +00:00
sessionModel . joinSession ( sessionId )
. fail ( function ( xhr , textStatus , errorMessage ) {
if ( xhr . status == 404 ) {
// we tried to join the session, but it's already gone. kick user back to join session screen
2014-02-23 05:21:36 +00:00
promptLeave = false ;
2014-02-06 13:03:44 +00:00
context . window . location = "/client#/findSession" ;
2013-08-31 13:54:11 +00:00
app . notify (
{ title : "Unable to Join Session" ,
text : "The session you attempted to join is over."
} ,
2014-05-14 05:16:33 +00:00
null ,
true ) ;
2013-10-03 07:16:27 +00:00
}
2014-07-31 15:32:20 +00:00
else if ( xhr . status == 422 ) {
2014-08-29 02:11:25 +00:00
var response = JSON . parse ( xhr . responseText ) ;
2014-07-31 15:32:20 +00:00
if ( response [ "errors" ] && response [ "errors" ] [ "tracks" ] && response [ "errors" ] [ "tracks" ] [ 0 ] == "Please select at least one track" ) {
app . notifyAlert ( "No Inputs Configured" , $ ( '<span>You will need to reconfigure your audio device.</span>' ) ) ;
}
2014-10-29 03:08:22 +00:00
else if ( response [ "errors" ] && response [ "errors" ] [ "music_session" ] && response [ "errors" ] [ "music_session" ] [ 0 ] == [ "is currently recording" ] ) {
promptLeave = false ;
context . window . location = "/client#/findSession" ;
app . notify ( { title : "Unable to Join Session" , text : "The session is currently recording." } , null , true ) ;
}
else {
app . notifyServerError ( xhr , 'Unable to Join Session' ) ;
}
2014-07-31 15:32:20 +00:00
}
2013-10-03 07:16:27 +00:00
else {
2014-03-01 23:01:45 +00:00
app . notifyServerError ( xhr , 'Unable to Join Session' ) ;
2013-08-31 13:54:11 +00:00
}
2013-09-05 04:24:28 +00:00
} ) ;
2013-02-10 18:51:37 +00:00
}
2014-02-25 02:20:17 +00:00
// not leave session but leave screen
2014-02-23 04:41:42 +00:00
function beforeLeave ( data ) {
if ( promptLeave ) {
var leaveSessionWarningDialog = new context . JK . LeaveSessionWarningDialog ( context . JK . app ,
function ( ) { promptLeave = false ; context . location . hash = data . hash } ) ;
leaveSessionWarningDialog . initialize ( ) ;
app . layout . showDialog ( 'leave-session-warning' ) ;
return false ;
}
2014-02-25 19:22:32 +00:00
return true ;
2014-02-23 04:41:42 +00:00
}
2014-02-22 18:43:11 +00:00
function beforeHide ( data ) {
2014-03-01 23:01:45 +00:00
if ( screenActive ) {
// this path is possible if FTUE is invoked on session page, and they cancel
sessionModel . leaveCurrentSession ( )
2014-10-29 03:08:22 +00:00
. fail ( function ( jqXHR ) {
if ( jqXHR . status != 404 ) {
logger . debug ( "leave session failed" ) ;
app . ajaxError ( arguments )
}
} ) ;
2014-03-01 23:01:45 +00:00
}
screenActive = false ;
2014-08-29 02:11:25 +00:00
sessionUtils . SessionPageLeave ( ) ;
2012-10-06 16:36:05 +00:00
}
2014-01-05 03:47:23 +00:00
function handleTransitionsInRecordingPlayback ( ) {
// let's see if we detect a transition to start playback or stop playback
var currentSession = sessionModel . getCurrentSession ( ) ;
2015-02-16 04:14:30 +00:00
2014-01-05 03:47:23 +00:00
if ( claimedRecording == null && ( currentSession && currentSession . claimed _recording != null ) ) {
// this is a 'started with a claimed_recording' transition.
// we need to start a timer to watch for the state of the play session
2014-01-06 20:35:35 +00:00
playbackControls . startMonitor ( ) ;
2014-01-05 03:47:23 +00:00
}
else if ( claimedRecording && ( currentSession == null || currentSession . claimed _recording == null ) ) {
2014-01-06 20:35:35 +00:00
playbackControls . stopMonitor ( ) ;
2014-01-05 03:47:23 +00:00
}
claimedRecording = currentSession == null ? null : currentSession . claimed _recording ;
2015-02-16 04:14:30 +00:00
if ( backing _track _path == null && ( currentSession && currentSession . backing _track _path != null ) ) {
playbackControls . startMonitor ( ) ;
}
else if ( backing _track _path && ( currentSession == null || currentSession . backing _track _path == null ) ) {
playbackControls . stopMonitor ( ) ;
}
backing _track _path = currentSession == null ? null : currentSession . backing _track _path ;
2014-01-05 03:47:23 +00:00
}
2015-02-16 04:14:30 +00:00
2013-03-02 19:02:42 +00:00
function sessionChanged ( ) {
2013-09-06 12:34:57 +00:00
2014-01-05 03:47:23 +00:00
handleTransitionsInRecordingPlayback ( ) ;
2013-08-19 00:54:32 +00:00
// TODO - in the specific case of a user changing their tracks using the configureTrack dialog,
// this event appears to fire before the underlying mixers have updated. I have no event to
// know definitively when the underlying mixers are up to date, so for now, we just delay slightly.
// This obviously has the possibility of introducing time-based bugs.
2013-09-10 02:07:12 +00:00
context . setTimeout ( renderSession , RENDER _SESSION _DELAY ) ;
2013-08-19 00:54:32 +00:00
}
/ * *
* the mixers object is a list . In order to find one by key ,
* you must iterate . Convenience method to locate a particular
* mixer by id .
* /
2014-11-21 23:16:00 +00:00
function getMixer ( mixerId ) {
return allMixers [ mixerId ] ;
}
function getMixerByResourceId ( resourceId , mode ) {
var mixerPair = mixersByResourceId [ resourceId ] ;
if ( ! mixerPair ) { return null ; }
if ( mode === undefined ) {
return mixerPair ;
}
else {
if ( mode == MIX _MODES . MASTER ) {
return mixerPair . master ;
}
else {
return mixerPair . personal ;
}
}
}
function getMixerByTrackId ( trackId , mode ) {
var mixerPair = mixersByTrackId [ trackId ] ;
if ( ! mixerPair ) { return null ; }
if ( mode === undefined ) {
return mixerPair ;
}
else {
if ( mode == MIX _MODES . MASTER ) {
return mixerPair . master ;
}
else {
return mixerPair . personal ;
}
}
2012-11-03 20:25:23 +00:00
}
function renderSession ( ) {
2013-02-14 07:02:05 +00:00
$ ( '#session-mytracks-container' ) . empty ( ) ;
2013-06-24 03:08:38 +00:00
$ ( '.session-track' ) . remove ( ) ; // Remove previous tracks
2013-09-06 02:27:43 +00:00
var $voiceChat = $ ( '#voice-chat' ) ;
$voiceChat . hide ( ) ;
2013-01-30 16:50:43 +00:00
_updateMixers ( ) ;
2012-11-03 20:25:23 +00:00
_renderTracks ( ) ;
2014-01-05 03:47:23 +00:00
_renderLocalMediaTracks ( ) ;
2013-02-07 04:58:41 +00:00
_wireTopVolume ( ) ;
2013-04-10 15:01:29 +00:00
_wireTopMix ( ) ;
2013-02-07 04:58:41 +00:00
_addVoiceChat ( ) ;
2013-05-22 05:03:34 +00:00
_initDialogs ( ) ;
2013-06-24 03:08:38 +00:00
if ( $ ( '.session-livetracks .track' ) . length === 0 ) {
$ ( '.session-livetracks .when-empty' ) . show ( ) ;
}
2015-02-01 23:14:22 +00:00
2014-01-05 03:47:23 +00:00
if ( $ ( '.session-recordings .track' ) . length === 0 ) {
$ ( '.session-recordings .when-empty' ) . show ( ) ;
$ ( '.session-recording-name-wrapper' ) . hide ( ) ;
2014-01-06 20:35:35 +00:00
$ ( '.session-recordings .recording-controls' ) . hide ( ) ;
2015-02-01 23:14:22 +00:00
} else {
$ ( '.session-recordings .when-empty' ) . hide ( ) ;
$ ( '.session-recording-name-wrapper' ) . show ( ) ;
$ ( '.session-recordings .recording-controls' ) . show ( ) ;
2014-01-05 03:47:23 +00:00
}
2015-02-01 23:14:22 +00:00
// Handle long labels:
$ ( ".track-label" ) . dotdotdot ( )
$ ( ".session-recording-name" ) . dotdotdot ( )
} // renderSession
2013-05-12 05:43:36 +00:00
2013-05-22 05:03:34 +00:00
function _initDialogs ( ) {
configureTrackDialog . initialize ( ) ;
2013-05-23 12:46:40 +00:00
addNewGearDialog . initialize ( ) ;
2013-01-30 16:50:43 +00:00
}
2014-11-21 23:16:00 +00:00
// Get the latest list of underlying audio mixer channels, and populates:
// * mixersByResourceId - a hash of resourceId / { master: mixer, personal: mixer } personal: can be null in case of PeerAudioInputMusicGroup
// * mixersByTrackId - a hash of track id / {master: mixer, personal: mixer}.
// * allMixers - a hash of mixer.id / mixer
// * masterMixers - array of master mode mixers
// * personalMixers - array of personal mode mixers
2013-01-30 16:50:43 +00:00
function _updateMixers ( ) {
2014-11-17 23:16:30 +00:00
masterMixers = context . jamClient . SessionGetAllControlState ( true ) ;
personalMixers = context . jamClient . SessionGetAllControlState ( false ) ;
2015-01-21 04:14:48 +00:00
context . jamClient
2014-11-11 22:21:29 +00:00
2014-11-21 23:16:00 +00:00
//logger.debug("masterMixers", masterMixers)
//logger.debug("personalMixers", personalMixers)
mixersByResourceId = { }
mixersByTrackId = { }
allMixers = { }
var i ;
for ( i = 0 ; i < masterMixers . length ; i ++ ) {
var masterMixer = masterMixers [ i ] ;
allMixers [ masterMixer . id ] = masterMixer ; // populate allMixers by mixer.id
// populate mixer pair
var mixerPair = { }
mixersByResourceId [ masterMixer . rid ] = mixerPair
mixersByTrackId [ masterMixer . id ] = mixerPair
mixerPair . master = masterMixer ;
}
for ( i = 0 ; i < personalMixers . length ; i ++ ) {
var personalMixer = personalMixers [ i ] ;
if ( personalMixer . group _id == ChannelGroupIds . MediaTrackGroup ) {
continue ;
}
allMixers [ personalMixer . id ] = personalMixer
// populate other side of mixer pair
var mixerPair = mixersByResourceId [ personalMixer . rid ]
if ( ! mixerPair ) {
if ( personalMixer . group _id != ChannelGroupIds . MonitorGroup ) {
logger . warn ( "there is no master version of " , personalMixer )
}
mixerPair = { }
mixersByResourceId [ personalMixer . rid ] = mixerPair
}
mixersByTrackId [ personalMixer . id ] = mixerPair ;
mixerPair . personal = personalMixer ;
}
2013-04-10 15:01:29 +00:00
// Always add a hard-coded simplified 'mixer' for the L2M mix
2014-11-09 15:13:22 +00:00
2014-11-11 22:21:29 +00:00
/ * *
var l2m _mixer = {
id : '__L2M__' ,
range _low : - 80 ,
range _high : 20 ,
volume _left : context . jamClient . SessionGetMasterLocalMix ( )
} ;
mixers . push ( l2m _mixer ) ; * /
2012-10-21 23:03:46 +00:00
}
2014-11-17 23:16:30 +00:00
function _mixersForGroupId ( groupId , mixMode ) {
2014-01-05 03:47:23 +00:00
var foundMixers = [ ] ;
2014-11-17 23:16:30 +00:00
var mixers = mixMode == MIX _MODES . MASTER ? masterMixers : personalMixers ;
2014-01-05 03:47:23 +00:00
$ . each ( mixers , function ( index , mixer ) {
2014-11-17 23:16:30 +00:00
if ( mixer . group _id === groupId ) {
2014-01-05 03:47:23 +00:00
foundMixers . push ( mixer ) ;
}
} ) ;
return foundMixers ;
}
2015-01-09 21:15:12 +00:00
function _mixersForGroupIds ( groupIds , mixMode ) {
var foundMixers = [ ] ;
var mixers = mixMode == MIX _MODES . MASTER ? masterMixers : personalMixers ;
$ . each ( mixers , function ( index , mixer ) {
var groupIdLen = groupIds . length ;
for ( var i = 0 ; i < groupIdLen ; i ++ ) {
if ( mixer . group _id === groupIds [ i ] ) {
foundMixers . push ( mixer ) ;
}
}
} ) ;
return foundMixers ;
}
2014-12-17 15:08:45 +00:00
function _getMyVoiceChatMixers ( ) {
var mixers = _mixersForGroupId ( ChannelGroupIds . AudioInputChatGroup , sessionModel . getMixMode ( ) ) ;
if ( mixers . length == 0 ) { return null ; }
var oppositeMixers = _mixersForGroupId ( ChannelGroupIds . AudioInputChatGroup , ! sessionModel . getMixMode ( ) ) ;
if ( oppositeMixers . length == 0 ) {
logger . warn ( "unable to find opposite mixer for voice chat" ) ;
return null ;
}
var mixer = mixers [ 0 ] ;
var oppositeMixer = oppositeMixers [ 0 ] ;
return {
mixer : mixer ,
oppositeMixer : oppositeMixer ,
vuMixer : mixer ,
muteMixer : mixer
}
}
2014-03-03 22:49:53 +00:00
2014-11-17 23:16:30 +00:00
function _clientIdForUserInputMixer ( mixerId , mixMode ) {
2014-03-03 22:49:53 +00:00
var found = null ;
2014-11-17 23:16:30 +00:00
var mixers = mixMode == MIX _MODES . MASTER ? masterMixers : personalMixers ;
2014-03-03 22:49:53 +00:00
$ . each ( mixers , function ( index , mixer ) {
if ( mixer . group _id === ChannelGroupIds . UserMusicInputGroup && mixer . id == mixerId ) {
found = mixer . client _id ;
return false ;
}
} ) ;
return found ;
}
2013-08-23 03:20:07 +00:00
// TODO FIXME - This needs to support multiple tracks for an individual
// client id and group.
2013-09-05 04:24:28 +00:00
function _mixerForClientId ( clientId , groupIds , usedMixers ) {
2014-06-20 17:50:31 +00:00
//logger.debug("clientId", clientId, "groupIds", groupIds, "mixers", mixers)
2013-02-14 07:02:05 +00:00
var foundMixer = null ;
$ . each ( mixers , function ( index , mixer ) {
if ( mixer . client _id === clientId ) {
for ( var i = 0 ; i < groupIds . length ; i ++ ) {
if ( mixer . group _id === groupIds [ i ] ) {
2013-09-05 04:24:28 +00:00
if ( ! ( mixer . id in usedMixers ) ) {
foundMixer = mixer ;
return false ;
}
2013-02-14 07:02:05 +00:00
}
}
2013-02-05 05:10:37 +00:00
}
} ) ;
2013-02-14 07:02:05 +00:00
return foundMixer ;
2013-01-30 16:50:43 +00:00
}
2014-11-17 23:16:30 +00:00
function _groupedMixersForClientId ( clientId , groupIds , usedMixers , mixMode ) {
2014-11-12 02:39:46 +00:00
//logger.debug("clientId", clientId, "groupIds", groupIds, "mixers", mixers)
var foundMixers = { } ;
2014-11-17 23:16:30 +00:00
var mixers = mixMode == MIX _MODES . MASTER ? masterMixers : personalMixers ;
2014-11-12 02:39:46 +00:00
$ . each ( mixers , function ( index , mixer ) {
if ( mixer . client _id === clientId ) {
for ( var i = 0 ; i < groupIds . length ; i ++ ) {
if ( mixer . group _id === groupIds [ i ] ) {
if ( ( mixer . groupId != ChannelGroupIds . UserMusicInputGroup ) && ! ( mixer . id in usedMixers ) ) {
var mixers = foundMixers [ mixer . group _id ]
if ( ! mixers ) {
mixers = [ ]
foundMixers [ mixer . group _id ] = mixers ;
}
mixers . push ( mixer )
}
}
}
}
} ) ;
return foundMixers ;
}
2013-02-07 04:58:41 +00:00
function _wireTopVolume ( ) {
2013-07-31 23:39:10 +00:00
var gainPercent = 0 ;
2013-03-14 03:29:57 +00:00
var mixerIds = [ ] ;
2014-11-17 23:16:30 +00:00
var mixers = sessionModel . isMasterMixMode ( ) ? masterMixers : personalMixers ;
2013-02-07 04:58:41 +00:00
$ . each ( mixers , function ( index , mixer ) {
2014-11-11 22:21:29 +00:00
if ( sessionModel . isMasterMixMode ( ) && mixer . group _id === ChannelGroupIds . MasterGroup ) {
2013-03-14 03:29:57 +00:00
mixerIds . push ( mixer . id ) ;
2013-07-31 23:39:10 +00:00
gainPercent = percentFromMixerValue (
2013-02-13 05:30:07 +00:00
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
2013-02-07 04:58:41 +00:00
}
2014-11-11 22:21:29 +00:00
else if ( ! sessionModel . isMasterMixMode ( ) && mixer . group _id === ChannelGroupIds . MonitorGroup ) {
2013-03-14 03:29:57 +00:00
mixerIds . push ( mixer . id ) ;
2014-11-11 22:21:29 +00:00
gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
2013-02-07 04:58:41 +00:00
}
} ) ;
2014-11-17 23:16:30 +00:00
if ( mixerIds . length == 0 ) {
logger . debug ( "did not find master/monitor volume" , mixers )
}
2013-07-31 23:39:10 +00:00
var faderId = mixerIds . join ( ',' ) ;
2014-06-13 17:51:03 +00:00
var $volume = $ ( '#volume' ) ;
$volume . attr ( 'mixer-id' , faderId ) ;
2013-07-31 23:39:10 +00:00
var faderOpts = {
faderId : faderId ,
faderType : "horizontal" ,
width : 50 ,
style : {
"background-image" : "none" ,
"background-repeat" : "no-repeat" ,
"height" : "24px"
}
} ;
2014-06-13 17:51:03 +00:00
context . JK . FaderHelpers . renderFader ( $volume , faderOpts ) ;
$volume . on ( 'fader_change' , faderChanged ) ;
2013-07-31 23:39:10 +00:00
// Visually update fader to underlying mixer start value.
2013-08-07 20:04:22 +00:00
// Always do this, even if gainPercent is zero.
2014-02-13 20:17:16 +00:00
2013-08-07 20:04:22 +00:00
context . JK . FaderHelpers . setFaderValue ( faderId , gainPercent ) ;
2013-02-07 04:58:41 +00:00
}
2013-04-10 15:01:29 +00:00
/ * *
* This control has it 's own Set/Get methods, so we don' t need to
* line it up with some mixer later . We ' ll use a special mixer - id value
* to let us know we ' re dealing with the mix control .
* /
function _wireTopMix ( ) {
var $mixSlider = $ ( '#l2m' ) ;
var l2m _mixer = {
range _low : - 80 ,
range _high : 20 ,
volume _left : context . jamClient . SessionGetMasterLocalMix ( )
} ;
2013-09-05 21:51:29 +00:00
// var gainPercent = percentFromMixerValue(
// l2m_mixer.range_low, l2m_mixer.range_high, l2m_mixer.volume_left);
2013-07-31 23:39:10 +00:00
var faderId = '#l2m' ; // also the selector for renderFader
var faderOpts = {
faderId : faderId ,
faderType : "horizontal" ,
width : 70 ,
style : {
"background-image" : "none" ,
"background-repeat" : "no-repeat" ,
"height" : "24px"
}
} ;
2014-06-13 17:51:03 +00:00
context . JK . FaderHelpers . renderFader ( $mixSlider , faderOpts ) ;
$mixSlider . on ( 'fader_change' , l2mChanged ) ;
2013-09-05 21:51:29 +00:00
2014-03-03 22:13:23 +00:00
var value = context . jamClient . SessionGetMasterLocalMix ( ) ;
context . JK . FaderHelpers . setFaderValue ( faderId , percentFromMixerValue ( - 80 , 20 , value ) ) ;
2013-07-31 23:39:10 +00:00
}
/ * *
* This has a specialized jamClient call , so custom handler .
* /
2014-06-13 17:51:03 +00:00
function l2mChanged ( e , data ) {
2014-03-03 22:13:23 +00:00
//var dbValue = context.JK.FaderHelpers.convertLinearToDb(newValue);
2014-06-13 17:51:03 +00:00
context . jamClient . SessionSetMasterLocalMix ( data . percentage - 80 ) ;
2013-04-10 15:01:29 +00:00
}
2013-02-07 04:58:41 +00:00
function _addVoiceChat ( ) {
2013-02-08 05:08:05 +00:00
// If, and only if, there is a mixer in group 3 (voice chat)
// Add the voice chat controls below my tracks, and hook up the mixer.
// Assumption is that there is only ever one, so we just take the first one.
2014-12-17 15:08:45 +00:00
var voiceChatMixers = _getMyVoiceChatMixers ( ) ;
if ( voiceChatMixers ) {
var mixer = voiceChatMixers . mixer ;
var $voiceChat = $ ( '#voice-chat' ) ;
$voiceChat . show ( ) ;
$voiceChat . attr ( 'mixer-id' , mixer . id ) ;
var $voiceChatGain = $voiceChat . find ( '.voicechat-gain' ) ;
$voiceChatGain . attr ( 'mixer-id' , mixer . id ) ;
var $voiceChatMute = $voiceChat . find ( '.voicechat-mute' ) . attr ( 'mixer-id' , mixer . id ) . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , voiceChatMixers . oppositeMixer )
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var faderOpts = {
faderId : mixer . id ,
faderType : "horizontal" ,
width : 50
} ;
context . JK . FaderHelpers . renderFader ( $voiceChatGain , faderOpts ) ;
$voiceChatGain . on ( 'fader_change' , faderChanged ) ;
context . JK . FaderHelpers . setFaderValue ( mixer . id , gainPercent ) ;
if ( mixer . mute ) {
_toggleVisualMuteControl ( $voiceChatMute , mixer . mute ) ;
}
}
2013-02-07 04:58:41 +00:00
}
2014-01-05 03:47:23 +00:00
function _renderLocalMediaTracks ( ) {
2015-01-22 02:16:52 +00:00
//console.log("_renderLocalMediaTracks")
2015-01-09 21:15:12 +00:00
// local media mixers come in different groups (MediaTrack, JamTrack, Metronome), but peer mixers are always PeerMediaTrackGroup
var localMediaMixers = _mixersForGroupIds ( [ ChannelGroupIds . MediaTrackGroup , ChannelGroupIds . JamTrackGroup , ChannelGroupIds . MetronomeGroup ] , MIX _MODES . MASTER ) ;
2015-01-06 22:51:19 +00:00
var peerLocalMediaMixers = _mixersForGroupId ( ChannelGroupIds . PeerMediaTrackGroup , MIX _MODES . MASTER ) ;
2014-01-05 03:47:23 +00:00
2015-02-16 04:14:30 +00:00
var recordedBackingTracks = sessionModel . recordedBackingTracks ( ) ;
var backingTracks = sessionModel . backingTracks ( ) ;
2015-01-06 22:51:19 +00:00
// with mixer info, we use these to decide what kind of tracks are open in the backend
2014-01-05 03:47:23 +00:00
2015-01-06 22:51:19 +00:00
// each mixer has a media_type field, which describes the type of media track it is.
// * JamTrack
// * BackingTrack
// * RecordingTrack
// * MetronomeTrack
// * "" - adhoc track (not supported visually)
2014-01-05 03:47:23 +00:00
2015-01-06 22:51:19 +00:00
// it is supposed to be the case that there are only one type of track open at a time, however, that's a business policy/logic
// constraint; and may be buggy. **So, we should render whatever we have, so that it's obvious what's really going on.**
2014-01-05 03:47:23 +00:00
2015-01-06 22:51:19 +00:00
// so, let's group up all mixers by type, and then ask them to be rendered
2014-01-05 03:47:23 +00:00
2015-01-06 22:51:19 +00:00
var recordingTrackMixers = [ ] ;
var backingTrackMixers = [ ] ;
var jamTrackMixers = [ ] ;
var metronomeTrackMixers = [ ] ;
var adhocTrackMixers = [ ] ;
2014-01-05 03:47:23 +00:00
2015-02-16 04:14:30 +00:00
function groupByType ( mixers , isLocalMixer ) {
2015-01-06 22:51:19 +00:00
context . _ . each ( mixers , function ( mixer ) {
var mediaType = mixer . media _type ;
2015-02-13 17:36:03 +00:00
var groupId = mixer . group _id ;
2015-02-16 04:14:30 +00:00
// mediaType == null is for backwards compat with older clients. Can be removed soon
if ( mediaType == null || mediaType == "" || mediaType == 'RecordingTrack' ) {
// additional check; if we can match an id in backing tracks or recorded backing track,
// we need to remove it from the recorded track set, but move it to the backing track set
var isBackingTrack = false
if ( recordedBackingTracks ) {
context . _ . each ( recordedBackingTracks , function ( recordedBackingTrack ) {
if ( mixer . id == 'L' + recordedBackingTrack . client _track _id ) {
isBackingTrack = true ;
return false ; // break
}
} )
}
if ( backingTracks ) {
context . _ . each ( backingTracks , function ( backingTrack ) {
if ( mixer . id == 'L' + backingTrack . client _track _id ) {
isBackingTrack = true ;
return false ; // break
}
} )
}
if ( isBackingTrack ) {
backingTrackMixers . push ( mixer )
}
else {
recordingTrackMixers . push ( mixer ) ;
}
} else if ( mediaType == 'PeerMediaTrack' || mediaType == 'BackingTrack' ) {
2015-01-21 04:14:48 +00:00
// BackingTrack
2015-01-06 22:51:19 +00:00
backingTrackMixers . push ( mixer ) ;
2015-02-13 17:36:03 +00:00
} else if ( mediaType == 'MetronomeTrack' || groupId == ChannelGroupIds . MetronomeGroup ) {
2015-02-12 20:05:25 +00:00
// Metronomes come across with a blank media type, so check group_id:
2015-01-06 22:51:19 +00:00
metronomeTrackMixers . push ( mixer ) ;
2015-01-22 02:16:52 +00:00
} else if ( mediaType == 'JamTrack' ) {
2015-01-06 22:51:19 +00:00
jamTrackMixers . push ( mixer ) ;
2015-02-13 17:36:03 +00:00
mixer . group _id == ChannelGroupIds . MediaTrackGroup ;
2015-02-12 20:05:25 +00:00
} else if ( mediaType == null || mediaType == "" || mediaType == 'RecordingTrack' ) {
// mediaType == null is for backwards compat with older clients. Can be removed soon
recordingTrackMixers . push ( mixer )
2015-01-22 02:16:52 +00:00
} else {
2015-02-16 04:15:34 +00:00
logger . warn ( "Unknown track type: " + mediaType )
2015-01-06 22:51:19 +00:00
adhocTrackMixers . push ( mixer ) ;
}
} ) ;
}
2014-01-05 03:47:23 +00:00
2015-02-16 04:14:30 +00:00
groupByType ( localMediaMixers , true ) ;
groupByType ( peerLocalMediaMixers , false ) ;
2014-01-05 03:47:23 +00:00
2015-01-06 22:51:19 +00:00
if ( recordingTrackMixers . length > 0 ) {
renderRecordingTracks ( recordingTrackMixers )
}
if ( backingTrackMixers . length > 0 ) {
renderBackingTracks ( backingTrackMixers )
}
if ( jamTrackMixers . length > 0 ) {
renderJamTracks ( jamTrackMixers ) ;
}
if ( metronomeTrackMixers . length > 0 ) {
2015-01-21 04:14:48 +00:00
renderMetronomeTracks ( metronomeTrackMixers ) ;
2015-01-06 22:51:19 +00:00
}
if ( adhocTrackMixers . length > 0 ) {
logger . warn ( "some tracks are open that we don't know how to show" )
}
2015-02-01 23:14:22 +00:00
2015-01-06 22:51:19 +00:00
}
2015-02-16 04:01:06 +00:00
// this method is pretty complicated because it forks on a key bit of state:
// sessionModel.isPlayingRecording()
// a backing track opened as part of a recording has a different behavior and presence on the server (recording.recorded_backing_tracks)
// than a backing track opend ad-hoc (connection.backing_tracks)
2015-01-06 22:51:19 +00:00
function renderBackingTracks ( backingTrackMixers ) {
2015-02-01 23:14:22 +00:00
2015-02-16 04:01:06 +00:00
var backingTracks = [ ]
if ( sessionModel . isPlayingRecording ( ) ) {
// only return managed mixers for recorded backing tracks
2015-02-16 04:14:30 +00:00
backingTrackMixers = context . _ . filter ( backingTrackMixers , function ( mixer ) { return mixer . managed || mixer . managed === undefined } )
2015-02-16 04:01:06 +00:00
backingTracks = sessionModel . recordedBackingTracks ( ) ;
}
else {
// only return un-managed (ad-hoc) mixers for normal backing tracks
backingTracks = sessionModel . backingTracks ( ) ;
backingTrackMixers = context . _ . filter ( backingTrackMixers , function ( mixer ) { return ! mixer . managed } )
if ( backingTrackMixers . length > 1 ) {
app . notify ( {
2015-02-16 04:14:30 +00:00
title : "Multiple Backing Tracks Encountered" ,
2015-02-16 04:01:06 +00:00
text : "Only one backing track can be open a time." ,
icon _url : "/assets/content/icon_alert_big.png"
} ) ;
return false ;
}
}
2015-01-16 02:28:34 +00:00
2015-02-16 04:01:06 +00:00
var noCorrespondingTracks = false ;
$ . each ( backingTrackMixers , function ( index , mixer ) {
console . log ( "hunting for backing tracks:" , backingTrackMixers , backingTracks )
2015-01-21 04:14:48 +00:00
// find the track or tracks that correspond to the mixer
var correspondingTracks = [ ]
2015-02-16 04:01:06 +00:00
var noCorrespondingTracks = false ;
if ( sessionModel . isPlayingRecording ( ) ) {
$ . each ( backingTracks , function ( i , backingTrack ) {
2015-02-16 04:14:30 +00:00
if ( mixer . persisted _track _id == backingTrack . client _track _id || // occurs if this client is the one that opened the track
mixer . id == 'L' + backingTrack . client _track _id ) { // occurs if this client is a remote participant
2015-02-16 04:01:06 +00:00
correspondingTracks . push ( backingTrack )
}
} ) ;
}
else
{
// if this is just an open backing track, then we can assume that the 1st backingTrackMixer is ours
correspondingTracks . push ( backingTracks [ 0 ] )
}
if ( correspondingTracks . length == 0 ) {
2015-01-21 04:14:48 +00:00
noCorrespondingTracks = true ;
2015-02-16 04:14:30 +00:00
logger . debug ( "renderBackingTracks: could not map backing tracks" )
2015-01-21 04:14:48 +00:00
app . notify ( {
2015-02-16 04:01:06 +00:00
title : "Unable to Open Backing Track" ,
2015-01-21 04:14:48 +00:00
text : "Could not correlate server and client tracks" ,
2015-02-16 04:01:06 +00:00
icon _url : "/assets/content/icon_alert_big.png"
} ) ;
2015-01-21 04:14:48 +00:00
return false ;
}
2015-01-16 02:28:34 +00:00
2015-02-16 04:01:06 +00:00
// now we have backing track and mixer in hand; we can render
var backingTrack = correspondingTracks [ 0 ]
2015-01-21 04:14:48 +00:00
2015-02-16 04:01:06 +00:00
// pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer)
// if it's a locally opened track (MediaTrackGroup), then we can say this person is the opener
var isOpener = mixer . group _id == ChannelGroupIds . MediaTrackGroup ;
2015-01-21 04:14:48 +00:00
2015-02-16 04:14:30 +00:00
var shortFilename = context . JK . getNameOfFile ( backingTrack . filename ) ;
2015-02-16 04:01:06 +00:00
if ( ! sessionModel . isPlayingRecording ( ) ) {
// if a recording is being played back, do not set this header, because renderRecordedTracks already did
// ugly.
2015-02-16 04:14:30 +00:00
$ ( '.session-recording-name' ) . text ( shortFilename ) ;
2015-02-16 04:01:06 +00:00
}
var instrumentIcon = context . JK . getInstrumentIcon45 ( backingTrack . instrument _id ) ;
var photoUrl = "/assets/content/icon_recording.png" ;
2015-01-21 04:14:48 +00:00
2015-02-16 04:14:30 +00:00
2015-01-21 04:14:48 +00:00
// Default trackData to participant + no Mixer state.
var trackData = {
2015-02-16 04:01:06 +00:00
trackId : backingTrack . id ,
clientId : backingTrack . client _id ,
2015-02-16 04:14:30 +00:00
name : 'Backing' ,
filename : backingTrack . filename ,
2015-01-21 04:14:48 +00:00
instrumentIcon : instrumentIcon ,
avatar : photoUrl ,
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
2015-02-16 04:01:06 +00:00
showLoop : ! sessionModel . isPlayingRecording ( ) ,
2015-01-21 04:14:48 +00:00
mixerId : "" ,
2015-02-16 04:01:06 +00:00
avatarClass : 'avatar-recording' ,
2015-01-21 04:14:48 +00:00
preMasteredClass : ""
} ;
2015-01-16 02:28:34 +00:00
2015-01-21 04:14:48 +00:00
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var muteClass = "enabled" ;
if ( mixer . mute ) {
muteClass = "muted" ;
2015-01-16 02:28:34 +00:00
}
2015-01-21 04:14:48 +00:00
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData . vuMixerId = mixer . id ; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData . muteMixerId = mixer . id ; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
2015-02-16 04:01:06 +00:00
if ( sessionModel . isPersonalMixMode ( ) || ! isOpener ) {
2015-01-21 04:14:48 +00:00
trackData . mediaControlsDisabled = true ;
trackData . mediaTrackOpener = isOpener ;
}
2015-02-16 04:14:30 +00:00
_addRecordingTrack ( trackData , mixer ) ;
2015-02-16 04:01:06 +00:00
} ) ;
2015-01-06 22:51:19 +00:00
}
function renderJamTracks ( jamTrackMixers ) {
2015-01-21 04:14:48 +00:00
console . log ( "rendering jam tracks" )
2015-01-09 21:15:12 +00:00
var jamTracks = sessionModel . jamTracks ( ) ;
// pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer)
// if it's a locally opened track (JamTrackGroup), then we can say this person is the opener
var isOpener = jamTrackMixers [ 0 ] . group _id == ChannelGroupIds . JamTrackGroup ;
// using the server's info in conjuction with the client's, draw the recording tracks
if ( jamTracks ) {
$ ( '.session-recording-name' ) . text ( sessionModel . getCurrentSession ( ) . jam _track . name ) ;
var noCorrespondingTracks = false ;
$ . each ( jamTrackMixers , function ( index , mixer ) {
var preMasteredClass = "" ;
// find the track or tracks that correspond to the mixer
var correspondingTracks = [ ]
$ . each ( jamTracks , function ( i , jamTrack ) {
if ( mixer . id . indexOf ( "L" ) == 0 ) {
if ( mixer . id . substring ( 1 ) == jamTrack . id ) {
correspondingTracks . push ( jamTrack ) ;
}
else {
// this should not be possible
2015-01-16 02:28:34 +00:00
alert ( "Invalid state: the backing track had neither persisted_track_id or persisted_client_id" ) ;
2015-01-09 21:15:12 +00:00
}
}
} ) ;
if ( correspondingTracks . length == 0 ) {
noCorrespondingTracks = true ;
app . notify ( {
title : "Unable to Open JamTrack" ,
text : "Could not correlate server and client tracks" ,
icon _url : "/assets/content/icon_alert_big.png" } ) ;
return false ;
}
// prune found recorded tracks
jamTracks = $ . grep ( jamTracks , function ( value ) {
return $ . inArray ( value , correspondingTracks ) < 0 ;
} ) ;
var oneOfTheTracks = correspondingTracks [ 0 ] ;
var instrumentIcon = context . JK . getInstrumentIcon45 ( oneOfTheTracks . instrument _id ) ;
var photoUrl = "/assets/content/icon_recording.png" ;
var name = oneOfTheTracks . part
if ( ! name ) {
name = oneOfTheTracks . instrument ;
}
// Default trackData to participant + no Mixer state.
var trackData = {
trackId : oneOfTheTracks . id ,
clientId : oneOfTheTracks . client _id ,
name : name ,
instrumentIcon : instrumentIcon ,
avatar : photoUrl ,
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
mixerId : "" ,
avatarClass : 'avatar-recording' ,
preMasteredClass : ""
} ;
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var muteClass = "enabled" ;
if ( mixer . mute ) {
muteClass = "muted" ;
}
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData . vuMixerId = mixer . id ; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData . muteMixerId = mixer . id ; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
if ( sessionModel . isPersonalMixMode ( ) || ! isOpener ) {
trackData . mediaControlsDisabled = true ;
trackData . mediaTrackOpener = isOpener ;
}
_addRecordingTrack ( trackData ) ;
} ) ;
if ( ! noCorrespondingTracks && jamTracks . length > 0 ) {
logger . error ( "unable to find all jam tracks against client tracks" ) ;
app . notify ( { title : "All tracks not found" ,
text : "Some tracks in the jam tracks are not present in the playback" ,
icon _url : "/assets/content/icon_alert_big.png" } )
}
}
2015-01-06 22:51:19 +00:00
}
function renderMetronomeTracks ( metronomeTrackMixers ) {
2015-01-21 04:14:48 +00:00
var metronomeActive = sessionModel . metronomeActive ( ) ;
console . log ( "rendering metronome track" , metronomeActive )
// pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer)
// if it's a locally opened track (MediaTrackGroup), then we can say this person is the opener
var isOpener = metronomeTrackMixers [ 0 ] . group _id == ChannelGroupIds . MediaTrackGroup ;
var name = "Metronome"
// using the server's info in conjuction with the client's, draw the recording tracks
if ( metronomeActive && metronomeTrackMixers . length > 0 ) {
var metronome = { active : metronomeActive }
$ ( '.session-recording-name' ) . text ( name ) ; //sessionModel.getCurrentSession().backing_track_path);
var noCorrespondingTracks = false ;
var mixer = metronomeTrackMixers [ 0 ]
var preMasteredClass = "" ;
// find the track or tracks that correspond to the mixer
var correspondingTracks = [ ]
correspondingTracks . push ( metronome ) ;
if ( correspondingTracks . length == 0 ) {
noCorrespondingTracks = true ;
app . notify ( {
title : "Unable to Open Metronome" ,
text : "Could not correlate server and client tracks" ,
icon _url : "/assets/content/icon_metronome_small.png" } ) ;
return false ;
}
// prune found recorded tracks
// Metronomes = $.grep(Metronomes, function(value) {
// return $.inArray(value, correspondingTracks) < 0;
// });
var oneOfTheTracks = correspondingTracks [ 0 ] ;
var instrumentIcon = context . JK . getInstrumentIcon45 ( oneOfTheTracks . instrument _id ) ;
var photoUrl = "/assets/content/icon_metronome_small.png" ;
2015-01-22 02:16:52 +00:00
// var trackData = {
// trackId: oneOfTheTracks.id,
// clientId: oneOfTheTracks.client_id,
// name: "Tempo",
// instrumentIcon: photoUrl,
// avatar: instrumentIcon,
// latency: "good",
// gainPercent: 0,
// muteClass: 'hidden',
// mixerId: "",
// avatarClass : 'avatar-recording',
// preMasteredClass: "",
// hideVU: true,
// faderChanged : tempoFaderChanged,
// showMetronomeControls: true
// };
// _addRecordingTrack(trackData);
2015-01-21 04:14:48 +00:00
// Default trackData to participant + no Mixer state.
var trackData = {
2015-01-22 02:16:52 +00:00
trackId : "MS" + oneOfTheTracks . id ,
2015-01-21 04:14:48 +00:00
clientId : oneOfTheTracks . client _id ,
2015-02-01 23:14:22 +00:00
name : "Metronome" ,
2015-01-22 02:16:52 +00:00
instrumentIcon : photoUrl ,
avatar : instrumentIcon ,
2015-01-21 04:14:48 +00:00
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
mixerId : "" ,
avatarClass : 'avatar-recording' ,
2015-01-22 02:16:52 +00:00
preMasteredClass : "" ,
showMetronomeControls : true
2015-01-21 04:14:48 +00:00
} ;
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var muteClass = "enabled" ;
if ( mixer . mute ) {
muteClass = "muted" ;
}
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData . vuMixerId = mixer . id ; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData . muteMixerId = mixer . id ; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
if ( sessionModel . isPersonalMixMode ( ) || ! isOpener ) {
2015-01-22 02:16:52 +00:00
//trackData.mediaControlsDisabled = true;
2015-01-21 04:14:48 +00:00
trackData . mediaTrackOpener = isOpener ;
}
2015-02-16 04:14:30 +00:00
_addRecordingTrack ( trackData , mixer ) ;
2015-01-21 04:14:48 +00:00
} // if
2015-02-12 20:05:25 +00:00
setFormFromMetronome ( )
2015-01-06 22:51:19 +00:00
}
function renderRecordingTracks ( recordingMixers ) {
// get the server's info for the recording
var recordedTracks = sessionModel . recordedTracks ( ) ;
2015-02-16 04:14:30 +00:00
var recordedBackingTracks = sessionModel . recordedBackingTracks ( ) ;
2014-01-05 03:47:23 +00:00
2015-01-06 22:51:19 +00:00
// pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between Local vs Peer)
// if it's a locally opened track (MediaTrackGroup), then we can say this person is the opener
var isOpener = recordingMixers [ 0 ] . group _id == ChannelGroupIds . MediaTrackGroup ;
// using the server's info in conjuction with the client's, draw the recording tracks
if ( recordedTracks ) {
$ ( '.session-recording-name' ) . text ( sessionModel . getCurrentSession ( ) . claimed _recording . name ) ;
2015-02-16 04:15:34 +00:00
console . log ( "renderRecordingTracks" , recordingMixers , recordedTracks )
2015-01-06 22:51:19 +00:00
var noCorrespondingTracks = false ;
$ . each ( recordingMixers , function ( index , mixer ) {
var preMasteredClass = "" ;
// find the track or tracks that correspond to the mixer
var correspondingTracks = [ ]
$ . each ( recordedTracks , function ( i , recordedTrack ) {
if ( mixer . id . indexOf ( "L" ) == 0 ) {
if ( mixer . id . substring ( 1 ) == recordedTrack . client _track _id ) {
correspondingTracks . push ( recordedTrack ) ;
}
}
else if ( mixer . id . indexOf ( "C" ) == 0 ) {
if ( mixer . id . substring ( 1 ) == recordedTrack . client _id ) {
correspondingTracks . push ( recordedTrack ) ;
preMasteredClass = "pre-mastered-track" ;
}
}
else {
// this should not be possible
alert ( "Invalid state: the recorded track had neither persisted_track_id or persisted_client_id" ) ;
2014-01-05 03:47:23 +00:00
}
2015-01-06 22:51:19 +00:00
} ) ;
if ( correspondingTracks . length == 0 ) {
noCorrespondingTracks = true ;
2015-02-16 04:14:30 +00:00
logger . debug ( "unable to correlate all recorded tracks" , recordingMixers , recordedTracks )
2015-01-06 22:51:19 +00:00
app . notify ( {
title : "Unable to Open Recording" ,
text : "Could not correlate server and client tracks" ,
icon _url : "/assets/content/icon_alert_big.png" } ) ;
return false ;
}
// prune found recorded tracks
recordedTracks = $ . grep ( recordedTracks , function ( value ) {
return $ . inArray ( value , correspondingTracks ) < 0 ;
} ) ;
var oneOfTheTracks = correspondingTracks [ 0 ] ;
var instrumentIcon = context . JK . getInstrumentIcon45 ( oneOfTheTracks . instrument _id ) ;
var photoUrl = "/assets/content/icon_recording.png" ;
var name = oneOfTheTracks . user . name ;
if ( ! ( name ) ) {
name = oneOfTheTracks . user . first _name + ' ' + oneOfTheTracks . user . last _name ;
}
// Default trackData to participant + no Mixer state.
var trackData = {
trackId : oneOfTheTracks . id ,
clientId : oneOfTheTracks . client _id ,
name : name ,
instrumentIcon : instrumentIcon ,
avatar : photoUrl ,
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
mixerId : "" ,
avatarClass : 'avatar-recording' ,
preMasteredClass : preMasteredClass
} ;
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var muteClass = "enabled" ;
if ( mixer . mute ) {
muteClass = "muted" ;
}
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData . vuMixerId = mixer . id ; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData . muteMixerId = mixer . id ; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
if ( sessionModel . isPersonalMixMode ( ) || ! isOpener ) {
trackData . mediaControlsDisabled = true ;
trackData . mediaTrackOpener = isOpener ;
}
2015-02-16 04:14:30 +00:00
_addRecordingTrack ( trackData , mixer ) ;
2015-01-06 22:51:19 +00:00
} ) ;
if ( ! noCorrespondingTracks && recordedTracks . length > 0 ) {
logger . error ( "unable to find all recorded tracks against client tracks" ) ;
app . notify ( { title : "All tracks not found" ,
text : "Some tracks in the recording are not present in the playback" ,
icon _url : "/assets/content/icon_alert_big.png" } )
2014-01-05 03:47:23 +00:00
}
2015-01-06 22:51:19 +00:00
}
2014-01-05 03:47:23 +00:00
}
2014-11-13 15:20:08 +00:00
function trackMuteSelected ( e , data ) {
var muteOption = data . muteOption ; // muteOption is going to be either 'master' or 'personal'. We mute the correct one, based on track info
var $muteControl = $ ( this ) ;
// mixer is the mixer object returned from the backend corresponding to the mixer in this particular mode
// oppositeMixer is the mixer correspond to the opposite mode.
// Note that oppositeMixer is not ever set for ChannelGroupIds.AudioInputMusicGroup or ChannelGroupIds.MediaTrackGroup
var mixer = $muteControl . data ( 'mixer' )
var oppositeMixer = $muteControl . data ( 'opposite-mixer' )
2014-11-21 23:16:00 +00:00
logger . debug ( "muting tracks. current mixer id=" + mixer . id + ", opposite mixer id=" + oppositeMixer . id )
var mixerPair = { }
if ( sessionModel . isMasterMixMode ( ) ) {
mixerPair . master = mixer ;
mixerPair . personal = oppositeMixer ;
2014-11-13 15:20:08 +00:00
}
2014-11-21 23:16:00 +00:00
else {
mixerPair . master = oppositeMixer ;
mixerPair . personal = mixer ;
}
if ( muteOption == 'master' ) {
_toggleAudioMute ( mixerPair . master . id , true , mixerPair . master . mode ) ;
_toggleAudioMute ( mixerPair . personal . id , true , mixerPair . personal . mode ) ;
}
else {
_toggleAudioMute ( mixerPair . personal . id , true , mixerPair . personal . mode ) ;
_toggleAudioMute ( mixerPair . master . id , false , mixerPair . master . mode ) ;
}
_toggleVisualMuteControl ( $muteControl , true ) ;
}
// find backend mixer based on track data, and target client_id
function findMixerForTrack ( client _id , track , myTrack ) {
var mixer = null ; // what is the best mixer for this track/client ID?
var oppositeMixer = null ; // what is the corresponding mixer in the opposite mode?
var vuMixer = null ;
var muteMixer = null ;
var mixMode = sessionModel . getMixMode ( ) ;
if ( myTrack ) {
2015-02-16 04:14:30 +00:00
2014-11-21 23:16:00 +00:00
// when it's your track, look it up by the backend resource ID
mixer = getMixerByTrackId ( track . client _track _id , mixMode )
vuMixer = mixer ;
muteMixer = mixer ;
// sanity checks
if ( mixer && ( mixer . group _id != ChannelGroupIds . AudioInputMusicGroup ) ) { logger . error ( "found local mixer that was not of groupID: AudioInputMusicGroup" , mixer ) }
if ( mixer ) {
// find the matching AudioInputMusicGroup for the opposite mode
oppositeMixer = getMixerByTrackId ( track . client _track _id , ! mixMode )
if ( mixMode == MIX _MODES . PERSONAL ) {
muteMixer = oppositeMixer ; // make the master mixer the mute mixer
}
// sanity checks
if ( ! oppositeMixer ) { logger . error ( "unable to find opposite mixer for local mixer" , mixer ) }
else if ( oppositeMixer . group _id != ChannelGroupIds . AudioInputMusicGroup ) { logger . error ( "found local mixer in opposite mode that was not of groupID: AudioInputMusicGroup" , mixer , oppositeMixer ) }
}
else {
logger . debug ( "local track is not present: " , track )
}
}
else {
if ( mixMode === MIX _MODES . MASTER ) {
// when it's a remote track and in master mode, we should find the PeerAudioInputMusicGroup
mixer = getMixerByTrackId ( track . client _track _id , MIX _MODES . MASTER )
if ( mixer && ( mixer . group _id != ChannelGroupIds . PeerAudioInputMusicGroup ) ) { logger . error ( "found remote mixer that was not of groupID: PeerAudioInputMusicGroup" , mixer ) }
vuMixer = mixer ;
muteMixer = mixer ;
if ( mixer ) {
// we should be able to find a UserMusicInputGroup for this clientId in personal mode
var oppositeMixers = _groupedMixersForClientId ( client _id , [ ChannelGroupIds . UserMusicInputGroup ] , { } , MIX _MODES . PERSONAL ) ;
if ( oppositeMixers [ ChannelGroupIds . UserMusicInputGroup ] ) { oppositeMixer = oppositeMixers [ ChannelGroupIds . UserMusicInputGroup ] [ 0 ] ; }
if ( ! oppositeMixer ) { logger . error ( "unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer" , mixer ) }
}
}
else {
// when it's a remote track and in personal mode, we want the 'Peer Stream', which is UserMusicInputGroup
// this spans N tracks for the remote user
var mixers = _groupedMixersForClientId ( client _id , [ ChannelGroupIds . UserMusicInputGroup ] , { } , MIX _MODES . PERSONAL ) ;
if ( mixers [ ChannelGroupIds . UserMusicInputGroup ] ) { mixer = mixers [ ChannelGroupIds . UserMusicInputGroup ] [ 0 ] ; }
vuMixer = mixer ;
muteMixer = mixer ;
if ( mixer ) {
// now grab the PeerAudioInputMusicGroup in master mode to satisfy the 'opposite' mixer
oppositeMixer = getMixerByTrackId ( track . client _track _id , MIX _MODES . MASTER )
if ( ! oppositeMixer ) { logger . debug ( "unable to find a PeerAudioInputMusicGroup master mixer matching a UserMusicInput" , track . client _track _id , mixersByTrackId ) }
else if ( oppositeMixer . group _id != ChannelGroupIds . PeerAudioInputMusicGroup ) { logger . error ( "found remote mixer that was not of groupID: PeerAudioInputMusicGroup" , mixer ) }
vuMixer = oppositeMixer ; // for personal mode, use the PeerAudioInputMusicGroup's VUs
}
}
2014-11-13 15:20:08 +00:00
}
2014-11-21 23:16:00 +00:00
return {
mixer : mixer ,
oppositeMixer : oppositeMixer ,
vuMixer : vuMixer ,
muteMixer : muteMixer
}
2014-11-13 15:20:08 +00:00
}
2012-11-03 20:25:23 +00:00
function _renderTracks ( ) {
2013-05-15 05:59:09 +00:00
myTracks = [ ] ;
2013-02-14 07:02:05 +00:00
// Participants are here now, but the mixers don't update right away.
// Draw tracks from participants, then setup timers to look for the
// mixers that go with those participants, if they're missing.
2014-11-21 23:16:00 +00:00
lookingForMixers = [ ] // clear this back out as we are restarting from scratch
2013-02-14 07:02:05 +00:00
lookingForMixersCount = 0 ;
2013-03-02 19:02:42 +00:00
$ . each ( sessionModel . participants ( ) , function ( index , participant ) {
2013-02-14 07:02:05 +00:00
var name = participant . user . name ;
if ( ! ( name ) ) {
name = participant . user . first _name + ' ' + participant . user . last _name ;
}
2014-11-21 23:16:00 +00:00
var myTrack = app . clientId == participant . client _id ;
2013-09-05 04:24:28 +00:00
2013-05-15 05:59:09 +00:00
// 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 ) ;
// Default trackData to participant + no Mixer state.
var trackData = {
trackId : track . id ,
2013-05-22 11:48:37 +00:00
connection _id : track . connection _id ,
2014-11-21 23:16:00 +00:00
client _track _id : track . client _track _id ,
client _resource _id : track . client _resource _id ,
2013-05-15 05:59:09 +00:00
clientId : participant . client _id ,
name : name ,
instrumentIcon : instrumentIcon ,
avatar : photoUrl ,
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
2014-01-05 03:47:23 +00:00
mixerId : "" ,
avatarClass : 'avatar-med' ,
2014-12-17 15:08:45 +00:00
preMasteredClass : "" ,
myTrack : myTrack
2013-05-15 05:59:09 +00:00
} ;
2014-11-21 23:16:00 +00:00
var mixerData = findMixerForTrack ( participant . client _id , track , myTrack )
var mixer = mixerData . mixer ;
var vuMixer = mixerData . vuMixer ;
var muteMixer = mixerData . muteMixer ;
var oppositeMixer = mixerData . oppositeMixer ;
2014-11-11 22:21:46 +00:00
2014-11-21 23:16:00 +00:00
if ( mixer && oppositeMixer ) {
2013-05-15 05:59:09 +00:00
myTrack = ( mixer . group _id === ChannelGroupIds . AudioInputMusicGroup ) ;
2015-01-18 21:46:40 +00:00
if ( ! myTrack ) {
2015-01-19 16:23:51 +00:00
// it only makes sense to track 'audio established' for tracks that don't belong to you
2015-01-18 21:46:40 +00:00
sessionModel . setAudioEstablished ( participant . client _id , true ) ;
}
2013-05-15 05:59:09 +00:00
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var muteClass = "enabled" ;
if ( mixer . mute ) {
muteClass = "muted" ;
}
2014-03-05 06:15:46 +00:00
2013-05-15 05:59:09 +00:00
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ;
2014-11-21 23:16:00 +00:00
trackData . vuMixerId = vuMixer . id ;
trackData . oppositeMixer = oppositeMixer ;
trackData . muteMixerId = muteMixer . id ;
2014-03-03 22:13:23 +00:00
trackData . noaudio = false ;
2014-11-11 22:21:29 +00:00
trackData . group _id = mixer . group _id ;
2013-09-24 07:22:41 +00:00
context . jamClient . SessionSetUserName ( participant . client _id , name ) ;
2014-03-03 22:13:23 +00:00
2013-05-15 05:59:09 +00:00
} else { // No mixer to match, yet
2014-11-21 23:16:00 +00:00
lookingForMixers . push ( { track : track , clientId : participant . client _id } )
2014-03-03 22:13:23 +00:00
trackData . noaudio = true ;
2013-05-15 05:59:09 +00:00
if ( ! ( lookingForMixersTimer ) ) {
2014-03-20 11:53:26 +00:00
logger . debug ( "waiting for mixer to show up for track: " + track . id )
2013-08-19 00:59:49 +00:00
lookingForMixersTimer = context . setInterval ( lookForMixers , 500 ) ;
2013-05-15 05:59:09 +00:00
}
2013-02-10 02:00:29 +00:00
}
2013-09-06 12:34:57 +00:00
2014-03-03 22:13:23 +00:00
var allowDelete = myTrack && index > 0 ;
2014-11-21 23:16:00 +00:00
_addTrack ( allowDelete , trackData , mixer , oppositeMixer ) ;
2013-05-22 05:03:34 +00:00
2013-05-15 05:59:09 +00:00
// Show settings icons only for my tracks
if ( myTrack ) {
2013-05-24 01:16:00 +00:00
myTracks . push ( trackData ) ;
2013-09-06 02:04:36 +00:00
}
2013-05-15 05:59:09 +00:00
} ) ;
2012-11-03 20:25:23 +00:00
} ) ;
2013-05-22 05:03:34 +00:00
configureTrackDialog = new context . JK . ConfigureTrackDialog ( app , myTracks , sessionId , sessionModel ) ;
2014-02-23 04:41:42 +00:00
addNewGearDialog = new context . JK . AddNewGearDialog ( app , self ) ;
2013-09-12 12:02:13 +00:00
}
2014-11-21 23:16:00 +00:00
function connectTrackToMixer ( trackSelector , track , mixerId , gainPercent , groupId ) {
2013-08-28 03:05:53 +00:00
var vuOpts = $ . extend ( { } , trackVuOpts ) ;
var faderOpts = $ . extend ( { } , trackFaderOpts ) ;
faderOpts . faderId = mixerId ;
var vuLeftSelector = trackSelector + " .track-vu-left" ;
var vuRightSelector = trackSelector + " .track-vu-right" ;
var faderSelector = trackSelector + " .track-gain" ;
2014-11-11 22:21:29 +00:00
var $fader = $ ( faderSelector ) . attr ( 'mixer-id' , mixerId ) . data ( 'groupId' , groupId )
2015-01-06 22:51:19 +00:00
if ( track . mediaControlsDisabled ) {
$fader . data ( 'media-controls-disabled' , true ) . data ( 'media-track-opener' , track . mediaTrackOpener ) // this we be applied later to the fader handle $element
2014-11-21 23:16:00 +00:00
}
2013-09-05 04:24:28 +00:00
var $track = $ ( trackSelector ) ;
2013-08-28 03:05:53 +00:00
// Set mixer-id attributes and render VU/Fader
2015-01-22 02:16:52 +00:00
if ( ! track . hideVU ) {
context . JK . VuHelpers . renderVU ( vuLeftSelector , vuOpts ) ;
$track . find ( '.track-vu-left' ) . attr ( 'mixer-id' , track . vuMixerId + '_vul' ) . data ( 'groupId' , groupId )
context . JK . VuHelpers . renderVU ( vuRightSelector , vuOpts ) ;
$track . find ( '.track-vu-right' ) . attr ( 'mixer-id' , track . vuMixerId + '_vur' ) . data ( 'groupId' , groupId )
}
if ( track . showMetronomeControls ) {
2015-02-12 20:05:25 +00:00
$track . find ( '.metronome-selects' ) . removeClass ( "hidden" )
2015-01-22 02:16:52 +00:00
} else {
$track . find ( '.metronome-selects' ) . addClass ( "hidden" )
}
// if (track.showMetroSound) {
// $track.find('.metro-sound-select').removeClass("hidden")
// }
2014-06-13 17:51:03 +00:00
context . JK . FaderHelpers . renderFader ( $fader , faderOpts ) ;
2013-08-28 03:05:53 +00:00
// Set gain position
context . JK . FaderHelpers . setFaderValue ( mixerId , gainPercent ) ;
2014-11-21 23:16:00 +00:00
2015-01-22 02:16:52 +00:00
if ( track . faderChanged ) {
$fader . on ( 'fader_change' , track . faderChanged ) ;
} else {
$fader . on ( 'fader_change' , faderChanged ) ;
}
return $track ;
2013-08-28 03:05:53 +00:00
}
2013-02-14 07:02:05 +00:00
// Function called on an interval when participants change. Mixers seem to
// show up later, so we render the tracks from participants, but keep track
// of the ones there weren't any mixers for, and continually try to find them
// and get them connected to the mixers underneath.
function lookForMixers ( ) {
lookingForMixersCount ++ ;
_updateMixers ( ) ;
2013-09-05 04:24:28 +00:00
var usedMixers = { } ;
2013-02-14 07:02:05 +00:00
var keysToDelete = [ ] ;
2014-11-21 23:16:00 +00:00
context . _ . each ( lookingForMixers , function ( data ) {
var clientId = data . clientId ;
var track = data . track ;
var myTrack = app . clientId == clientId ;
var mixerData = findMixerForTrack ( clientId , track , myTrack )
var mixer = mixerData . mixer ;
var oppositeMixer = mixerData . oppositeMixer ;
var vuMixer = mixerData . vuMixer ;
var muteMixer = mixerData . muteMixer ;
if ( mixer && oppositeMixer ) {
2015-01-18 21:46:40 +00:00
if ( ! myTrack ) {
2015-01-19 16:23:51 +00:00
// it only makes sense to track 'audio established' for tracks that don't belong to you
2015-01-18 21:46:40 +00:00
sessionModel . setAudioEstablished ( clientId , true ) ;
}
2014-11-21 23:16:00 +00:00
var participant = ( sessionModel . getParticipant ( clientId ) || { name : 'unknown' } ) . name ;
logger . debug ( "found mixer=" + mixer . id + ", participant=" + participant )
usedMixers [ mixer . id ] = true ;
keysToDelete . push ( data ) ;
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var trackSelector = 'div.track[track-id="' + track . id + '"]' ;
connectTrackToMixer ( trackSelector , track , mixer . id , gainPercent , mixer . group _id ) ;
var $track = $ ( 'div.track[client-id="' + clientId + '"]' ) ;
var $trackIconMute = $track . find ( '.track-icon-mute' )
$trackIconMute . attr ( 'mixer-id' , muteMixer . id ) . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , oppositeMixer )
$trackIconMute . muteSelector ( ) . on ( EVENTS . MUTE _SELECTED , trackMuteSelected )
// hide overlay for all tracks associated with this client id (if one mixer is present, then all tracks are valid)
$ ( '.disabled-track-overlay' , $track ) . hide ( ) ;
$ ( '.track-connection' , $track ) . removeClass ( 'red yellow green' ) . addClass ( 'grey' ) ;
// Set mute state
_toggleVisualMuteControl ( $trackIconMute , mixer . mute || oppositeMixer . mute ) ;
}
else {
// if 1 second has gone by and still no mixer, then we gray the participant's tracks
if ( lookingForMixersCount == 2 ) {
var $track = $ ( 'div.track[client-id="' + clientId + '"]' ) ;
$ ( '.disabled-track-overlay' , $track ) . show ( ) ;
$ ( '.track-connection' , $track ) . removeClass ( 'red yellow green' ) . addClass ( 'red' ) ;
2014-03-03 22:13:23 +00:00
}
2015-01-18 21:46:40 +00:00
// if 5 seconds have gone by and no mixer, then we tell the server failed to establish audio
else if ( lookingForMixersCount == 10 ) {
if ( ! myTrack ) {
2015-01-19 16:23:51 +00:00
// it only makes sense to track 'audio established' for tracks that don't belong to you
2015-01-18 21:46:40 +00:00
sessionModel . setAudioEstablished ( clientId , false ) ;
}
}
2014-11-21 23:16:00 +00:00
var participant = ( sessionModel . getParticipant ( clientId ) || { user : { name : 'unknown' } } ) . user . name ;
logger . debug ( "still looking for mixer for participant=" + participant + ", clientId=" + clientId )
}
} )
2013-02-14 07:02:05 +00:00
for ( var i = 0 ; i < keysToDelete . length ; i ++ ) {
2014-11-21 23:16:00 +00:00
var index = lookingForMixers . indexOf ( keysToDelete [ i ] ) ;
lookingForMixers . splice ( index , 1 ) ;
2013-02-14 07:02:05 +00:00
}
2014-11-21 23:16:00 +00:00
if ( lookingForMixers . length === 0 ||
2013-08-19 00:59:49 +00:00
lookingForMixersCount > 20 ) {
2013-02-14 07:02:05 +00:00
lookingForMixersCount = 0 ;
2014-11-21 23:16:00 +00:00
lookingForMixers = [ ]
2013-02-14 07:02:05 +00:00
context . clearTimeout ( lookingForMixersTimer ) ;
lookingForMixersTimer = null ;
}
}
2013-01-30 16:50:43 +00:00
// Given a mixerID and a value between 0.0-1.0,
// light up the proper VU lights.
2014-11-21 23:16:00 +00:00
function _updateVU ( mixerId , value , isClipping ) {
2013-08-19 00:54:32 +00:00
// Special-case for mono tracks. If mono, and it's a _vul id,
// update both sides, otherwise do nothing.
// If it's a stereo track, just do the normal thing.
var selector ;
var pureMixerId = mixerId . replace ( "_vul" , "" ) ;
pureMixerId = pureMixerId . replace ( "_vur" , "" ) ;
2014-11-21 23:16:00 +00:00
var mixer = getMixer ( pureMixerId ) ;
2013-08-19 00:54:32 +00:00
if ( mixer ) {
if ( ! ( mixer . stereo ) ) { // mono track
if ( mixerId . substr ( - 4 ) === "_vul" ) {
// Do the left
2014-06-13 17:51:03 +00:00
selector = $ ( '#tracks [mixer-id="' + pureMixerId + '_vul"]' ) ;
2013-08-19 00:54:32 +00:00
context . JK . VuHelpers . updateVU ( selector , value ) ;
// Do the right
2014-06-13 17:51:03 +00:00
selector = $ ( '#tracks [mixer-id="' + pureMixerId + '_vur"]' ) ;
2013-08-19 00:54:32 +00:00
context . JK . VuHelpers . updateVU ( selector , value ) ;
} // otherwise, it's a mono track, _vur event - ignore.
} else { // stereo track
2014-06-13 17:51:03 +00:00
selector = $ ( '#tracks [mixer-id="' + mixerId + '"]' ) ;
2013-08-19 00:54:32 +00:00
context . JK . VuHelpers . updateVU ( selector , value ) ;
}
}
2013-01-30 16:50:43 +00:00
}
2014-11-21 23:16:00 +00:00
function _addTrack ( allowDelete , trackData , mixer , oppositeMixer ) {
2014-03-03 22:13:23 +00:00
2013-07-20 15:38:52 +00:00
var parentSelector = '#session-mytracks-container' ;
var $destination = $ ( parentSelector ) ;
2013-02-05 05:10:37 +00:00
if ( trackData . clientId !== app . clientId ) {
2013-07-20 15:38:52 +00:00
parentSelector = '#session-livetracks-container' ;
$destination = $ ( parentSelector ) ;
2013-06-24 03:08:38 +00:00
$ ( '.session-livetracks .when-empty' ) . hide ( ) ;
2013-02-05 05:10:37 +00:00
}
2012-10-21 23:03:46 +00:00
var template = $ ( '#template-session-track' ) . html ( ) ;
2014-01-05 03:47:23 +00:00
var newTrack = $ ( context . JK . fillTemplate ( template , trackData ) ) ;
2014-03-03 22:13:23 +00:00
var audioOverlay = $ ( '.disabled-track-overlay' , newTrack ) ;
2014-11-13 15:20:08 +00:00
var $trackIconMute = newTrack . find ( '.track-icon-mute' )
$trackIconMute . muteSelector ( ) . on ( EVENTS . MUTE _SELECTED , trackMuteSelected )
2014-11-21 23:16:00 +00:00
$trackIconMute . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , oppositeMixer )
2014-11-13 15:20:08 +00:00
2014-03-03 22:13:23 +00:00
audioOverlay . hide ( ) ; // always start with overlay hidden, and only show if no audio persists
2013-02-05 05:10:37 +00:00
$destination . append ( newTrack ) ;
2013-05-22 05:03:34 +00:00
2013-07-26 14:46:38 +00:00
// Render VU meters and gain fader
2013-09-05 04:24:28 +00:00
var trackSelector = parentSelector + ' .session-track[track-id="' + trackData . trackId + '"]' ;
2013-08-28 03:05:53 +00:00
var gainPercent = trackData . gainPercent || 0 ;
2014-11-21 23:16:00 +00:00
connectTrackToMixer ( trackSelector , trackData , trackData . mixerId , gainPercent , trackData . group _id ) ;
2013-07-20 15:38:52 +00:00
2013-05-22 05:03:34 +00:00
var $closeButton = $ ( '#div-track-close' , 'div[track-id="' + trackData . trackId + '"]' ) ;
2014-03-03 22:13:23 +00:00
if ( ! allowDelete ) {
2013-05-22 05:03:34 +00:00
$closeButton . hide ( ) ;
}
else {
$closeButton . click ( deleteTrack ) ;
}
2015-01-06 22:51:19 +00:00
// is this used?
2013-05-15 05:59:09 +00:00
tracks [ trackData . trackId ] = new context . JK . SessionTrack ( trackData . clientId ) ;
2012-10-21 23:03:46 +00:00
}
2014-01-05 03:47:23 +00:00
2015-02-16 04:14:30 +00:00
function _addRecordingTrack ( trackData , mixer ) {
2014-01-05 03:47:23 +00:00
var parentSelector = '#session-recordedtracks-container' ;
var $destination = $ ( parentSelector ) ;
2015-02-01 23:14:22 +00:00
2014-01-05 03:47:23 +00:00
var template = $ ( '#template-session-track' ) . html ( ) ;
var newTrack = $ ( context . JK . fillTemplate ( template , trackData ) ) ;
$destination . append ( newTrack ) ;
if ( trackData . preMasteredClass ) {
context . JK . helpBubble ( $ ( '.track-instrument' , newTrack ) , 'pre-processed-track' , { } , { offsetParent : newTrack . closest ( '.content-body' ) } ) ;
}
// Render VU meters and gain fader
var trackSelector = parentSelector + ' .session-track[track-id="' + trackData . trackId + '"]' ;
var gainPercent = trackData . gainPercent || 0 ;
2014-11-21 23:16:00 +00:00
var $track = connectTrackToMixer ( trackSelector , trackData , trackData . mixerId , gainPercent , null ) ;
var $trackIconMute = $track . find ( '.track-icon-mute' )
2015-01-06 22:51:19 +00:00
if ( trackData . mediaControlsDisabled ) {
$trackIconMute . data ( 'media-controls-disabled' , true ) . data ( 'media-track-opener' , trackData . mediaTrackOpener )
2014-11-21 23:16:00 +00:00
}
2015-02-16 04:14:30 +00:00
$trackIconMute . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , null )
2015-01-22 02:16:52 +00:00
2015-02-01 23:59:34 +00:00
if ( trackData . showLoop ) {
var $trackIconLoop = $track . find ( '.track-icon-loop' )
$trackIconLoop . show ( )
var loopBtn = $trackIconLoop . find ( '#loop-button' )
loopBtn . on ( 'click' , function ( event ) {
var loop = loopBtn . is ( ':checked' )
2015-02-16 04:14:30 +00:00
logger . debug ( "Looping: " , loop , trackData . filename ) ;
context . jamClient . SessionSetBackingTrackFileLoop ( trackData . filename , loop )
2015-02-01 23:59:34 +00:00
} )
}
2015-01-06 22:51:19 +00:00
// is this used?
2014-01-05 03:47:23 +00:00
tracks [ trackData . trackId ] = new context . JK . SessionTrack ( trackData . clientId ) ;
}
2013-07-26 14:46:38 +00:00
/ * *
* Will be called when fader changes . The fader id ( provided at subscribe time ) ,
* the new value ( 0 - 100 ) and whether the fader is still being dragged are passed .
* /
2014-06-13 17:51:03 +00:00
function faderChanged ( e , data ) {
var $target = $ ( this ) ;
var faderId = $target . attr ( 'mixer-id' ) ;
2014-11-11 22:21:29 +00:00
var groupId = $target . data ( 'groupId' ) ;
2013-07-26 14:46:38 +00:00
var mixerIds = faderId . split ( ',' ) ;
$ . each ( mixerIds , function ( i , v ) {
2014-06-13 17:51:03 +00:00
var broadcast = ! ( data . dragging ) ; // If fader is still dragging, don't broadcast
2013-08-02 21:16:49 +00:00
fillTrackVolumeObject ( v , broadcast ) ;
2014-06-13 17:51:03 +00:00
setMixerVolume ( v , data . percentage ) ;
2014-11-11 22:21:29 +00:00
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 ( v , data . percentage ) ;
}
2013-07-26 14:46:38 +00:00
} ) ;
}
2015-01-22 02:16:52 +00:00
// function tempoFaderChanged(e, data) {
// var $target = $(this);
// var faderId = $target.attr('mixer-id');
// var groupId = $target.data('groupId');
// var mixerIds = faderId.split(',');
// $.each(mixerIds, function(i,v) {
// // TODO Interpolate tempo values if we decide to go this way:
// 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
// }
// });
// }
2015-02-12 20:05:25 +00:00
function handleMetronomeCallback ( args ) {
console . log ( "MetronomeCallback: " , args )
metroTempo = args . bpm
// This isn't actually there, so we rely on the metroSound as set from select on form:
// metroSound = args.sound
context . JK . CurrentSessionModel . refreshCurrentSession ( true ) ;
}
2013-10-05 18:24:22 +00:00
function handleVolumeChangeCallback ( mixerId , isLeft , value , isMuted ) {
2013-08-07 20:04:22 +00:00
// Visually update mixer
2013-08-27 02:31:18 +00:00
// There is no need to actually set the back-end mixer value as the
// back-end will already have updated the audio mixer directly prior to sending
// me this event. I simply need to visually show the new fader position.
2013-08-07 20:04:22 +00:00
// TODO: Use mixer's range
var faderValue = percentFromMixerValue ( - 80 , 20 , value ) ;
context . JK . FaderHelpers . setFaderValue ( mixerId , faderValue ) ;
2014-12-17 15:08:45 +00:00
var $muteControl = $ ( '[control="mute"][mixer-id="' + mixerId + '"]' ) ;
_toggleVisualMuteControl ( $muteControl , isMuted ) ;
2013-08-07 20:04:22 +00:00
}
2014-11-21 23:16:00 +00:00
function handleBridgeCallback ( vuData ) {
var j ;
2013-01-31 05:23:30 +00:00
var eventName = null ;
var mixerId = null ;
var value = null ;
2014-11-21 23:16:00 +00:00
var vuInfo = null ;
for ( j = 0 ; j < vuData . length ; j ++ ) {
vuInfo = vuData [ j ] ;
var eventName = vuInfo [ 0 ] ;
var vuVal = 0.0 ;
if ( eventName === "vu" ) {
var mixerId = vuInfo [ 1 ] ;
var leftValue = vuInfo [ 2 ] ;
var leftClipping = vuInfo [ 3 ] ;
var rightValue = vuInfo [ 4 ] ;
var rightClipping = vuInfo [ 5 ] ;
// TODO - no guarantee range will be -80 to 20. Get from the
// GetControlState for this mixer which returns min/max
// value is a DB value from -80 to 20. Convert to float from 0.0-1.0
_updateVU ( mixerId + "_vul" , ( leftValue + 80 ) / 100 , leftClipping ) ;
_updateVU ( mixerId + "_vur" , ( rightValue + 80 ) / 100 , rightClipping ) ;
}
else if ( eventName === 'connection_status' ) {
var mixerId = vuInfo [ 1 ] ;
var value = vuInfo [ 2 ] ;
// Connection Quality Change
var connectionClass = 'green' ;
if ( value < 7 ) {
connectionClass = 'yellow' ;
}
if ( value < 4 ) {
connectionClass = 'red' ;
}
var mixerPair = getMixerByTrackId ( mixerId ) ;
2014-03-03 22:49:53 +00:00
2014-11-21 23:16:00 +00:00
var clientId = mixerPair ? mixerPair . master . client _id : null ;
if ( clientId ) {
var $connection = $ ( '.session-track[client-id="' + clientId + '"] .track-connection' ) ;
if ( $connection . length == 0 ) {
logger . debug ( "connection status: looking for clientId: " + clientId + ", mixer: " + mixerId )
}
else {
$connection . removeClass ( 'red yellow green grey' ) ;
$connection . addClass ( connectionClass ) ;
}
2013-01-31 05:23:30 +00:00
}
2014-11-21 23:16:00 +00:00
}
else if ( eventName === 'add' || eventName === 'remove' ) {
// TODO - _renderSession. Note I get streams of these in
// sequence, so have Nat fix, or buffer/spam protect
// Note - this is already handled from websocket events.
// However, there may be use of these two events to avoid
// the polling-style check for when a mixer has been added
// to match a participant track.
}
else {
logger . debug ( 'non-vu event: ' + JSON . stringify ( vuInfo ) ) ;
}
2013-01-30 16:50:43 +00:00
}
2014-11-21 23:16:00 +00:00
}
2015-02-16 04:14:30 +00:00
function handleBackingTrackSelectedCallback ( result ) {
if ( result . success ) {
logger . debug ( "backing track selected: " + result . file ) ;
rest . openBackingTrack ( { id : context . JK . CurrentSessionModel . id ( ) , backing _track _path : result . file } )
. done ( function ( response ) {
var openResult = context . jamClient . SessionOpenBackingTrackFile ( result . file , false ) ;
console . log ( "BackingTrackPlay response: %o" , openResult ) ;
//context.JK.CurrentSessionModel.refreshCurrentSession(true);
sessionModel . setBackingTrack ( result . file ) ;
} )
. fail ( function ( jqXHR ) {
app . notifyServerError ( jqXHR , "Unable to Open BackingTrack For Playback" ) ;
} )
2013-01-30 16:50:43 +00:00
2015-02-16 04:14:30 +00:00
}
else {
logger . debug ( "no backing track selected" )
}
}
2012-10-06 16:36:05 +00:00
function deleteSession ( evt ) {
2012-12-07 00:28:48 +00:00
var sessionId = $ ( evt . currentTarget ) . attr ( "action-id" ) ;
2012-10-06 16:36:05 +00:00
if ( sessionId ) {
$ . ajax ( {
type : "DELETE" ,
2013-02-26 03:54:09 +00:00
url : "/api/sessions/" + sessionId ,
success : function ( response ) {
2014-02-06 13:03:44 +00:00
context . location = "/client#/home" ;
2013-02-26 03:54:09 +00:00
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
logger . error ( "Error deleting session " + sessionId ) ;
}
} ) ;
2012-10-06 16:36:05 +00:00
}
}
2013-05-22 05:03:34 +00:00
function deleteTrack ( evt ) {
var trackId = $ ( evt . currentTarget ) . attr ( "track-id" ) ;
2013-05-23 12:46:40 +00:00
sessionModel . deleteTrack ( sessionId , trackId ) ;
2013-05-22 05:03:34 +00:00
}
2014-11-21 23:16:00 +00:00
function _toggleVisualMuteControl ( $control , mute ) {
if ( mute ) {
2013-01-31 16:32:32 +00:00
$control . removeClass ( 'enabled' ) ;
$control . addClass ( 'muted' ) ;
} else {
$control . removeClass ( 'muted' ) ;
$control . addClass ( 'enabled' ) ;
}
}
2014-11-21 23:16:00 +00:00
function _toggleAudioMute ( mixerId , muting , mode ) {
2013-03-15 02:44:51 +00:00
fillTrackVolumeObject ( mixerId ) ;
2013-01-31 16:32:32 +00:00
context . trackVolumeObject . mute = muting ;
2014-11-21 23:16:00 +00:00
if ( mode === undefined ) {
mode = sessionModel . getMixMode ( ) ;
}
context . jamClient . SessionSetControlState ( mixerId , mode ) ;
2013-01-31 16:32:32 +00:00
}
2014-11-13 15:20:08 +00:00
function showMuteDropdowns ( $control ) {
$control . btOn ( ) ;
}
2013-01-31 16:32:32 +00:00
function toggleMute ( evt ) {
var $control = $ ( evt . currentTarget ) ;
var muting = ( $control . hasClass ( 'enabled' ) ) ;
2013-03-15 02:44:51 +00:00
var mixerIds = $control . attr ( 'mixer-id' ) . split ( ',' ) ;
2014-11-13 15:20:08 +00:00
// track icons have a special mute behavior
if ( $control . is ( '.track-icon-mute' ) ) {
2015-01-06 22:51:19 +00:00
var mediaControlsDisabled = $control . data ( 'media-controls-disabled' ) ;
if ( mediaControlsDisabled ) {
var mediaTrackOpener = $control . data ( 'media-track-opener' ) ;
context . JK . prodBubble ( $control , 'media-controls-disabled' , { mediaTrackOpener : mediaTrackOpener } , { positions : [ 'bottom' ] , offsetParent : $control . closest ( '.screen' ) } )
2014-11-21 23:16:00 +00:00
return false ;
2014-11-13 15:20:08 +00:00
}
2014-11-21 23:16:00 +00:00
$ . each ( mixerIds , function ( i , v ) {
var mixerId = v ;
// behavior: if this is the user's track in personal mode, then we mute the track globally
// otherwise, for any other track (user+master mode, or remote track in any mode)
// we just mute the type of track for that mode
var mixer = $control . data ( 'mixer' ) ;
var oppositeMixer = $control . data ( 'opposite-mixer' )
2014-12-17 15:08:45 +00:00
if ( mixer && oppositeMixer && mixer . group _id == ChannelGroupIds . AudioInputMusicGroup ) {
// this is the user's local track; mute both personal and master mode
_toggleAudioMute ( mixer . id , muting , getMixer ( mixer . id ) . mode )
_toggleAudioMute ( oppositeMixer . id , muting , getMixer ( oppositeMixer . id ) . mode )
}
else {
_toggleAudioMute ( mixer . id , muting , getMixer ( mixer . id ) . mode )
}
2014-11-21 23:16:00 +00:00
// look for all controls matching this mixer id (important when it's personal mode + UserMusicInputGroup)
var $controls = $screen . find ( '.track-icon-mute[mixer-id=' + mixerId + ']' ) ;
_toggleVisualMuteControl ( $controls , muting ) ;
} ) ;
2014-11-13 15:20:08 +00:00
}
else {
2014-12-17 15:08:45 +00:00
// this path is taken for voice chat, but maybe others eventually
2014-11-13 15:20:08 +00:00
$ . each ( mixerIds , function ( i , v ) {
2014-12-17 15:08:45 +00:00
var mixerId = v ;
var mixer = $control . data ( 'mixer' ) ;
var oppositeMixer = $control . data ( 'opposite-mixer' )
if ( mixer && oppositeMixer && mixer . group _id == ChannelGroupIds . AudioInputChatGroup ) {
_toggleAudioMute ( mixer . id , muting , mixer . mode ) ;
_toggleAudioMute ( oppositeMixer . id , muting , oppositeMixer . mode ) ;
}
else {
_toggleAudioMute ( mixerId , muting ) ;
}
2014-11-13 15:20:08 +00:00
} ) ;
_toggleVisualMuteControl ( $control , muting ) ;
}
2013-01-31 16:32:32 +00:00
}
2013-03-24 20:47:45 +00:00
function fillTrackVolumeObject ( mixerId , broadcast ) {
2013-03-15 02:44:51 +00:00
_updateMixers ( ) ;
2013-03-24 20:47:45 +00:00
var _broadcast = true ;
if ( broadcast !== undefined ) {
_broadcast = broadcast ;
}
2014-11-21 23:16:00 +00:00
var mixer = getMixer ( mixerId ) ;
context . trackVolumeObject . clientID = mixer . client _id ;
context . trackVolumeObject . broadcast = _broadcast ;
context . trackVolumeObject . master = mixer . master ;
context . trackVolumeObject . monitor = mixer . monitor ;
context . trackVolumeObject . mute = mixer . mute ;
context . trackVolumeObject . name = mixer . name ;
context . trackVolumeObject . record = mixer . record ;
context . trackVolumeObject . volL = mixer . volume _left ;
context . trackVolumeObject . volR = mixer . volume _right ;
// trackVolumeObject doesn't have a place for range min/max
currentMixerRangeMin = mixer . range _low ;
currentMixerRangeMax = mixer . range _high ;
2013-02-03 22:47:17 +00:00
}
2013-02-10 02:00:29 +00:00
// Given a mixer's min/max and current value, return it as
// a percent from 0-100. Return an integer.
function percentFromMixerValue ( min , max , value ) {
2013-08-07 20:04:22 +00:00
try {
var range = Math . abs ( max - min ) ;
var magnitude = value - min ;
var percent = Math . round ( 100 * ( magnitude / range ) ) ;
return percent ;
} catch ( err ) {
return 0 ;
}
2013-02-10 02:00:29 +00:00
}
// Given a mixer's min/max and a percent value, return it as
// the mixer's value. Returns an integer.
function percentToMixerValue ( min , max , percent ) {
var range = Math . abs ( max - min ) ;
var multiplier = percent / 100 ; // Change 85 into 0.85
var value = min + ( multiplier * range ) ;
// Protect against percents < 0 and > 100
if ( value < min ) {
value = min ;
}
if ( value > max ) {
value = max ;
}
return value ;
}
2013-02-03 22:47:17 +00:00
2013-02-10 02:00:29 +00:00
// Given a volume percent (0-100), set the underlying
2013-02-03 19:48:39 +00:00
// audio volume level of the passed mixerId to the correct
// value.
function setMixerVolume ( mixerId , volumePercent ) {
2013-02-03 22:47:17 +00:00
// The context.trackVolumeObject has been filled with the mixer values
// that go with mixerId, and the range of that mixer
// has been set in currentMixerRangeMin-Max.
// All that needs doing is to translate the incoming percent
// into the real value ont the sliders range. Set Left/Right
// volumes on trackVolumeObject, and call SetControlState to stick.
2013-02-10 02:00:29 +00:00
var sliderValue = percentToMixerValue (
currentMixerRangeMin , currentMixerRangeMax , volumePercent ) ;
2014-07-31 01:05:04 +00:00
context . trackVolumeObject . volL = context . JK . FaderHelpers . convertPercentToAudioTaper ( volumePercent ) ;
context . trackVolumeObject . volR = context . JK . FaderHelpers . convertPercentToAudioTaper ( volumePercent ) ;
2013-04-10 15:01:29 +00:00
// Special case for L2M mix:
if ( mixerId === '__L2M__' ) {
2013-09-05 21:51:29 +00:00
logger . debug ( "L2M volumePercent=" + volumePercent ) ;
var dbValue = context . JK . FaderHelpers . convertLinearToDb ( volumePercent ) ;
context . jamClient . SessionSetMasterLocalMix ( dbValue ) ;
// context.jamClient.SessionSetMasterLocalMix(sliderValue);
2013-04-10 15:01:29 +00:00
} else {
2014-11-21 23:16:00 +00:00
context . jamClient . SessionSetControlState ( mixerId , sessionModel . getMixMode ( ) ) ;
2013-04-10 15:01:29 +00:00
}
2013-02-03 19:48:39 +00:00
}
2014-05-01 06:35:16 +00:00
function bailOut ( ) {
2015-01-09 02:35:39 +00:00
promptLeave = false ;
2014-05-01 06:35:16 +00:00
context . window . location = '/client#/home' ;
}
2014-02-25 02:20:17 +00:00
function sessionLeave ( evt ) {
evt . preventDefault ( ) ;
2014-04-30 16:44:37 +00:00
rateSession ( ) ;
2014-05-01 06:35:16 +00:00
bailOut ( ) ;
2014-04-30 16:44:37 +00:00
return false ;
}
2014-02-25 02:20:17 +00:00
2014-04-30 16:44:37 +00:00
function rateSession ( ) {
2014-05-01 01:48:57 +00:00
if ( rateSessionDialog === null ) {
2014-05-01 06:35:16 +00:00
rateSessionDialog = new context . JK . RateSessionDialog ( context . JK . app ) ;
2014-05-01 01:48:57 +00:00
rateSessionDialog . initialize ( ) ;
}
2014-05-01 06:35:16 +00:00
rateSessionDialog . showDialog ( ) ;
2014-04-30 16:44:37 +00:00
return true ;
2014-02-25 02:20:17 +00:00
}
2013-09-14 17:27:03 +00:00
function sessionResync ( evt ) {
evt . preventDefault ( ) ;
2013-09-16 01:55:12 +00:00
var response = context . jamClient . SessionAudioResync ( ) ;
2013-09-14 17:27:03 +00:00
if ( response ) {
app . notify ( {
"title" : "Error" ,
"text" : response ,
"icon_url" : "/assets/content/icon_alert_big.png" } ) ;
}
return false ;
}
2013-11-03 20:55:55 +00:00
// http://stackoverflow.com/questions/2604450/how-to-create-a-jquery-clock-timer
function updateRecordingTimer ( ) {
function pretty _time _string ( num ) {
return ( num < 10 ? "0" : "" ) + num ;
}
var total _seconds = ( new Date - startTimeDate ) / 1000 ;
var hours = Math . floor ( total _seconds / 3600 ) ;
total _seconds = total _seconds % 3600 ;
var minutes = Math . floor ( total _seconds / 60 ) ;
total _seconds = total _seconds % 60 ;
var seconds = Math . floor ( total _seconds ) ;
hours = pretty _time _string ( hours ) ;
minutes = pretty _time _string ( minutes ) ;
seconds = pretty _time _string ( seconds ) ;
if ( hours > 0 ) {
var currentTimeString = hours + ":" + minutes + ":" + seconds ;
}
else {
var currentTimeString = minutes + ":" + seconds ;
}
$recordingTimer . text ( '(' + currentTimeString + ')' ) ;
}
function displayStartingRecording ( ) {
$ ( '#recording-start-stop' ) . addClass ( 'currently-recording' ) ;
$ ( '#recording-status' ) . text ( "Starting..." )
}
function displayStartedRecording ( ) {
startTimeDate = new Date ;
$recordingTimer = $ ( "<span id='recording-timer'>(0:00)</span>" ) ;
var $recordingStatus = $ ( '<span></span>' ) . append ( "<span>Stop Recording</span>" ) . append ( $recordingTimer ) ;
$ ( '#recording-status' ) . html ( $recordingStatus ) ;
recordingTimerInterval = setInterval ( updateRecordingTimer , 1000 ) ;
}
function displayStoppingRecording ( data ) {
if ( data ) {
if ( data . reason ) {
app . notify ( {
"title" : "Recording Aborted" ,
"text" : "The recording was aborted due to '" + data . reason + '"' ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
}
}
$ ( '#recording-status' ) . text ( "Stopping..." ) ;
}
function displayDoneRecording ( ) {
if ( recordingTimerInterval ) {
clearInterval ( recordingTimerInterval ) ;
recordingTimerInterval = null ;
startTimeDate = null ;
}
$recordingTimer = null ;
$ ( '#recording-start-stop' ) . removeClass ( 'currently-recording' ) ;
$ ( '#recording-status' ) . text ( "Make a Recording" ) ;
}
function displayWhoCreated ( clientId ) {
if ( app . clientId != clientId ) { // don't show to creator
sessionModel . findUserBy ( { clientId : clientId } )
. done ( function ( user ) {
app . notify ( {
"title" : "Recording Started" ,
"text" : user . name + " started a recording" ,
"icon_url" : context . JK . resolveAvatarUrl ( user . photo _url )
} ) ;
} )
. fail ( function ( ) {
app . notify ( {
"title" : "Recording Started" ,
"text" : "Oops! Can't determine who started this recording" ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} )
}
}
function promptUserToSave ( recordingId ) {
rest . getRecording ( { id : recordingId } )
. done ( function ( recording ) {
2014-01-06 20:35:35 +00:00
recordingFinishedDialog . setRecording ( recording ) ;
2014-10-23 04:10:49 +00:00
app . layout . showDialog ( 'recordingFinished' ) . one ( EVENTS . DIALOG _CLOSED , function ( e , data ) {
if ( data . result && data . result . keep ) {
context . JK . prodBubble ( $recordingManagerViewer , 'file-manager-poke' , { } , { positions : [ 'top' , 'left' , 'right' , 'bottom' ] , offsetParent : $screen . parent ( ) } )
}
} )
2013-11-03 20:55:55 +00:00
} )
. fail ( app . ajaxError ) ;
}
2015-01-16 02:28:34 +00:00
function openBackingTrack ( e ) {
// just ignore the click if they are currently recording for now
if ( sessionModel . recordingModel . isRecording ( ) ) {
app . notify ( {
"title" : "Currently Recording" ,
"text" : "You can't open a backing track while creating a recording." ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
return false ;
}
2015-02-16 04:14:30 +00:00
context . jamClient . ShowSelectBackingTrackDialog ( "window.JK.HandleBackingTrackSelectedCallback" ) ;
//app.layout.showDialog('open-backing-track-dialog').one(EVENTS.DIALOG_CLOSED, function(e, data) {
// if(!data.cancel && data.result){
// sessionModel.setBackingTrack(data.result);
// }
//})
2015-01-16 02:28:34 +00:00
return false ;
}
2015-01-09 02:35:39 +00:00
function openJamTrack ( e ) {
// just ignore the click if they are currently recording for now
if ( sessionModel . recordingModel . isRecording ( ) ) {
app . notify ( {
"title" : "Currently Recording" ,
"text" : "You can't open a jam track while creating a recording." ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
return false ;
}
app . layout . showDialog ( 'open-jam-track-dialog' ) ;
return false ;
}
2015-01-21 04:14:48 +00:00
function openBackingTrackFile ( e ) {
2015-01-16 02:28:34 +00:00
// just ignore the click if they are currently recording for now
if ( sessionModel . recordingModel . isRecording ( ) ) {
2015-01-21 04:14:48 +00:00
app . notify ( {
"title" : "Currently Recording" ,
"text" : "You can't open a backing track while creating a recording." ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
return false ;
} else {
context . jamClient . openBackingTrackFile ( sessionModel . backing _track )
2015-02-03 15:25:45 +00:00
//context.JK.CurrentSessionModel.refreshCurrentSession(true);
2015-01-16 02:28:34 +00:00
}
2015-01-21 04:14:48 +00:00
return false ;
}
2015-02-15 20:00:36 +00:00
function unstableNTPClocks ( ) {
var unstable = [ ]
// This should be handled in the below loop, actually:
// var map = context.jamClient.getMyNetworkState()
// if (!map.ntp_stable) {
// unstable.push("self");
// }
var map ;
$ . each ( sessionModel . participants ( ) , function ( index , participant ) {
map = context . jamClient . getPeerState ( participant . client _id )
if ( ! map . ntp _stable ) {
var name = participant . user . name ;
if ( ! ( name ) ) {
name = participant . user . first _name + ' ' + participant . user . last _name ;
}
if ( app . clientId == participant . client _id ) {
name += " (This computer)"
}
unstable . push ( name )
}
} ) ;
return unstable
}
2015-01-21 04:14:48 +00:00
function openMetronome ( e ) {
// just ignore the click if they are currently recording for now
2015-02-15 20:00:36 +00:00
2015-01-21 04:14:48 +00:00
if ( sessionModel . recordingModel . isRecording ( ) ) {
app . notify ( {
"title" : "Currently Recording" ,
"text" : "You can't open a metronome while creating a recording." ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
return false ;
} else {
2015-02-15 20:00:36 +00:00
var unstable = unstableNTPClocks ( )
if ( unstable . length > 0 ) {
var names = unstable . join ( ", " )
console . log ( "Unstable clocks: " , names , unstable )
2015-01-21 04:14:48 +00:00
app . notify ( {
"title" : "Couldn't open metronome" ,
2015-02-15 20:00:36 +00:00
"text" : "The metronome feature requires that every user's computer in the session must agree on the current time. The computers of " + names + " have not successfully synchronized to the current time. The JamKazam service is trying to automatically correct this error condition. Please close this message, wait about 10 seconds, and then try opening the metronome again. If this problem persists after a couple of attempts, we recommend that the unsynchronized users restart the JamKazam application. If this error persists after a restart, please have the users with the issue contact support@jamkazam.com." ,
2015-01-21 04:14:48 +00:00
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
2015-02-15 20:00:36 +00:00
} else {
rest . openMetronome ( { id : sessionModel . id ( ) } )
. done ( function ( ) {
context . jamClient . SessionOpenMetronome ( 120 , "Click" , 1 , 0 )
context . JK . CurrentSessionModel . refreshCurrentSession ( true )
context . JK . CurrentSessionModel . refreshCurrentSession ( true )
} )
. fail ( function ( jqXHR ) {
console . log ( jqXHR , jqXHR )
app . notify ( {
"title" : "Couldn't open metronome" ,
"text" : "Couldn't inform the server to open metronome. msg=" + jqXHR . responseText ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
}
2015-01-16 02:28:34 +00:00
2015-01-21 04:14:48 +00:00
return false ;
}
2015-01-16 02:28:34 +00:00
}
2015-01-21 04:14:48 +00:00
2014-01-05 03:47:23 +00:00
function openRecording ( e ) {
// just ignore the click if they are currently recording for now
if ( sessionModel . recordingModel . isRecording ( ) ) {
app . notify ( {
"title" : "Currently Recording" ,
"text" : "You can't open a recording while creating a recording." ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
return false ;
}
if ( ! localRecordingsDialog . isShowing ( ) ) {
app . layout . showDialog ( 'localRecordings' ) ;
}
return false ;
}
2015-01-09 02:35:39 +00:00
function closeOpenMedia ( ) {
if ( sessionModel . recordedTracks ( ) ) {
closeRecording ( ) ;
}
2015-01-09 21:15:12 +00:00
else if ( sessionModel . jamTracks ( ) ) {
2015-01-09 02:35:39 +00:00
closeJamTrack ( ) ;
}
2015-01-21 04:14:48 +00:00
else if ( sessionModel . backingTrack ( ) && sessionModel . backingTrack ( ) . path ) {
closeBackingTrack ( ) ;
}
else if ( sessionModel . metronomeActive ( ) ) {
closeMetronomeTrack ( ) ;
}
2015-01-09 02:35:39 +00:00
else {
2015-02-03 15:25:45 +00:00
logger . error ( "don't know how to close open media" ) ;
2015-01-09 02:35:39 +00:00
}
2015-02-03 15:25:45 +00:00
return false ;
2015-01-09 02:35:39 +00:00
}
2015-01-16 02:28:34 +00:00
function closeBackingTrack ( ) {
rest . closeBackingTrack ( { id : sessionModel . id ( ) } )
. done ( function ( ) {
2015-02-03 15:25:45 +00:00
//sessionModel.refreshCurrentSession(true);
2015-01-16 02:28:34 +00:00
} )
. fail ( function ( jqXHR ) {
app . notify ( {
"title" : "Couldn't Close BackingTrack" ,
"text" : "Couldn't inform the server to close BackingTrack. msg=" + jqXHR . responseText ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
2015-02-03 15:25:45 +00:00
// '' closes all open backing tracks
context . jamClient . SessionCloseBackingTrackFile ( '' ) ;
2015-01-16 02:28:34 +00:00
return false ;
2015-01-21 04:14:48 +00:00
}
2015-01-16 02:28:34 +00:00
2015-01-09 02:35:39 +00:00
function closeJamTrack ( ) {
rest . closeJamTrack ( { id : sessionModel . id ( ) } )
. done ( function ( ) {
2015-01-21 04:14:48 +00:00
sessionModel . refreshCurrentSession ( true ) ;
2015-01-09 02:35:39 +00:00
} )
. fail ( function ( jqXHR ) {
app . notify ( {
"title" : "Couldn't Close JamTrack" ,
"text" : "Couldn't inform the server to close JamTrack. msg=" + jqXHR . responseText ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
context . jamClient . JamTrackStopPlay ( ) ;
return false ;
}
2015-01-21 04:14:48 +00:00
function closeMetronomeTrack ( ) {
rest . closeMetronome ( { id : sessionModel . id ( ) } )
. done ( function ( ) {
context . jamClient . SessionCloseMetronome ( ) ;
sessionModel . refreshCurrentSession ( true ) ;
} )
. fail ( function ( jqXHR ) {
app . notify ( {
"title" : "Couldn't Close MetronomeTrack" ,
"text" : "Couldn't inform the server to close MetronomeTrack. msg=" + jqXHR . responseText ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
return false ;
}
2015-01-16 02:28:34 +00:00
2014-01-05 03:47:23 +00:00
function closeRecording ( ) {
rest . stopPlayClaimedRecording ( { id : sessionModel . id ( ) , claimed _recording _id : sessionModel . getCurrentSession ( ) . claimed _recording . id } )
2015-02-16 04:01:06 +00:00
. done ( function ( response ) {
//sessionModel.refreshCurrentSession(true);
// update session info
context . JK . CurrentSessionModel . updateSession ( response ) ;
2014-01-05 03:47:23 +00:00
} )
. fail ( function ( jqXHR ) {
app . notify ( {
"title" : "Couldn't Stop Recording Playback" ,
"text" : "Couldn't inform the server to stop playback. msg=" + jqXHR . responseText ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
context . jamClient . CloseRecording ( ) ;
return false ;
}
function onPause ( ) {
logger . debug ( "calling jamClient.SessionStopPlay" ) ;
context . jamClient . SessionStopPlay ( ) ;
}
2014-01-06 20:35:35 +00:00
function onPlay ( e , data ) {
2014-01-05 03:47:23 +00:00
logger . debug ( "calling jamClient.SessionStartPlay" ) ;
2014-01-06 20:35:35 +00:00
context . jamClient . SessionStartPlay ( data . playbackMode ) ;
2014-01-05 03:47:23 +00:00
}
function onChangePlayPosition ( e , data ) {
logger . debug ( "calling jamClient.SessionTrackSeekMs(" + data . positionMs + ")" ) ;
context . jamClient . SessionTrackSeekMs ( data . positionMs ) ;
}
2013-11-03 20:55:55 +00:00
function startStopRecording ( ) {
if ( sessionModel . recordingModel . isRecording ( ) ) {
sessionModel . recordingModel . stopRecording ( ) ;
}
else {
sessionModel . recordingModel . startRecording ( ) ;
}
}
2014-01-14 01:00:42 +00:00
function inviteMusicians ( ) {
2015-01-09 02:35:39 +00:00
friendInput = inviteMusiciansUtil . inviteSessionUpdate ( '#update-session-invite-musicians' ,
2014-07-27 23:39:11 +00:00
sessionId ) ;
inviteMusiciansUtil . loadFriends ( ) ;
$ ( friendInput ) . show ( ) ;
2015-01-22 02:16:52 +00:00
}
2014-11-11 22:21:29 +00:00
2015-02-12 20:05:25 +00:00
function setFormFromMetronome ( ) {
$ ( "select.metro-tempo" ) . val ( metroTempo )
$ ( "select.metro-sound" ) . val ( metroSound )
2015-01-22 02:16:52 +00:00
}
function setMetronomeFromForm ( ) {
var tempo = $ ( "select.metro-tempo:visible option:selected" ) . val ( )
2015-01-29 22:12:26 +00:00
var sound = $ ( "select.metro-sound:visible option:selected" ) . val ( )
2015-02-12 20:05:25 +00:00
var t = parseInt ( tempo )
var s
2015-01-29 22:12:26 +00:00
if ( tempo == NaN || tempo == 0 || tempo == null ) {
t = 120
}
if ( sound == null || typeof ( sound ) == 'undefined' || sound == "" ) {
s = "click"
} else {
s = sound
}
console . log ( "Setting tempo and sound:" , t , s )
2015-02-12 20:05:25 +00:00
metroTempo = t
metroSound = s
2015-01-29 22:12:26 +00:00
context . jamClient . SessionSetMetronome ( t , s , 1 , 0 )
2015-01-22 02:16:52 +00:00
}
function onMetronomeChanged ( e , data ) {
setMetronomeFromForm ( )
}
2014-11-11 22:21:29 +00:00
2015-01-22 02:16:52 +00:00
function onMixerModeChanged ( e , data ) {
$mixModeDropdown . easyDropDown ( 'select' , data . mode , true ) ;
2014-11-11 22:21:29 +00:00
setTimeout ( renderSession , 1 ) ;
}
function onUserChangeMixMode ( e ) {
var mode = $mixModeDropdown . val ( ) == "master" ? MIX _MODES . MASTER : MIX _MODES . PERSONAL ;
context . jamClient . SetMixerMode ( mode )
modUtils . shouldShow ( NAMED _MESSAGES . MASTER _VS _PERSONAL _MIX ) . done ( function ( shouldShow ) {
if ( shouldShow ) {
var modeChangeHtml = $ ( $templateMixerModeChange . html ( ) ) ;
context . JK . Banner . show ( { title : 'Master vs. Personal Mix' , text : modeChangeHtml , no _show : NAMED _MESSAGES . MASTER _VS _PERSONAL _MIX } ) ;
}
} )
return true ;
2014-01-14 01:00:42 +00:00
}
2015-01-22 02:16:52 +00:00
function events ( ) {
2014-02-25 02:20:17 +00:00
$ ( '#session-leave' ) . on ( 'click' , sessionLeave ) ;
$ ( '#session-resync' ) . on ( 'click' , sessionResync ) ;
2012-10-06 16:36:05 +00:00
$ ( '#session-contents' ) . on ( "click" , '[action="delete"]' , deleteSession ) ;
2013-01-31 16:32:32 +00:00
$ ( '#tracks' ) . on ( 'click' , 'div[control="mute"]' , toggleMute ) ;
2014-01-05 03:47:23 +00:00
$ ( '#recording-start-stop' ) . on ( 'click' , startStopRecording ) ;
$ ( '#open-a-recording' ) . on ( 'click' , openRecording ) ;
2015-01-09 02:35:39 +00:00
$ ( '#open-a-jamtrack' ) . on ( 'click' , openJamTrack ) ;
2015-01-16 02:28:34 +00:00
$ ( '#open-a-backingtrack' ) . on ( 'click' , openBackingTrack ) ;
$ ( '#open-a-metronome' ) . on ( 'click' , openMetronome ) ;
2014-01-14 01:00:42 +00:00
$ ( '#session-invite-musicians' ) . on ( 'click' , inviteMusicians ) ;
2014-07-27 23:39:11 +00:00
$ ( '#session-invite-musicians2' ) . on ( 'click' , inviteMusicians ) ;
2013-10-26 01:34:40 +00:00
$ ( '#track-settings' ) . click ( function ( ) {
2014-03-03 22:13:23 +00:00
configureTrackDialog . refresh ( ) ;
2013-05-22 05:03:34 +00:00
configureTrackDialog . showVoiceChatPanel ( true ) ;
2013-10-26 01:34:40 +00:00
configureTrackDialog . showMusicAudioPanel ( true ) ;
2013-05-18 05:59:25 +00:00
} ) ;
2014-01-25 15:37:15 +00:00
2015-01-09 02:35:39 +00:00
$ ( '#close-playback-recording' ) . on ( 'click' , closeOpenMedia ) ;
2014-01-05 03:47:23 +00:00
$ ( playbackControls )
. on ( 'pause' , onPause )
. on ( 'play' , onPlay )
. on ( 'change-position' , onChangePlayPosition ) ;
2014-07-27 23:39:11 +00:00
$ ( friendInput ) . focus ( function ( ) { $ ( this ) . val ( '' ) ; } )
2014-11-11 22:21:29 +00:00
$ ( document ) . on ( EVENTS . MIXER _MODE _CHANGED , onMixerModeChanged )
$mixModeDropdown . change ( onUserChangeMixMode )
2015-01-22 02:16:52 +00:00
$ ( document ) . on ( "change" , ".metronome-select" , onMetronomeChanged )
2012-10-06 16:36:05 +00:00
}
2014-07-09 22:20:20 +00:00
this . initialize = function ( localRecordingsDialogInstance , recordingFinishedDialogInstance , friendSelectorDialog ) {
inviteMusiciansUtil = new JK . InviteMusiciansUtil ( JK . app ) ;
inviteMusiciansUtil . initialize ( friendSelectorDialog ) ;
2014-01-05 03:47:23 +00:00
localRecordingsDialog = localRecordingsDialogInstance ;
2014-01-06 20:35:35 +00:00
recordingFinishedDialog = recordingFinishedDialogInstance ;
2013-02-15 05:15:36 +00:00
context . jamClient . SetVURefreshRate ( 150 ) ;
2014-02-13 18:54:54 +00:00
context . jamClient . RegisterVolChangeCallBack ( "JK.HandleVolumeChangeCallback" ) ;
2014-01-05 03:47:23 +00:00
playbackControls = new context . JK . PlaybackControls ( $ ( '.session-recordings .recording-controls' ) ) ;
2015-02-12 20:05:25 +00:00
context . jamClient . setMetronomeOpenCallback ( "JK.HandleMetronomeCallback" )
2014-01-05 03:47:23 +00:00
2012-12-07 00:28:48 +00:00
var screenBindings = {
2012-10-29 15:10:02 +00:00
'beforeShow' : beforeShow ,
2012-10-29 00:37:59 +00:00
'afterShow' : afterShow ,
2014-02-23 04:41:42 +00:00
'beforeHide' : beforeHide ,
2014-04-09 17:25:52 +00:00
'beforeLeave' : beforeLeave ,
'beforeDisconnect' : beforeDisconnect ,
2012-10-14 15:48:56 +00:00
} ;
app . bindScreen ( 'session' , screenBindings ) ;
2014-05-22 16:26:56 +00:00
2014-10-23 04:10:49 +00:00
$recordingManagerViewer = $ ( '#recording-manager-viewer' ) ;
$screen = $ ( '#session-screen' ) ;
2014-11-09 15:13:22 +00:00
$mixModeDropdown = $screen . find ( 'select.monitor-mode' )
2014-11-11 22:21:29 +00:00
$templateMixerModeChange = $ ( '#template-mixer-mode-change' ) ;
events ( ) ;
2014-11-09 15:13:22 +00:00
// make sure no previous plays are still going on by accident
2014-05-22 16:26:56 +00:00
context . jamClient . SessionStopPlay ( ) ;
2014-08-31 20:23:42 +00:00
if ( context . jamClient . SessionRemoveAllPlayTracks ) {
// upgrade guard
context . jamClient . SessionRemoveAllPlayTracks ( ) ;
}
2012-10-06 16:36:05 +00:00
} ;
2013-10-12 22:35:12 +00:00
2012-10-22 02:55:05 +00:00
this . tracks = tracks ;
2013-06-10 02:12:43 +00:00
this . getCurrentSession = function ( ) {
return sessionModel . getCurrentSession ( ) ;
2013-06-09 17:02:53 +00:00
} ;
2014-03-05 23:18:53 +00:00
this . refreshCurrentSession = function ( force ) {
sessionModel . refreshCurrentSession ( force ) ;
2013-06-11 01:53:49 +00:00
} ;
2014-02-23 04:41:42 +00:00
this . setPromptLeave = function ( _promptLeave ) {
promptLeave = _promptLeave ;
}
2013-08-07 20:04:22 +00:00
context . JK . HandleVolumeChangeCallback = handleVolumeChangeCallback ;
2015-02-12 20:05:25 +00:00
context . JK . HandleMetronomeCallback = handleMetronomeCallback ;
2013-01-30 16:50:43 +00:00
context . JK . HandleBridgeCallback = handleBridgeCallback ;
2015-02-16 04:14:30 +00:00
context . JK . HandleBackingTrackSelectedCallback = handleBackingTrackSelectedCallback ;
2012-10-06 16:36:05 +00:00
} ;
} ) ( window , jQuery ) ;