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 ;
2015-04-16 18:05:40 +00:00
var webcamViewer = new context . JK . WebcamViewer ( )
2015-04-15 23:37:07 +00:00
2015-02-19 15:31:30 +00:00
var defaultParticipant = {
tracks : [ {
instrument _id : "unknown"
} ] ,
user : {
first _name : 'Unknown' ,
last _name : 'User' ,
photo _url : null
}
} ;
// 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
} ;
// 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 ,
"PeerAudioInputMusicGroup" : 9 ,
"PeerMediaTrackGroup" : 10 ,
"JamTrackGroup" : 11 ,
"MetronomeGroup" : 12
} ;
2015-03-04 01:06:55 +00:00
var METRO _SOUND _LOOKUP = {
0 : "BuiltIn" ,
1 : "SineWave" ,
2 : "Beep" ,
3 : "Click" ,
4 : "Kick" ,
5 : "Snare" ,
6 : "MetroFile"
}
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 ;
2015-02-27 17:51:45 +00:00
var jamTrack = null ;
2015-05-01 17:09:18 +00:00
var musicianAccessOnJoin ; // was this a private or public session when the user tried to joined?
2015-03-12 13:51:52 +00:00
2015-03-04 01:06:55 +00:00
var metronomeMixer = 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 ;
2015-03-04 01:06:55 +00:00
var metroCricket = false ;
2015-02-12 20:05:25 +00:00
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 ;
2015-04-08 19:34:05 +00:00
var $myTracksNoTracks = null ;
2015-02-27 17:51:45 +00:00
var $otherAudioContainer = null ;
var $myTracksContainer = null ;
var $liveTracksContainer = null ;
var downloadJamTrack = null ;
2015-02-18 21:41:51 +00:00
var $closePlaybackRecording = null ;
2015-02-20 15:50:03 +00:00
var $openBackingTrack = null ;
2015-03-04 01:06:55 +00:00
var $metronomePlaybackSelect = null ;
var $metronomePlaybackHelp = null ;
2015-03-13 02:53:23 +00:00
var $templatePendingMetronome = null ;
2015-03-27 20:36:09 +00:00
var $myTracks = null ;
var $liveTracks = null ;
var $audioTracks = null ;
var $fluidTracks = null ;
2015-04-08 19:34:05 +00:00
var $voiceChat = null ;
var $openFtue = null ;
var $tracksHolder = null ;
2015-03-27 20:36:09 +00:00
2015-02-19 15:31:30 +00:00
var mediaTrackGroups = [ ChannelGroupIds . MediaTrackGroup , ChannelGroupIds . JamTrackGroup , ChannelGroupIds . MetronomeGroup ] ;
2015-03-14 20:00:11 +00:00
var muteBothMasterAndPersonalGroups = [ ChannelGroupIds . AudioInputMusicGroup , ChannelGroupIds . MediaTrackGroup , ChannelGroupIds . JamTrackGroup , ChannelGroupIds . MetronomeGroup ] ;
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.
2012-10-29 15:10:02 +00:00
function beforeShow ( data ) {
2015-04-22 15:18:33 +00:00
sessionId = data . id ;
if ( ! sessionId ) {
window . location = '/client#/home' ;
}
promptLeave = true ;
$myTracksContainer . empty ( ) ;
displayDoneRecording ( ) ; // assumption is that you can't join a recording session, so this should be safe
2014-02-07 05:57:31 +00:00
2015-04-22 15:18:33 +00:00
var shareDialog = new JK . ShareDialog ( context . JK . app , sessionId , "session" ) ;
shareDialog . initialize ( context . JK . FacebookHelperInstance ) ;
2015-04-22 18:28:44 +00:00
if ( gon . global . video _available && gon . global . video _available != "none" ) {
2015-04-16 18:05:40 +00:00
webcamViewer . beforeShow ( )
2015-04-22 15:18:33 +00:00
}
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 ( ) ;
2015-04-17 19:01:07 +00:00
context . JK . HelpBubbleHelper . jamtrackGuideSession ( $screen . find ( 'li.open-a-jamtrack' ) , $screen )
2014-03-01 23:01:45 +00:00
}
2012-10-06 16:36:05 +00:00
function afterShow ( data ) {
2013-05-31 02:07:33 +00:00
2015-04-15 20:14:41 +00:00
$fluidTracks . addClass ( 'showing' ) ;
2015-02-20 15:50:03 +00:00
$openBackingTrack . removeClass ( 'disabled' ) ;
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 ;
2015-04-08 19:34:05 +00:00
rest . getSessionHistory ( data . id )
. done ( function ( musicSession ) {
2014-08-29 02:11:25 +00:00
2015-05-01 17:09:18 +00:00
musicianAccessOnJoin = musicSession . musician _access ; ;
2014-08-29 02:11:25 +00:00
2015-04-08 19:34:05 +00:00
var shouldVerifyNetwork = musicSession . musician _access ;
gearUtils . guardAgainstInvalidConfiguration ( app , shouldVerifyNetwork )
. fail ( function ( ) {
promptLeave = false ;
window . location = '/client#/home'
} )
. done ( function ( ) {
var result = sessionUtils . SessionPageEnter ( ) ;
2014-08-29 02:11:25 +00:00
2015-04-08 19:34:05 +00:00
gearUtils . guardAgainstActiveProfileMissing ( app , result )
. fail ( function ( data ) {
promptLeave = false ;
if ( data && data . reason == 'handled' ) {
if ( data . nav == 'BACK' ) {
window . history . go ( - 1 ) ;
}
else {
window . location = data . nav ;
}
}
else {
window . location = '/client#/home' ;
}
} )
. done ( function ( ) {
sessionModel . waitForSessionPageEnterDone ( )
. done ( function ( userTracks ) {
context . JK . CurrentSessionModel . setUserTracks ( userTracks ) ;
initializeSession ( ) ;
} )
. fail ( function ( data ) {
if ( data == "timeout" ) {
context . JK . alertSupportedNeeded ( 'The audio system has not reported your configured tracks in a timely fashion.' )
}
else if ( data == 'session_over' ) {
// do nothing; session ended before we got the user track info. just bail
}
else {
context . JK . alertSupportedNeeded ( 'Unable to determine configured tracks due to reason: ' + data )
}
promptLeave = false ;
window . location = '/client#/home'
} ) ;
} )
} )
} )
. fail ( function ( ) {
2014-06-25 21:54:31 +00:00
} )
2015-04-08 19:34:05 +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 ( ) {
2013-08-31 13:54:11 +00:00
2015-05-01 17:09:18 +00:00
// now check if the user can play in a session with others
var deferred = new $ . Deferred ( ) ;
if ( musicianAccessOnJoin ) {
deferred = context . JK . guardAgainstSinglePlayerProfile ( app , function ( ) {
promptLeave = false ;
} ) ;
}
else {
deferred . resolve ( ) ;
}
deferred . fail ( function ( result ) {
if ( ! result . controlled _location ) {
window . location = "/client#/home"
}
} )
2015-05-12 20:45:23 +00:00
. done ( function ( ) {
logger . debug ( "user has passed all session guards" )
2015-05-01 17:09:18 +00:00
promptLeave = true ;
var sessionModel = context . JK . CurrentSessionModel ;
$ ( sessionModel . recordingModel )
2013-11-03 20:55:55 +00:00
. on ( 'startingRecording' , function ( e , data ) {
2015-05-01 17:09:18 +00:00
displayStartingRecording ( ) ;
lockControlsforJamTrackRecording ( ) ;
2013-11-16 04:35:40 +00:00
} )
. on ( 'startedRecording' , function ( e , data ) {
2015-05-01 17:09:18 +00:00
if ( data . reason ) {
var reason = data . reason ;
var detail = data . detail ;
2013-11-16 04:35:40 +00:00
2015-05-01 17:09:18 +00:00
var title = "Could Not Start Recording" ;
2013-11-16 04:35:40 +00:00
2015-05-01 17:09:18 +00:00
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' ) {
app . notifyAlert ( title , 'Already recording. If this appears incorrect, try restarting JamKazam.' ) ;
}
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 if ( data . reason == 'rest' ) {
var jqXHR = detail [ 0 ] ;
app . notifyServerError ( jqXHR ) ;
2013-11-03 20:55:55 +00:00
}
2015-05-01 17:09:18 +00:00
else {
notifyWithUserInfo ( title , 'Error Reason: ' + reason ) ;
2013-11-03 20:55:55 +00:00
}
2015-05-01 17:09:18 +00:00
displayDoneRecording ( ) ;
}
else
{
displayStartedRecording ( ) ;
displayWhoCreated ( data . clientId ) ;
lockControlsforJamTrackRecording ( ) ;
}
2013-11-03 20:55:55 +00:00
} )
. on ( 'stoppingRecording' , function ( e , data ) {
2015-05-01 17:09:18 +00:00
displayStoppingRecording ( data ) ;
unlockControlsforJamTrackRecording ( ) ;
2013-11-03 20:55:55 +00:00
} )
. on ( 'stoppedRecording' , function ( e , data ) {
2015-02-27 17:51:45 +00:00
2015-05-01 17:09:18 +00:00
unlockControlsforJamTrackRecording ( ) ;
if ( sessionModel . selfOpenedJamTracks ( ) ) {
2015-02-27 17:51:45 +00:00
2015-05-01 17:09:18 +00:00
var timeline = context . jamClient . GetJamTrackTimeline ( ) ;
2013-11-16 04:35:40 +00:00
2015-05-01 17:09:18 +00:00
rest . addRecordingTimeline ( data . recordingId , timeline )
. fail ( function ( ) {
app . notify (
{ title : "Unable to Add JamTrack Volume Data" ,
text : "The volume of the JamTrack will not be correct in the recorded mix." } ,
null ,
true ) ;
} )
}
2013-11-03 20:55:55 +00:00
2015-05-01 17:09:18 +00:00
if ( data . reason ) {
logger . warn ( "Recording Discarded: " , data ) ;
2013-11-16 04:35:40 +00:00
var reason = data . reason ;
var detail = data . detail ;
2013-11-03 20:55:55 +00:00
2015-05-01 17:09:18 +00:00
var title = "Recording Discarded" ;
2013-11-03 20:55:55 +00:00
2013-11-16 04:35:40 +00:00
if ( data . reason == 'client-no-response' ) {
2015-05-01 17:09:18 +00:00
notifyWithUserInfo ( title , 'did not respond to the stop signal.' , detail ) ;
2013-11-16 04:35:40 +00:00
}
else if ( data . reason == 'missing-client' ) {
2015-05-01 17:09:18 +00:00
notifyWithUserInfo ( title , 'could not be signalled to stop recording.' , detail ) ;
2013-11-16 04:35:40 +00:00
}
2015-05-01 17:09:18 +00:00
else if ( data . reason == 'empty-recording-id' ) {
app . notifyAlert ( title , "No recording ID specified." ) ;
2013-11-16 04:35:40 +00:00
}
2015-05-01 17:09:18 +00:00
else if ( data . reason == 'wrong-recording-id' ) {
app . notifyAlert ( title , "Wrong recording ID specified." ) ;
2013-11-16 04:35:40 +00:00
}
2015-05-01 17:09:18 +00:00
else if ( data . reason == 'not-recording' ) {
app . notifyAlert ( title , "Not currently recording." ) ;
2013-11-16 04:35:40 +00:00
}
2015-05-01 17:09:18 +00:00
else if ( data . reason == 'already-stopping' ) {
app . notifyAlert ( title , "Already stopping the current recording." ) ;
2013-11-16 04:35:40 +00:00
}
2015-05-01 17:09:18 +00:00
else if ( data . reason == 'start-before-stop' ) {
notifyWithUserInfo ( title , 'asked that we start a new recording; cancelling the current one.' , detail ) ;
2013-11-16 04:35:40 +00:00
}
else {
2015-05-01 17:09:18 +00:00
app . notifyAlert ( title , "Error reason: " + reason ) ;
2013-11-16 04:35:40 +00:00
}
displayDoneRecording ( ) ;
2015-05-01 17:09:18 +00:00
}
else {
displayDoneRecording ( ) ;
promptUserToSave ( data . recordingId , timeline ) ;
}
2013-11-16 04:35:40 +00:00
} )
2015-05-01 17:09:18 +00:00
. on ( 'abortedRecording' , function ( e , data ) {
var reason = data . reason ;
var detail = data . detail ;
var title = "Recording Cancelled" ;
2013-11-03 20:55:55 +00:00
2015-05-01 17:09:18 +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 ( ) ;
} )
sessionModel . subscribe ( 'sessionScreen' , sessionChanged ) ;
sessionModel . joinSession ( sessionId )
2013-08-31 13:54:11 +00:00
. fail ( function ( xhr , textStatus , errorMessage ) {
2015-05-01 17:09:18 +00:00
if ( xhr . status == 404 ) {
// we tried to join the session, but it's already gone. kick user back to join session screen
promptLeave = false ;
context . window . location = "/client#/findSession" ;
app . notify (
{ title : "Unable to Join Session" ,
text : "The session you attempted to join is over."
} ,
null ,
true ) ;
}
else if ( xhr . status == 422 ) {
var response = JSON . parse ( xhr . responseText ) ;
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>' ) ) ;
2013-10-03 07:16:27 +00:00
}
2015-05-01 17:09:18 +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 ) ;
2014-07-31 15:32:20 +00:00
}
2013-10-03 07:16:27 +00:00
else {
2015-05-01 17:09:18 +00:00
app . notifyServerError ( xhr , 'Unable to Join Session' ) ;
2013-08-31 13:54:11 +00:00
}
2015-05-01 17:09:18 +00:00
}
else {
app . notifyServerError ( xhr , 'Unable to Join Session' ) ;
}
2015-05-12 20:45:23 +00:00
} )
. done ( function ( ) {
// check if this is a auto-load jamtrack situation (came from account jamtrack screen)
var jamTrack = sessionUtils . grabAutoOpenJamTrack ( ) ;
if ( jamTrack ) {
// give the session to settle just a little (call a timeout of 1 second)
setTimeout ( function ( ) {
// tell the server we are about to open a jamtrack
rest . openJamTrack ( { id : context . JK . CurrentSessionModel . id ( ) , jam _track _id : jamTrack . id } )
. done ( function ( response ) {
// now actually load the jamtrack
2015-05-15 17:34:35 +00:00
context . JK . CurrentSessionModel . updateSession ( response ) ;
2015-05-12 20:45:23 +00:00
loadJamTrack ( jamTrack ) ;
} )
. fail ( function ( jqXHR ) {
app . notifyServerError ( jqXHR , "Unable to Open JamTrack For Playback" ) ;
} )
} , 1000 )
}
} )
2015-05-01 17:09:18 +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 ) {
2015-04-24 22:28:59 +00:00
context . JK . HelpBubbleHelper . clearJamTrackGuide ( ) ;
2015-04-26 13:25:36 +00:00
2015-04-22 18:28:44 +00:00
if ( gon . global . video _available && gon . global . video _available != "none" ) {
2015-04-22 15:18:33 +00:00
webcamViewer . setVideoOff ( )
}
2015-04-15 20:14:41 +00:00
$fluidTracks . removeClass ( 'showing' ) ;
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
}
2015-03-04 01:06:55 +00:00
function getMetronomeMasterMixers ( ) {
return _mixersForGroupId ( ChannelGroupIds . MetronomeGroup , MIX _MODES . MASTER ) ;
}
2014-01-05 03:47:23 +00:00
2015-03-04 01:06:55 +00:00
function checkMetronomeTransition ( ) {
// trust backend over server
2014-01-05 03:47:23 +00:00
2015-03-26 22:45:23 +00:00
if ( sessionModel . jamTracks ( ) !== null || sessionModel . recordedJamTracks ( ) !== null ) {
2015-03-25 19:45:51 +00:00
// ignore all metronome events when jamtracks are open, because backend opens metronome mixer to play jamtrack tap-ins
logger . debug ( "ignore checkMetronomeTransition because JamTrack is open" )
return ;
}
2015-03-04 01:06:55 +00:00
var metronomeMasterMixers = getMetronomeMasterMixers ( ) ;
2015-02-16 04:14:30 +00:00
2015-03-04 01:06:55 +00:00
if ( metronomeMixer == null && metronomeMasterMixers . length > 0 ) {
2015-04-21 21:24:10 +00:00
logger . debug ( "monitoring metronome" )
2015-03-04 01:06:55 +00:00
playbackControls . startMonitor ( context . JK . PLAYBACK _MONITOR _MODE . METRONOME )
}
else if ( metronomeMixer != null && metronomeMasterMixers . length == 0 ) {
playbackControls . stopMonitor ( ) ;
}
metronomeMixer = metronomeMasterMixers . length > 0 ? metronomeMasterMixers : null ;
}
2014-01-05 03:47:23 +00:00
2015-03-04 01:06:55 +00:00
function checkJamTrackTransition ( currentSession ) {
2015-03-13 02:53:23 +00:00
// handle jam tracks
2015-04-17 20:01:56 +00:00
// if we have a recording open, then don't go into JamTrack monitor mode even if a JamTrack is open
if ( jamTrack == null && ( currentSession && currentSession . jam _track != null && currentSession . claimed _recording == null ) ) {
2015-04-21 21:24:10 +00:00
logger . debug ( "monitoring jamtrack" )
2015-03-04 01:06:55 +00:00
playbackControls . startMonitor ( context . JK . PLAYBACK _MONITOR _MODE . JAMTRACK ) ;
}
2015-04-17 20:01:56 +00:00
else if ( jamTrack && ( currentSession == null || ( currentSession . jam _track == null && currentSession . claimed _recording == null ) ) ) {
2015-04-21 21:24:10 +00:00
logger . debug ( "stop monitoring jamtrack" )
2015-03-04 01:06:55 +00:00
playbackControls . stopMonitor ( ) ;
}
jamTrack = currentSession == null ? null : currentSession . jam _track ;
}
2015-02-16 04:14:30 +00:00
2015-03-04 01:06:55 +00:00
function checkBackingTrackTransition ( currentSession ) {
2015-03-13 02:53:23 +00:00
// handle backing tracks
2015-03-04 01:06:55 +00:00
if ( backing _track _path == null && ( currentSession && currentSession . backing _track _path != null ) ) {
2015-04-21 21:24:10 +00:00
logger . debug ( "monitoring backing track" )
2015-03-04 01:06:55 +00:00
playbackControls . startMonitor ( ) ;
}
else if ( backing _track _path && ( currentSession == null || currentSession . backing _track _path == null ) ) {
2015-04-21 21:24:10 +00:00
logger . debug ( "stop monitoring backing track" )
2015-03-04 01:06:55 +00:00
playbackControls . stopMonitor ( ) ;
}
backing _track _path = currentSession == null ? null : currentSession . backing _track _path ;
}
2015-02-27 17:51:45 +00:00
2015-03-12 13:51:52 +00:00
2015-03-04 01:06:55 +00:00
function checkRecordingTransition ( currentSession ) {
2015-03-13 02:53:23 +00:00
// handle claimed recordings
2015-03-04 01:06:55 +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
2015-04-21 21:24:10 +00:00
logger . debug ( "monitoring recording" )
2015-03-04 01:06:55 +00:00
playbackControls . startMonitor ( ) ;
}
else if ( claimedRecording && ( currentSession == null || currentSession . claimed _recording == null ) ) {
2015-04-21 21:24:10 +00:00
logger . debug ( "stop monitoring recording" )
2015-03-04 01:06:55 +00:00
playbackControls . stopMonitor ( ) ;
2014-01-05 03:47:23 +00:00
}
2015-03-04 01:06:55 +00:00
claimedRecording = currentSession == null ? null : currentSession . claimed _recording ;
}
function handleTransitionsInRecordingPlayback ( ) {
// let's see if we detect a transition to start playback or stop playback
var currentSession = sessionModel . getCurrentSession ( ) ;
checkRecordingTransition ( currentSession ) ;
checkBackingTrackTransition ( currentSession ) ;
checkJamTrackTransition ( currentSession ) ;
checkMetronomeTransition ( ) ;
}
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 .
* /
2015-03-04 01:06:55 +00:00
function getMixer ( mixerId , mode ) {
if ( mode === undefined ) {
mode = sessionModel . getMixMode ( ) ;
}
return allMixers [ ( mode ? 'M' : 'P' ) + mixerId ] ;
2014-11-21 23:16:00 +00:00
}
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
}
2015-02-27 17:51:45 +00:00
function resetOtherAudioContent ( ) {
2015-03-13 02:53:23 +00:00
if ( $ ( '.session-recordings .track' ) . length === 0 && $ ( '.session-recordings .download-jamtrack' ) . length === 0 && $ ( '.session-recordings .pending-metronome' ) . length === 0 ) {
2015-02-27 17:51:45 +00:00
$ ( '.session-recordings .when-empty' ) . show ( ) ;
$ ( '.session-recording-name-wrapper' ) . hide ( ) ;
$ ( '.session-recordings .recording-controls' ) . hide ( ) ;
2015-03-13 02:53:23 +00:00
$closePlaybackRecording . show ( ) ;
2015-02-27 17:51:45 +00:00
$ ( '.session-recordings .session-recording-name' ) . text ( '(No audio loaded)' )
2015-03-27 20:36:09 +00:00
$ ( '.session-recordings' ) . attr ( 'media-state' , 'closed' )
$ ( '.session-livetracks' ) . attr ( 'media-state' , 'closed' )
2015-02-27 17:51:45 +00:00
}
}
2015-02-18 21:41:51 +00:00
function didSelfOpenMedia ( ) {
var localMediaMixers = _mixersForGroupIds ( [ ChannelGroupIds . MediaTrackGroup , ChannelGroupIds . JamTrackGroup , ChannelGroupIds . MetronomeGroup ] , MIX _MODES . MASTER ) ;
// if we find any local media mixers, then we are the opener of media
return localMediaMixers . length > 0 ;
}
function checkShowCloseControl ( ) {
didSelfOpenMedia ( ) ? $closePlaybackRecording . show ( ) : $closePlaybackRecording . hide ( ) ;
}
2012-11-03 20:25:23 +00:00
function renderSession ( ) {
2015-02-27 17:51:45 +00:00
$myTracksContainer . empty ( ) ;
2013-06-24 03:08:38 +00:00
$ ( '.session-track' ) . remove ( ) ; // Remove previous tracks
2013-09-06 02:27:43 +00:00
$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 ( ) ;
2015-02-18 21:41:51 +00:00
2013-06-24 03:08:38 +00:00
if ( $ ( '.session-livetracks .track' ) . length === 0 ) {
$ ( '.session-livetracks .when-empty' ) . show ( ) ;
}
2015-03-13 02:53:23 +00:00
checkPendingMetronome ( ) ;
2015-02-27 17:51:45 +00:00
resetOtherAudioContent ( ) ;
2015-03-27 20:36:09 +00:00
resizeFluid ( ) ;
2015-02-27 17:51:45 +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-18 21:41:51 +00:00
// should we show the close button? Only if the user opened the media
checkShowCloseControl ( ) ;
2015-02-01 23:14:22 +00:00
} else {
$ ( '.session-recordings .when-empty' ) . hide ( ) ;
$ ( '.session-recording-name-wrapper' ) . show ( ) ;
$ ( '.session-recordings .recording-controls' ) . show ( ) ;
2015-02-18 21:41:51 +00:00
checkShowCloseControl ( ) ;
2014-01-05 03:47:23 +00:00
}
2015-02-27 17:51:45 +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 ( ) ;
2015-04-16 18:05: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 ) ;
2014-11-11 22:21:29 +00:00
2015-04-17 20:01:56 +00:00
//logger.debug("masterMixers", masterMixers)
2014-11-21 23:16:00 +00:00
//logger.debug("personalMixers", personalMixers)
mixersByResourceId = { }
mixersByTrackId = { }
allMixers = { }
var i ;
for ( i = 0 ; i < masterMixers . length ; i ++ ) {
var masterMixer = masterMixers [ i ] ;
2015-03-04 01:06:55 +00:00
allMixers [ 'M' + masterMixer . id ] = masterMixer ; // populate allMixers by mixer.id
2014-11-21 23:16:00 +00:00
// 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 ] ;
2015-03-04 01:06:55 +00:00
allMixers [ 'P' + personalMixer . id ] = personalMixer
2014-11-21 23:16:00 +00:00
// 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 ;
$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-09 21:15:12 +00:00
// local media mixers come in different groups (MediaTrack, JamTrack, Metronome), but peer mixers are always PeerMediaTrackGroup
2015-02-19 15:31:30 +00:00
var localMediaMixers = _mixersForGroupIds ( mediaTrackGroups , 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-03-28 15:10:18 +00:00
var recordedJamTracks = sessionModel . recordedJamTracks ( ) ;
var jamTracks = sessionModel . jamTracks ( ) ;
2015-02-16 04:14:30 +00:00
2015-03-28 15:10:18 +00:00
//logger.debug("localMediaMixers", localMediaMixers)
//logger.debug("peerMediaMixers", peerLocalMediaMixers)
2015-03-26 22:45:23 +00:00
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
2015-02-24 23:16:12 +00:00
if ( mediaType == 'MetronomeTrack' || groupId == ChannelGroupIds . MetronomeGroup ) {
// Metronomes come across with a blank media type, so check group_id:
metronomeTrackMixers . push ( mixer ) ;
}
else if ( mediaType == null || mediaType == "" || mediaType == 'RecordingTrack' ) {
2015-02-16 04:14:30 +00:00
// 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
2015-03-28 15:10:18 +00:00
var isJamTrack = false ;
if ( jamTracks ) {
// check if the ID matches that of an open jam track
context . _ . each ( jamTracks , function ( jamTrack ) {
if ( mixer . id == jamTrack . id ) {
isJamTrack = true ;
2015-02-16 04:14:30 +00:00
return false ; // break
}
} )
}
2015-03-28 15:10:18 +00:00
if ( ! isJamTrack && recordedJamTracks ) {
// then check if the ID matches that of a open, recorded jam track
context . _ . each ( recordedJamTracks , function ( recordedJamTrack ) {
if ( mixer . id == recordedJamTrack . id ) {
isJamTrack = true ;
2015-02-16 04:14:30 +00:00
return false ; // break
}
} )
}
2015-03-28 15:10:18 +00:00
if ( isJamTrack ) {
jamTrackMixers . push ( mixer )
2015-02-16 04:14:30 +00:00
}
else {
2015-03-28 15:10:18 +00:00
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 {
// couldn't resolve this as a JamTrack or Backing track, must be a normal recorded file
recordingTrackMixers . push ( mixer ) ;
}
2015-02-16 04:14:30 +00:00
}
} 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-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 ) ;
}
2015-03-26 22:45:23 +00:00
if ( metronomeTrackMixers . length > 0 && sessionModel . jamTracks ( ) === null && sessionModel . recordedJamTracks ( ) == null ) {
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-03-04 01:06:55 +00:00
checkMetronomeTransition ( ) ;
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 ) {
2015-02-18 16:16:47 +00:00
logger . error ( "multiple, managed backing track mixers encountered" , backingTrackMixers )
2015-02-16 04:01:06 +00:00
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 ) {
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-23 21:00:57 +00:00
if ( isOpener ) {
var oppositeMixer = getMixerByResourceId ( mixer . rid , MIX _MODES . PERSONAL ) ;
2015-03-04 01:06:55 +00:00
var mixerId = mixer . id + "," + oppositeMixer . id
2015-02-23 21:00:57 +00:00
}
2015-02-24 04:29:28 +00:00
else {
var mixerId = mixer . id ;
}
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-27 17:51:45 +00:00
type : 'backing_track' ,
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-14 21:57:12 +00:00
showLoop : isOpener && ! sessionModel . isPlayingRecording ( ) ,
2015-02-23 16:45:10 +00:00
loopState : mixer . loop ,
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-02-19 15:31:30 +00:00
2015-01-21 04:14:48 +00:00
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
2015-02-24 04:29:28 +00:00
trackData . mixerId = mixerId ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
2015-01-21 04:14:48 +00:00
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-19 15:31:30 +00:00
trackData . mediaTrackOpener = isOpener ;
trackData . mediaControlsDisabled = ! isOpener ;
trackData . showHelpAboutMediaMixers = sessionModel . isPersonalMixMode ( ) && isOpener ;
2015-01-21 04:14:48 +00:00
2015-02-23 21:00:57 +00:00
_addRecordingTrack ( trackData , mixer , oppositeMixer ) ;
2015-02-16 04:01:06 +00:00
} ) ;
2015-01-06 22:51:19 +00:00
}
2015-04-29 19:38:03 +00:00
function renderJamTracks ( jamTrackMixersOrig ) {
2015-05-12 20:45:23 +00:00
logger . debug ( "rendering jam tracks" , jamTrackMixersOrig ) ;
2015-03-26 22:45:23 +00:00
2015-04-29 19:38:03 +00:00
var jamTrackMixers = jamTrackMixersOrig . slice ( ) ;
2015-03-26 22:45:23 +00:00
var jamTracks = [ ]
var jamTrackName = 'JamTrack' ;
if ( sessionModel . isPlayingRecording ( ) ) {
// only return managed mixers for recorded backing tracks
jamTracks = sessionModel . recordedJamTracks ( ) ;
jamTrackName = sessionModel . recordedJamTrackName ( ) ;
}
else {
// only return un-managed (ad-hoc) mixers for normal backing tracks
jamTracks = sessionModel . jamTracks ( ) ;
jamTrackName = sessionModel . jamTrackName ( ) ;
}
2015-01-09 21:15:12 +00:00
2015-03-09 14:44:12 +00:00
2015-01-09 21:15:12 +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 (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 ) {
2015-03-26 22:45:23 +00:00
$ ( '.session-recording-name' ) . text ( jamTrackName ) ;
2015-01-09 21:15:12 +00:00
var noCorrespondingTracks = false ;
2015-04-28 14:35:39 +00:00
$ . each ( jamTracks , function ( index , jamTrack ) {
var mixer = null ;
2015-01-09 21:15:12 +00:00
var preMasteredClass = "" ;
// find the track or tracks that correspond to the mixer
var correspondingTracks = [ ]
2015-04-29 19:38:03 +00:00
$ . each ( jamTrackMixersOrig , function ( i , matchMixer ) {
2015-04-28 14:35:39 +00:00
if ( matchMixer . id == jamTrack . id ) {
2015-01-09 21:15:12 +00:00
correspondingTracks . push ( jamTrack ) ;
2015-04-28 14:35:39 +00:00
mixer = matchMixer ;
2015-01-09 21:15:12 +00:00
}
} ) ;
if ( correspondingTracks . length == 0 ) {
noCorrespondingTracks = true ;
2015-02-27 17:51:45 +00:00
logger . error ( "could not correlate jam tracks" , jamTrackMixers , jamTracks )
2015-01-09 21:15:12 +00:00
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 ;
} ) ;
2015-04-29 19:38:03 +00:00
// prune found mixers
jamTrackMixers . splice ( mixer ) ;
2015-01-09 21:15:12 +00:00
var oneOfTheTracks = correspondingTracks [ 0 ] ;
2015-03-21 03:04:03 +00:00
var instrumentIcon = context . JK . getInstrumentIcon45 ( oneOfTheTracks . instrument . id ) ;
2015-01-09 21:15:12 +00:00
var photoUrl = "/assets/content/icon_recording.png" ;
var name = oneOfTheTracks . part
if ( ! name ) {
2015-03-21 03:04:03 +00:00
name = '' ;
2015-01-09 21:15:12 +00:00
}
2015-02-23 21:00:57 +00:00
if ( isOpener ) {
var oppositeMixer = getMixerByResourceId ( mixer . rid , MIX _MODES . PERSONAL ) ;
2015-03-04 01:06:55 +00:00
var mixerId = mixer . id + "," + oppositeMixer . id
2015-02-23 21:00:57 +00:00
}
2015-02-24 04:29:28 +00:00
else {
var mixerId = mixer . id ;
}
2015-01-09 21:15:12 +00:00
// Default trackData to participant + no Mixer state.
var trackData = {
2015-02-27 17:51:45 +00:00
type : 'jam_track' ,
2015-01-09 21:15:12 +00:00
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 ;
2015-02-24 04:29:28 +00:00
trackData . mixerId = mixerId ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
2015-01-09 21:15:12 +00:00
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-19 15:31:30 +00:00
trackData . mediaTrackOpener = isOpener ;
trackData . mediaControlsDisabled = ! isOpener ;
trackData . showHelpAboutMediaMixers = sessionModel . isPersonalMixMode ( ) && isOpener ;
2015-01-09 21:15:12 +00:00
2015-02-23 21:00:57 +00:00
_addRecordingTrack ( trackData , mixer , oppositeMixer ) ;
2015-01-09 21:15:12 +00:00
} ) ;
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-03-04 01:06:55 +00:00
logger . debug ( "rendering metronome track" )
2015-01-21 04:14:48 +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 name = "Metronome"
// using the server's info in conjuction with the client's, draw the recording tracks
2015-03-04 01:06:55 +00:00
if ( metronomeTrackMixers . length > 0 ) {
var metronome = { }
2015-01-21 04:14:48 +00:00
$ ( '.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-03-04 01:06:55 +00:00
var oppositeMixer = getMixerByResourceId ( mixer . rid , MIX _MODES . PERSONAL ) ;
var mixerId = mixer . id + "," + oppositeMixer . id
2015-02-24 04:29:28 +00:00
2015-01-21 04:14:48 +00:00
// Default trackData to participant + no Mixer state.
var trackData = {
2015-02-27 17:51:45 +00:00
type : 'metronome' ,
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 ;
2015-02-24 04:29:28 +00:00
trackData . mixerId = mixerId ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
2015-01-21 04:14:48 +00:00
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-03-04 01:06:55 +00:00
trackData . mediaTrackOpener = true
trackData . mediaControlsDisabled = false
trackData . showHelpAboutMediaMixers = false
2015-02-16 04:14:30 +00:00
2015-02-23 21:00:57 +00:00
_addRecordingTrack ( trackData , mixer , oppositeMixer ) ;
2015-01-21 04:14:48 +00:00
} // if
2015-02-12 20:05:25 +00:00
setFormFromMetronome ( )
2015-03-04 01:06:55 +00:00
metroCricket = context . jamClient . getMetronomeCricketTestState ( ) ;
setMetronomePlaybackMode ( )
2015-03-13 02:53:23 +00:00
$closePlaybackRecording . show ( ) ;
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 ) ;
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 ;
}
2015-02-23 21:00:57 +00:00
if ( isOpener ) {
var oppositeMixer = getMixerByResourceId ( mixer . rid , MIX _MODES . PERSONAL ) ;
2015-03-04 01:06:55 +00:00
var mixerId = mixer . id + "," + oppositeMixer . id
2015-02-24 04:29:28 +00:00
}
else {
var mixerId = mixer . id ;
2015-02-23 21:00:57 +00:00
}
2015-01-06 22:51:19 +00:00
// Default trackData to participant + no Mixer state.
var trackData = {
2015-02-27 17:51:45 +00:00
type : 'recorded_track' ,
2015-01-06 22:51:19 +00:00
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 ;
2015-02-24 04:29:28 +00:00
trackData . mixerId = mixerId ; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
2015-01-06 22:51:19 +00:00
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-19 15:31:30 +00:00
trackData . mediaControlsDisabled = ! isOpener ;
trackData . mediaTrackOpener = isOpener ;
trackData . showHelpAboutMediaMixers = sessionModel . isPersonalMixMode ( ) && isOpener ;
2015-01-06 22:51:19 +00:00
2015-02-23 21:00:57 +00:00
_addRecordingTrack ( trackData , mixer , oppositeMixer ) ;
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
2015-04-08 19:34:05 +00:00
// special case; if it's me and I have no tracks, show info about this sort of use of the app
if ( myTrack && participant . tracks . length == 0 ) {
$tracksHolder . addClass ( 'no-local-tracks' )
2015-04-17 14:39:27 +00:00
$liveTracksContainer . addClass ( 'no-local-tracks' )
2015-04-08 19:34:05 +00:00
}
else {
$tracksHolder . removeClass ( 'no-local-tracks' )
2015-04-17 14:39:27 +00:00
$liveTracksContainer . removeClass ( 'no-local-tracks' )
2015-04-08 19:34:05 +00:00
}
2013-05-15 05:59:09 +00:00
// loop through all tracks for each participant
2015-04-08 19:34:05 +00:00
$ . each ( participant . tracks , function ( index , track ) {
var instrumentIcon = context . JK . getInstrumentIcon45 ( track . instrument _id ) ;
var photoUrl = context . JK . resolveAvatarUrl ( participant . user . photo _url ) ;
// Default trackData to participant + no Mixer state.
var trackData = {
trackId : track . id ,
connection _id : track . connection _id ,
client _track _id : track . client _track _id ,
client _resource _id : track . client _resource _id ,
clientId : participant . client _id ,
name : name ,
instrumentIcon : instrumentIcon ,
avatar : photoUrl ,
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
mixerId : "" ,
avatarClass : 'avatar-med' ,
preMasteredClass : "" ,
myTrack : myTrack
} ;
var mixerData = findMixerForTrack ( participant . client _id , track , myTrack )
var mixer = mixerData . mixer ;
var vuMixer = mixerData . vuMixer ;
var muteMixer = mixerData . muteMixer ;
var oppositeMixer = mixerData . oppositeMixer ;
if ( mixer && oppositeMixer ) {
myTrack = ( mixer . group _id === ChannelGroupIds . AudioInputMusicGroup ) ;
if ( ! myTrack ) {
// it only makes sense to track 'audio established' for tracks that don't belong to you
sessionModel . setAudioEstablished ( participant . client _id , true ) ;
}
2015-01-18 21:46:40 +00:00
2015-04-08 19:34:05 +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
2015-04-08 19:34:05 +00:00
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ;
trackData . vuMixerId = vuMixer . id ;
trackData . oppositeMixer = oppositeMixer ;
trackData . muteMixerId = muteMixer . id ;
trackData . noaudio = false ;
trackData . group _id = mixer . group _id ;
context . jamClient . SessionSetUserName ( participant . client _id , name ) ;
} else { // No mixer to match, yet
lookingForMixers . push ( { track : track , clientId : participant . client _id } )
trackData . noaudio = true ;
if ( ! ( lookingForMixersTimer ) ) {
logger . debug ( "waiting for mixer to show up for track: " + track . id )
lookingForMixersTimer = context . setInterval ( lookForMixers , 500 ) ;
2013-02-10 02:00:29 +00:00
}
2015-04-08 19:34:05 +00:00
}
2013-09-06 12:34:57 +00:00
2015-04-08 19:34:05 +00:00
var allowDelete = myTrack && index > 0 ;
_addTrack ( allowDelete , trackData , mixer , oppositeMixer ) ;
2013-05-22 05:03:34 +00:00
2015-04-08 19:34:05 +00:00
// Show settings icons only for my tracks
if ( myTrack ) {
myTracks . push ( trackData ) ;
}
2013-05-15 05:59:09 +00:00
} ) ;
2015-04-08 19:34:05 +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
}
2015-03-04 01:06:55 +00:00
function connectTrackToMixer ( trackSelector , track , mixerId , gainPercent , groupId , mixer , oppositeMixer ) {
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" ;
2015-03-04 01:06:55 +00:00
var $fader = $ ( faderSelector ) . attr ( 'mixer-id' , mixerId ) . data ( 'groupId' , groupId ) . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , oppositeMixer ) ;
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
}
2015-02-19 15:31:30 +00:00
$fader . data ( 'showHelpAboutMediaMixers' , track . showHelpAboutMediaMixers )
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 ) ;
2015-03-04 01:06:55 +00:00
$track . find ( '.track-vu-left' ) . attr ( 'mixer-id' , track . vuMixerId + '_vul' ) . data ( 'groupId' , groupId ) . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , oppositeMixer )
2015-01-22 02:16:52 +00:00
context . JK . VuHelpers . renderVU ( vuRightSelector , vuOpts ) ;
2015-03-04 01:06:55 +00:00
$track . find ( '.track-vu-right' ) . attr ( 'mixer-id' , track . vuMixerId + '_vur' ) . data ( 'groupId' , groupId ) . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , oppositeMixer )
2015-01-22 02:16:52 +00:00
}
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 + '"]' ;
2015-03-04 01:06:55 +00:00
connectTrackToMixer ( trackSelector , track , mixer . id , gainPercent , mixer . group _id , mixer , oppositeMixer ) ;
2014-11-21 23:16:00 +00:00
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" , "" ) ;
2015-03-05 15:47:33 +00:00
var mixer = getMixer ( pureMixerId , sessionModel . getMixMode ( ) ) ;
if ( ! mixer ) {
// try again, in the opposite mode (awful that this is necessary)
mixer = getMixer ( pureMixerId , ! sessionModel . getMixMode ( ) ) ;
}
2013-08-19 00:54:32 +00:00
if ( mixer ) {
if ( ! ( mixer . stereo ) ) { // mono track
if ( mixerId . substr ( - 4 ) === "_vul" ) {
// Do the left
2015-04-08 19:34:05 +00:00
selector = $tracksHolder . find ( '[mixer-id="' + pureMixerId + '_vul"]' ) ;
2013-08-19 00:54:32 +00:00
context . JK . VuHelpers . updateVU ( selector , value ) ;
// Do the right
2015-04-08 19:34:05 +00:00
selector = $tracksHolder . find ( '[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
2015-04-08 19:34:05 +00:00
selector = $tracksHolder . find ( '[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
2015-02-27 17:51:45 +00:00
var $destination = $myTracksContainer ;
2013-02-05 05:10:37 +00:00
if ( trackData . clientId !== app . clientId ) {
2015-02-27 17:51:45 +00:00
$destination = $liveTracksContainer
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 ) ) ;
2015-02-27 17:51:45 +00:00
newTrack . data ( 'track_data' , 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
2015-02-27 17:51:45 +00:00
var trackSelector = $destination . selector + ' .session-track[track-id="' + trackData . trackId + '"]' ;
2013-08-28 03:05:53 +00:00
var gainPercent = trackData . gainPercent || 0 ;
2015-03-04 01:06:55 +00:00
connectTrackToMixer ( trackSelector , trackData , trackData . mixerId , gainPercent , trackData . group _id , mixer , oppositeMixer ) ;
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
}
2015-02-27 17:51:45 +00:00
// something is being shown now in the other audio area
function otherAudioFilled ( ) {
$ ( '.session-recordings .when-empty' ) . hide ( ) ;
$ ( '.session-recording-name-wrapper' ) . show ( ) ;
2015-03-27 20:36:09 +00:00
$ ( '.session-recordings' ) . attr ( 'media-state' , 'open' ) ;
$ ( '.session-livetracks' ) . attr ( 'media-state' , 'open' ) ;
}
function resizeFluid ( ) {
var trackWidth = 78 ; // 70 width + 8 margin
var trackPadding = 30 ; // 15px left and right
var numLiveTracks = $liveTracks . find ( '.track' ) . length ;
var numAudioTracks = $audioTracks . find ( '.track' ) . length ;
var totalWidth = $fluidTracks . width ( ) ;
// calculate desired audio tracks width
var minimumLiveTrackWidth = numLiveTracks * trackWidth + trackPadding ;
var otherAudioWidth = numAudioTracks * trackWidth + trackPadding ;
var liveTrackWidth = totalWidth - otherAudioWidth ;
// live tracks get precedence over audio tracks, if there is a content over width usage
if ( liveTrackWidth < minimumLiveTrackWidth ) {
logger . debug ( "live track width trumping mode" )
liveTrackWidth = minimumLiveTrackWidth ;
otherAudioWidth = totalWidth - liveTrackWidth ;
}
var otherAudioWidthPct = Math . floor ( 100 * otherAudioWidth / totalWidth ) ;
var liveTrackWidthPct = Math . ceil ( 100 * liveTrackWidth / totalWidth ) ;
2015-04-17 14:39:27 +00:00
//logger.debug("resizeFluid: ", minimumLiveTrackWidth, otherAudioWidth, otherAudioWidthPct, liveTrackWidthPct, liveTrackWidthPct)
2015-03-27 20:36:09 +00:00
$audioTracks . css ( 'width' , otherAudioWidthPct + '%' ) ;
$liveTracks . css ( 'width' , liveTrackWidthPct + '%' ) ;
2015-02-27 17:51:45 +00:00
}
2014-01-05 03:47:23 +00:00
2015-02-23 21:00:57 +00:00
function _addRecordingTrack ( trackData , mixer , oppositeMixer ) {
2015-02-27 17:51:45 +00:00
otherAudioFilled ( ) ;
$ ( '.session-recordings .recording-controls' ) . show ( ) ;
2014-01-05 03:47:23 +00:00
var parentSelector = '#session-recordedtracks-container' ;
var $destination = $ ( parentSelector ) ;
2015-02-27 17:51:45 +00:00
2014-01-05 03:47:23 +00:00
var template = $ ( '#template-session-track' ) . html ( ) ;
var newTrack = $ ( context . JK . fillTemplate ( template , trackData ) ) ;
2015-02-27 17:51:45 +00:00
newTrack . data ( 'track_data' , trackData ) ;
$otherAudioContainer . append ( newTrack ) ;
2014-01-05 03:47:23 +00:00
if ( trackData . preMasteredClass ) {
context . JK . helpBubble ( $ ( '.track-instrument' , newTrack ) , 'pre-processed-track' , { } , { offsetParent : newTrack . closest ( '.content-body' ) } ) ;
}
// Render VU meters and gain fader
2015-02-27 17:51:45 +00:00
var trackSelector = $otherAudioContainer . selector + ' .session-track[track-id="' + trackData . trackId + '"]' ;
2014-01-05 03:47:23 +00:00
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-23 21:00:57 +00:00
$trackIconMute . data ( 'mixer' , mixer ) . data ( 'opposite-mixer' , oppositeMixer )
2015-02-19 15:31:30 +00:00
$trackIconMute . data ( 'showHelpAboutMediaMixers' , trackData . showHelpAboutMediaMixers )
2015-02-16 04:14:30 +00:00
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' )
2015-02-23 16:45:10 +00:00
var $trackIconLoopCheckbox = $trackIconLoop . find ( 'input' ) ;
$trackIconLoopCheckbox . prop ( 'checked' , trackData . loopState ) ;
2015-02-14 21:57:12 +00:00
context . JK . checkbox ( $trackIconLoopCheckbox )
$trackIconLoopCheckbox . on ( 'ifChanged' , function ( ) {
var loop = $trackIconLoopCheckbox . is ( ':checked' )
2015-02-18 09:43:33 +00:00
_toggleAudioLoop ( mixer . id , loop , getMixer ( mixer . id ) . mode )
2015-02-14 21:57:12 +00:00
} ) ;
$trackIconLoop . show ( )
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 ( ',' ) ;
2015-03-04 01:06:55 +00:00
// media tracks are the only controls that sometimes set two mixers right now
var hasMasterAndPersonalControls = mixerIds . length == 2 ;
2013-07-26 14:46:38 +00:00
$ . 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
2015-03-04 01:06:55 +00:00
var mode = undefined ;
if ( hasMasterAndPersonalControls ) {
mode = i == 0 ? MIX _MODES . MASTER : MIX _MODES . PERSONAL ;
}
var mixer = fillTrackVolumeObject ( v , mode , broadcast ) ;
2015-02-23 21:00:57 +00:00
2015-02-19 15:31:30 +00:00
setMixerVolume ( mixer , 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 ) {
2015-02-19 15:31:30 +00:00
logger . debug ( "MetronomeCallback: " , args )
2015-02-12 20:05:25 +00:00
metroTempo = args . bpm
2015-03-04 01:06:55 +00:00
metroCricket = args . cricket ;
metroSound = METRO _SOUND _LOOKUP [ args . sound ] ;
setMetronomePlaybackMode ( ) ;
setFormFromMetronome ( ) ;
2015-02-12 20:05:25 +00:00
// 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 ) {
2015-02-20 15:50:03 +00:00
$openBackingTrack . removeClass ( 'disabled' ) ;
if ( ! sessionModel . inSession ( ) ) {
return ;
}
2015-02-16 04:14:30 +00:00
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 ) ;
2015-02-24 23:16:12 +00:00
if ( openResult ) {
sessionModel . setBackingTrack ( result . file ) ;
}
else {
app . notify ( {
"title" : "Couldn't Open Backing Track" ,
"text" : "Is the file a valid audio file?" ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
closeBackingTrack ( ) ;
}
2015-02-16 04:14:30 +00:00
} )
. fail ( function ( jqXHR ) {
2015-02-24 23:16:12 +00:00
app . notifyServerError ( jqXHR , "Unable to Open Backing Track For Playback" ) ;
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 ) {
2015-03-04 01:06:55 +00:00
fillTrackVolumeObject ( mixerId , mode ) ;
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
}
2015-02-18 09:43:33 +00:00
function _toggleAudioLoop ( mixerId , loop , mode ) {
2015-03-04 01:06:55 +00:00
fillTrackVolumeObject ( mixerId , mode ) ;
2015-02-18 09:43:33 +00:00
context . trackVolumeObject . loop = loop ;
if ( mode === undefined ) {
mode = sessionModel . getMixMode ( ) ;
}
context . jamClient . SessionSetControlState ( mixerId , mode ) ;
}
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
}
2015-02-27 17:51:45 +00:00
if ( sessionModel . areControlsLockedForJamTrackRecording ( ) && $control . closest ( '.session-track' ) . data ( 'track_data' ) . type == 'jam_track' ) {
context . JK . prodBubble ( $control , 'jamtrack-controls-disabled' , { } , { positions : [ 'bottom' ] , offsetParent : $control . closest ( '.screen' ) } )
return false ;
}
2015-02-19 15:31:30 +00:00
if ( $control . data ( 'showHelpAboutMediaMixers' ) ) {
if ( ! sessionModel . hasShownAudioMediaMixerHelp ( ) ) {
context . JK . prodBubble ( $control , 'volume-media-mixers' , { } , { positions : [ 'bottom' ] , offsetParent : $control . closest ( '.screen' ) } )
sessionModel . markShownAudioMediaMixerHelp ( )
}
}
2015-02-27 17:51:45 +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' )
2015-03-04 01:06:55 +00:00
if ( mixer && oppositeMixer && ( muteBothMasterAndPersonalGroups . indexOf ( mixer . group _id ) > - 1 ) ) {
2014-12-17 15:08:45 +00:00
// this is the user's local track; mute both personal and master mode
2015-02-23 21:00:57 +00:00
logger . debug ( "muting both master and personal mode mixers" )
2015-03-04 01:06:55 +00:00
_toggleAudioMute ( mixer . id , muting , mixer . mode )
_toggleAudioMute ( oppositeMixer . id , muting , oppositeMixer . mode )
2014-12-17 15:08:45 +00:00
}
else {
2015-02-23 21:00:57 +00:00
logger . debug ( "muting mixer" )
2015-03-04 01:06:55 +00:00
_toggleAudioMute ( mixer . id , muting , mixer . mode )
2014-12-17 15:08:45 +00:00
}
2014-11-21 23:16:00 +00:00
// look for all controls matching this mixer id (important when it's personal mode + UserMusicInputGroup)
2015-02-19 15:31:30 +00:00
var $controls = $screen . find ( '.track-icon-mute[mixer-id="' + mixerId + '"]' ) ;
2014-11-21 23:16:00 +00:00
_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
}
2015-03-04 01:06:55 +00:00
function fillTrackVolumeObject ( mixerId , mode , 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 ;
}
2015-03-04 01:06:55 +00:00
var mixer = getMixer ( mixerId , mode ) ;
2014-11-21 23:16:00 +00:00
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 ;
2015-02-25 22:15:41 +00:00
// today we treat all tracks as mono, but this is required to make a stereo track happy
//context.trackVolumeObject.volR = mixer.volume_right;
context . trackVolumeObject . volR = mixer . volume _left ;
2015-02-18 09:43:33 +00:00
context . trackVolumeObject . loop = mixer . loop ;
2014-11-21 23:16:00 +00:00
// trackVolumeObject doesn't have a place for range min/max
currentMixerRangeMin = mixer . range _low ;
currentMixerRangeMax = mixer . range _high ;
2015-02-19 15:31:30 +00:00
return mixer ;
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.
2015-02-19 15:31:30 +00:00
function setMixerVolume ( mixer , 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:
2015-02-19 15:31:30 +00:00
if ( mixer . id === '__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 {
2015-02-23 21:00:57 +00:00
//var isMediaMixer = mediaTrackGroups.indexOf(mixer.group_id) > -1;
2015-02-19 15:31:30 +00:00
// if this is a media file (Metronome, JamTrack, BackingTrack, RecordedTrack), then we only modify master
2015-02-23 21:00:57 +00:00
//var mixMode = isMediaMixer ? MIX_MODES.MASTER : sessionModel.getMixMode();
context . jamClient . SessionSetControlState ( mixer . id , mixer . mode ) ;
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 ;
}
2015-04-16 18:05:40 +00:00
function sessionWebCam ( e ) {
e . preventDefault ( ) ;
2015-04-16 19:20:34 +00:00
if ( webcamViewer . isVideoShared ( ) ) {
$ ( '#session-webcam' ) . removeClass ( "selected" )
} else {
$ ( '#session-webcam' ) . addClass ( "selected" )
}
webcamViewer . toggleWebcam ( )
2015-04-16 18:05:40 +00:00
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 ( ) {
2015-04-28 14:44:56 +00:00
// the commented out code reflects dropping the counter as your recording to save space
2013-11-03 20:55:55 +00:00
startTimeDate = new Date ;
2015-04-28 14:44:56 +00:00
//$recordingTimer = $("<span id='recording-timer'>(0:00)</span>");
var $recordingStatus = $ ( '<span></span>' ) . append ( "<span>Stop Recording</span>" ) //.append($recordingTimer);
2013-11-03 20:55:55 +00:00
$ ( '#recording-status' ) . html ( $recordingStatus ) ;
2015-04-28 14:44:56 +00:00
//recordingTimerInterval = setInterval(updateRecordingTimer, 1000);
2013-11-03 20:55:55 +00:00
}
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' ) ;
2015-04-28 14:44:56 +00:00
$ ( '#recording-status' ) . text ( "Make Recording" ) ;
2013-11-03 20:55:55 +00:00
}
2015-02-27 17:51:45 +00:00
function lockControlsforJamTrackRecording ( ) {
sessionModel . lockControlsforJamTrackRecording ( ) ;
}
function unlockControlsforJamTrackRecording ( ) {
sessionModel . unlockControlsforJamTrackRecording ( ) ;
}
2013-11-03 20:55:55 +00:00
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"
} ) ;
} )
}
}
2015-04-17 20:01:56 +00:00
function promptUserToSave ( recordingId , timeline ) {
2013-11-03 20:55:55 +00:00
rest . getRecording ( { id : recordingId } )
. done ( function ( recording ) {
2015-04-17 21:32:53 +00:00
if ( timeline ) {
recording . timeline = timeline . global
}
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-03-13 02:53:23 +00:00
function checkPendingMetronome ( ) {
2015-04-29 21:02:33 +00:00
if ( sessionModel . jamTracks ( ) !== null || sessionModel . recordedJamTracks ( ) !== null ) {
// ignore all metronome events when jamtracks are open, because backend opens metronome mixer to play jamtrack tap-ins
logger . debug ( "ignore checkPendingMetronome because JamTrack is open" )
return ;
}
2015-04-17 20:01:56 +00:00
//logger.debug("checkPendingMetronome", sessionModel.isMetronomeOpen(), getMetronomeMasterMixers().length)
2015-03-13 02:53:23 +00:00
if ( sessionModel . isMetronomeOpen ( ) && getMetronomeMasterMixers ( ) . length == 0 ) {
var pendingMetronome = $ ( $templatePendingMetronome . html ( ) )
// hide the open options
otherAudioFilled ( ) ;
// fill out the 'media' name
$ ( '.session-recordings .session-recording-name' ) . text ( 'Metronome' )
// and hide the close button
$closePlaybackRecording . hide ( ) ;
// avoid double addition of pending metronome
if ( $otherAudioContainer . find ( '.pending-metronome' ) . length === 0 ) {
$otherAudioContainer . append ( pendingMetronome )
}
}
else {
$ ( '.session-recordings .pending-metronome' ) . remove ( )
}
}
2015-01-16 02:28:34 +00:00
function openBackingTrack ( e ) {
2015-02-20 15:50:03 +00:00
if ( $openBackingTrack . is ( '.disabled' ) ) {
logger . debug ( "backing track dialog already open" )
return false ;
}
2015-01-16 02:28:34 +00:00
// 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-20 15:50:03 +00:00
$openBackingTrack . addClass ( 'disabled' ) ;
2015-02-16 04:14:30 +00:00
context . jamClient . ShowSelectBackingTrackDialog ( "window.JK.HandleBackingTrackSelectedCallback" ) ;
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 ;
}
2015-02-27 17:51:45 +00:00
app . layout . showDialog ( 'open-jam-track-dialog' ) . one ( EVENTS . DIALOG _CLOSED , function ( e , data ) {
// once the dialog is closed, see if the user has a jamtrack selected
if ( ! data . canceled && data . result . jamTrack ) {
2015-05-12 20:45:23 +00:00
loadJamTrack ( data . result . jamTrack ) ;
}
else {
logger . debug ( "OpenJamTrack dialog closed with no selection; ignoring" , data )
}
} )
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
return false ;
}
2015-04-12 21:22:01 +00:00
2015-05-12 20:45:23 +00:00
function loadJamTrack ( jamTrack ) {
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
$ ( '.session-recording-name' ) . text ( '' ) ;
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
// hide 'other audio' placeholder
otherAudioFilled ( ) ;
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
if ( downloadJamTrack ) {
// if there was one showing before somehow, destroy it.
logger . warn ( "destroying existing JamTrack" )
downloadJamTrack . root . remove ( ) ;
downloadJamTrack . destroy ( ) ;
downloadJamTrack = null
}
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
downloadJamTrack = new context . JK . DownloadJamTrack ( app , jamTrack , 'large' ) ;
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
// the widget indicates when it gets to any transition; we can hide it once it reaches completion
$ ( downloadJamTrack ) . on ( EVENTS . JAMTRACK _DOWNLOADER _STATE _CHANGED , function ( e , data ) {
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
if ( data . state == downloadJamTrack . states . synchronized ) {
logger . debug ( "jamtrack synchronized; hide widget and show tracks" )
downloadJamTrack . root . remove ( ) ;
downloadJamTrack . destroy ( ) ;
downloadJamTrack = null ;
2015-05-01 17:09:18 +00:00
2015-05-12 20:45:23 +00:00
// XXX: test with this removed; it should be unnecessary
context . jamClient . JamTrackStopPlay ( ) ;
2015-05-01 17:09:18 +00:00
2015-05-12 20:45:23 +00:00
var sampleRate = context . jamClient . GetSampleRate ( )
var sampleRateForFilename = sampleRate == 48 ? '48' : '44'
var fqId = jamTrack . id + '-' + sampleRateForFilename
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
if ( jamTrack . jmep )
{
logger . debug ( "setting jmep data" )
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
context . jamClient . JamTrackLoadJmep ( fqId , jamTrack . jmep )
}
else {
logger . debug ( "no jmep data for jamtrack" )
}
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
// JamTrackPlay means 'load'
var result = context . jamClient . JamTrackPlay ( fqId ) ;
2015-02-27 17:51:45 +00:00
2015-05-12 20:45:23 +00:00
if ( ! result ) {
app . notify (
{ title : "JamTrack Can Not Open" ,
text : "Unable to open your JamTrack. Please contact support@jamkazam.com"
} , null , true ) ;
} else {
playJamTrack ( jamTrack . id ) ;
}
2015-02-27 17:51:45 +00:00
}
} )
2015-01-09 02:35:39 +00:00
2015-05-12 20:45:23 +00:00
// show it on the page
$otherAudioContainer . append ( downloadJamTrack . root )
2015-01-09 02:35:39 +00:00
2015-05-12 20:45:23 +00:00
// kick off the download JamTrack process
downloadJamTrack . init ( )
}
2015-04-07 19:04:29 +00:00
function playJamTrack ( jamTrackId ) {
var participantCnt = sessionModel . participants ( ) . length
2015-04-13 18:08:34 +00:00
rest . playJamTrack ( jamTrackId )
2015-04-17 19:01:07 +00:00
. done ( function ( ) {
app . refreshUser ( ) ;
} )
2015-04-15 23:37:07 +00:00
context . stats . write ( 'web.jamtrack.open' , {
value : 1 ,
session _size : participantCnt ,
user _id : context . JK . currentUserId ,
user _name : context . JK . currentUserName
} )
2015-04-07 19:04:29 +00:00
} // function
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-04-07 19:04:29 +00:00
context . stats . write ( 'web.backingtrack.open' , {
value : 1 ,
session _size : participantCnt ,
user _id : context . JK . currentUserId ,
user _name : context . JK . currentUserName
} )
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:
2015-03-04 01:06:55 +00:00
var myState = context . jamClient . getMyNetworkState ( )
2015-02-15 20:00:36 +00:00
var map ;
2015-03-04 01:06:55 +00:00
2015-02-15 20:00:36 +00:00
$ . each ( sessionModel . participants ( ) , function ( index , participant ) {
2015-03-04 01:06:55 +00:00
var isSelf = participant . client _id == app . clientId ;
if ( isSelf ) {
var isStable = myState . ntp _stable ;
}
else {
2015-02-15 20:00:36 +00:00
map = context . jamClient . getPeerState ( participant . client _id )
2015-03-04 01:06:55 +00:00
var isStable = map . ntp _stable ;
}
2015-02-15 20:00:36 +00:00
2015-03-04 01:06:55 +00:00
if ( ! isStable ) {
2015-02-15 20:00:36 +00:00
var name = participant . user . name ;
if ( ! ( name ) ) {
name = participant . user . first _name + ' ' + participant . user . last _name ;
}
2015-03-04 01:06:55 +00:00
if ( isSelf ) {
name += " (this computer)"
2015-02-15 20:00:36 +00:00
}
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 ( )
2015-03-04 01:06:55 +00:00
if ( sessionModel . participants ( ) . length > 1 && unstable . length > 0 ) {
2015-02-15 20:00:36 +00:00
var names = unstable . join ( ", " )
2015-02-19 15:31:30 +00:00
logger . debug ( "Unstable clocks: " , names , unstable )
2015-03-04 01:06:55 +00:00
context . JK . Banner . showAlert ( "Couldn't open metronome" , context . _ . template ( $ ( '#template-help-metronome-unstable' ) . html ( ) , { names : names } , { variable : 'data' } ) ) ;
2015-02-15 20:00:36 +00:00
} else {
2015-04-01 02:08:09 +00:00
var data = {
value : 1 ,
session _size : sessionModel . participants ( ) . length ,
user _id : context . JK . currentUserId ,
user _name : context . JK . currentUserName }
2015-04-01 14:04:52 +00:00
context . stats . write ( 'web.metronome.open' , data )
2015-03-04 01:06:55 +00:00
var bpm = 120 ;
logger . debug ( "opening the metronome with bpm: " + bpm + ", sound:" + metroSound )
2015-02-15 20:00:36 +00:00
rest . openMetronome ( { id : sessionModel . id ( ) } )
. done ( function ( ) {
2015-03-04 01:06:55 +00:00
context . jamClient . SessionStopPlay ( ) ;
context . jamClient . SessionOpenMetronome ( bpm , metroSound , 1 , 0 ) ;
2015-02-15 20:00:36 +00:00
} )
. fail ( function ( jqXHR ) {
2015-02-19 15:31:30 +00:00
logger . debug ( jqXHR , jqXHR )
2015-02-15 20:00:36 +00:00
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-02-27 17:51:45 +00:00
else if ( sessionModel . jamTracks ( ) || downloadJamTrack ) {
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 ( ) ;
}
2015-03-04 01:06:55 +00:00
else if ( getMetronomeMasterMixers ( ) . length > 0 ) {
2015-01-21 04:14:48 +00:00
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 ( ) {
2015-04-21 21:34:57 +00:00
2015-04-21 21:30:40 +00:00
if ( sessionModel . recordingModel . isRecording ( ) ) {
logger . debug ( "can't close backing track while recording" )
return false ;
}
2015-01-16 02:28:34 +00:00
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 ( {
2015-02-24 23:16:12 +00:00
"title" : "Couldn't Close Backing Track" ,
"text" : "Couldn't inform the server to close Backing Track. msg=" + jqXHR . responseText ,
2015-01-16 02:28:34 +00:00
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ;
} ) ;
2015-02-03 15:25:45 +00:00
// '' closes all open backing tracks
2015-02-23 16:56:22 +00:00
context . jamClient . SessionStopPlay ( ) ;
2015-02-03 15:25:45 +00:00
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 ( ) {
2015-05-01 21:30:03 +00:00
logger . debug ( "closing jam track" ) ;
2015-02-27 17:51:45 +00:00
2015-04-21 21:30:40 +00:00
if ( sessionModel . recordingModel . isRecording ( ) ) {
logger . debug ( "can't close jamtrack while recording" )
2015-05-01 21:34:56 +00:00
app . notify ( { title : 'Can Not Close JamTrack' , text : 'A JamTrack can not be closed while recording.' } )
2015-04-21 21:30:40 +00:00
return false ;
}
2015-05-01 21:30:03 +00:00
if ( ! sessionModel . selfOpenedJamTracks ( ) ) {
logger . debug ( "can't close jamtrack if not the opener" )
2015-05-01 21:34:56 +00:00
app . notify ( { title : 'Can Not Close JamTrack' , text : 'Only the person who opened the JamTrack can close it.' } )
2015-05-01 21:30:03 +00:00
return false ;
}
2015-05-01 21:30:03 +00:00
if ( ! sessionModel . selfOpenedJamTracks ( ) ) {
logger . debug ( "can't close jamtrack if not the opener" )
return false ;
}
2015-02-27 17:51:45 +00:00
if ( downloadJamTrack ) {
logger . debug ( "closing DownloadJamTrack widget" )
downloadJamTrack . root . remove ( ) ;
downloadJamTrack . destroy ( ) ;
downloadJamTrack = null ;
// this is necessary because a syncing widget means no jamtracks are loaded;
// so removing the widget will not cause a backend media change event (and so renderSession will not be called, ultimately)
resetOtherAudioContent ( ) ;
}
2015-01-09 02:35:39 +00:00
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 ( ) {
2015-02-27 17:51:45 +00:00
logger . debug ( "closing recording" ) ;
2014-01-05 03:47:23 +00:00
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 ;
}
2015-03-04 01:06:55 +00:00
function onPause ( e , data ) {
2015-04-28 13:58:34 +00:00
// if a JamTrack is open, and the user hits 'pause' or 'stop', we need to automatically stop the recording
2015-04-21 21:34:57 +00:00
if ( sessionModel . jamTracks ( ) && sessionModel . recordingModel . isRecording ( ) ) {
2015-05-06 20:54:06 +00:00
logger . debug ( "preemptive jamtrack stop" )
2015-04-21 21:34:57 +00:00
startStopRecording ( ) ;
}
2015-03-04 01:06:55 +00:00
if ( ! data . endReached ) {
2015-05-07 02:08:17 +00:00
logger . debug ( "calling jamClient.SessionPausePlay. endReached:" , data . endReached ) ;
2015-04-28 13:58:34 +00:00
context . jamClient . SessionPausePlay ( ) ;
2015-03-04 01:06:55 +00:00
}
2014-01-05 03:47:23 +00:00
}
2015-04-28 13:58:34 +00:00
function onStop ( e , data ) {
// if a JamTrack is open, and the user hits 'pause' or 'stop', we need to automatically stop the recording
if ( sessionModel . jamTracks ( ) && sessionModel . recordingModel . isRecording ( ) ) {
2015-05-06 20:54:06 +00:00
logger . debug ( "preemptive jamtrack stop" )
2015-04-28 13:58:34 +00:00
startStopRecording ( ) ;
}
if ( ! data . endReached ) {
2015-05-07 02:08:17 +00:00
logger . debug ( "calling jamClient.SessionStopPlay. endReached:" , data . endReached ) ;
2015-04-28 13:58:34 +00:00
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 ) {
2015-03-25 20:01:22 +00:00
var seek = data . positionMs ;
if ( data . playbackMonitorMode == context . JK . PLAYBACK _MONITOR _MODE . JAMTRACK ) {
// if positionMs == 0, then seek it back to whatever the earliest play start is to catch all the prelude
if ( seek == 0 ) {
var duration = context . jamClient . SessionGetJamTracksPlayDurationMs ( ) ;
seek = duration . start ;
}
}
logger . debug ( "calling jamClient.SessionTrackSeekMs(" + seek + ")" ) ;
2015-02-27 17:51:45 +00:00
2015-03-04 01:06:55 +00:00
if ( data . playbackMonitorMode == context . JK . PLAYBACK _MONITOR _MODE . JAMTRACK ) {
2015-05-12 19:42:10 +00:00
// this doesn't ever show anything, because of blocking nature of the seek call
//var $mediaSeeking = $screen.find('.media-seeking')
//$mediaSeeking.attr('data-mode', 'SEEKING')
2015-03-25 20:01:22 +00:00
context . jamClient . SessionJamTrackSeekMs ( seek ) ;
2015-05-12 19:42:10 +00:00
//$mediaSeeking.attr('data-mode', '')
2015-02-27 17:51:45 +00:00
}
else {
2015-03-25 20:01:22 +00:00
context . jamClient . SessionTrackSeekMs ( seek ) ;
2015-02-27 17:51:45 +00:00
}
2014-01-05 03:47:23 +00:00
}
2013-11-03 20:55:55 +00:00
function startStopRecording ( ) {
2015-02-27 17:51:45 +00:00
// check first if a jamtrack is loaded, and playing; if so, tell user to stop the play
2015-03-26 22:45:23 +00:00
/ * * i f ( s e s s i o n M o d e l . j a m T r a c k s ( ) & & c o n t e x t . j a m C l i e n t . i s S e s s i o n T r a c k P l a y i n g ( ) ) {
2015-02-27 17:51:45 +00:00
app . notify (
{ title : "Can't Recording a Play JamTrack" ,
text : "Stop the JamTrack before trying to recording." } ,
null ,
true ) ;
return ;
2015-03-26 22:45:23 +00:00
} * /
2015-02-27 17:51:45 +00:00
2013-11-03 20:55:55 +00:00
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
}
2015-03-04 01:06:55 +00:00
function setMetronomePlaybackMode ( ) {
$metronomePlaybackSelect . metronomeSetPlaybackMode ( metroCricket ? 'cricket' : 'self' )
}
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 == "" ) {
2015-03-04 01:06:55 +00:00
s = "Beep"
2015-01-29 22:12:26 +00:00
} else {
s = sound
}
2015-02-18 09:43:33 +00:00
logger . debug ( "Setting tempo and sound:" , t , s )
2015-02-12 20:05:25 +00:00
metroTempo = t
metroSound = s
2015-03-04 01:06:55 +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-03-04 01:06:55 +00:00
function metronomePlaybackModeChanged ( e , data ) {
var mode = data . playbackMode ; // will be either 'self' or 'cricket'
logger . debug ( "setting metronome playback mode: " , mode )
var isCricket = mode == 'cricket' ;
context . jamClient . setMetronomeCricketTestState ( isCricket ) ;
}
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-04-08 19:34:05 +00:00
function showFTUEWhenNoInputs ( ) {
//app.afterFtue = function() { window.location.reload };
2015-04-29 21:41:02 +00:00
//app.layout.startNewFtue();
window . location = '/client#/account/audio'
2015-04-08 19:34:05 +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 ) ;
2015-04-16 18:05:40 +00:00
$ ( '#session-webcam' ) . on ( 'click' , sessionWebCam ) ;
2012-10-06 16:36:05 +00:00
$ ( '#session-contents' ) . on ( "click" , '[action="delete"]' , deleteSession ) ;
2015-04-08 19:34:05 +00:00
$tracksHolder . 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-02-20 15:50:03 +00:00
$openBackingTrack . on ( 'click' , openBackingTrack ) ;
2015-01-16 02:28:34 +00:00
$ ( '#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 ( ) {
2015-04-08 19:34:05 +00:00
if ( gearUtils . isNoInputProfile ( ) ) {
// show FTUE
2015-04-29 21:41:02 +00:00
// showFTUEWhenNoInputs();
app . notify ( { title : 'Settings Disabled' , text : 'You can not alter any settings for the System Default playback device.' } )
2015-04-08 19:34:05 +00:00
return false ;
}
else {
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 ) ;
2015-04-08 19:34:05 +00:00
}
2013-05-18 05:59:25 +00:00
} ) ;
2014-01-25 15:37:15 +00:00
2015-04-08 19:34:05 +00:00
$openFtue . click ( function ( ) {
showFTUEWhenNoInputs ( ) ;
return false ;
} )
2015-02-18 21:41:51 +00:00
$closePlaybackRecording . on ( 'click' , closeOpenMedia ) ;
2014-01-05 03:47:23 +00:00
$ ( playbackControls )
. on ( 'pause' , onPause )
2015-04-28 13:58:34 +00:00
. on ( 'stop' , onStop )
2014-01-05 03:47:23 +00:00
. 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 )
2015-03-04 01:06:55 +00:00
$metronomePlaybackSelect . metronomePlaybackMode ( ) . on ( EVENTS . METRONOME _PLAYBACK _MODE _SELECTED , metronomePlaybackModeChanged )
context . JK . helpBubble ( $metronomePlaybackHelp , 'metromone-playback-modes' , { } , { offsetParent : $screen , width : '400px' } ) ;
2015-03-27 20:36:09 +00:00
$ ( document ) . on ( 'layout_resized' , function ( ) {
resizeFluid ( ) ;
} ) ;
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' ) ;
2015-02-27 17:51:45 +00:00
$otherAudioContainer = $ ( '#session-recordedtracks-container' ) ;
2015-04-08 19:34:05 +00:00
$myTracksNoTracks = $ ( '#session-mytracks-notracks' )
$openFtue = $screen . find ( '.open-ftue-no-tracks' )
2015-02-27 17:51:45 +00:00
$myTracksContainer = $ ( '#session-mytracks-container' )
$liveTracksContainer = $ ( '#session-livetracks-container' ) ;
2015-02-18 21:41:51 +00:00
$closePlaybackRecording = $ ( '#close-playback-recording' )
2015-02-20 15:50:03 +00:00
$openBackingTrack = $ ( '#open-a-backingtrack' ) ;
2015-03-04 01:06:55 +00:00
$metronomePlaybackSelect = $ ( '#metronome-playback-select' )
$metronomePlaybackHelp = $ ( '#metronome-playback-help' )
2015-03-13 02:53:23 +00:00
$templatePendingMetronome = $ ( '#template-pending-metronome' ) ;
2015-03-27 20:36:09 +00:00
$myTracks = $screen . find ( '.session-mytracks' ) ;
$liveTracks = $screen . find ( '.session-livetracks' ) ;
$audioTracks = $screen . find ( '.session-recordings' ) ;
2015-04-08 19:34:05 +00:00
$fluidTracks = $screen . find ( '.session-fluidtracks' ) ;
$voiceChat = $screen . find ( '#voice-chat' ) ;
$tracksHolder = $screen . find ( '#tracks' )
2015-04-22 18:28:44 +00:00
if ( gon . global . video _available && gon . global . video _available != "none" ) {
2015-04-22 15:18:33 +00:00
webcamViewer . init ( $ ( ".webcam-container" ) )
webcamViewer . setVideoOff ( )
}
2014-11-11 22:21:29 +00:00
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 ;
}
2015-05-04 02:28:17 +00:00
this . onPlaybackStateChange = function ( change _type ) {
// if it's play_stop or play_start, poke the playControls
if ( change _type == 'play_start' ) {
playbackControls . onPlayStartEvent ( ) ;
}
else if ( change _type == 'play_stop' ) {
playbackControls . onPlayStopEvent ( ) ;
}
else if ( change _type == 'play_pause' ) {
playbackControls . onPlayPauseEvent ( ) ;
}
}
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 ) ;