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 ) {
2012-10-14 15:48:56 +00:00
var logger = context . JK . logger ;
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 = [ ] ;
2013-01-30 16:50:43 +00:00
var mixers = [ ] ;
2013-03-02 19:02:42 +00:00
2013-05-22 05:03:34 +00:00
var configureTrackDialog ;
var addTrackDialog ;
2013-05-23 12:46:40 +00:00
var addNewGearDialog ;
2013-05-13 22:35:14 +00:00
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 ;
2012-10-06 16:36:05 +00:00
2013-02-14 07:02:05 +00:00
var lookingForMixersCount = 0 ;
var lookingForMixersTimer = null ;
var lookingForMixers = { } ;
2013-02-05 05:10:37 +00:00
var defaultParticipant = {
2013-02-10 00:33:47 +00:00
tracks : [ {
instrument _id : "unknown"
} ] ,
2013-02-05 05:10:37 +00:00
user : {
first _name : 'Unknown' ,
last _name : 'User' ,
photo _url : null
}
} ;
2013-08-03 18:30:45 +00:00
// Be sure to copy/extend these instead of modifying in place
var trackVuOpts = {
vuType : "vertical" ,
lightCount : 13 ,
lightWidth : 3 ,
lightHeight : 17
} ;
// Must add faderId key to this
var trackFaderOpts = {
faderType : "vertical" ,
height : 83
} ;
2013-02-26 03:54:09 +00:00
// Recreate ChannelGroupIDs ENUM from C++
var ChannelGroupIds = {
"MasterGroup" : 0 ,
"MonitorGroup" : 1 ,
"AudioInputMusicGroup" : 2 ,
"AudioInputChatGroup" : 3 ,
"MediaTrackGroup" : 4 ,
"StreamOutMusicGroup" : 5 ,
"StreamOutChatGroup" : 6 ,
"UserMusicInputGroup" : 7 ,
"UserChatInputGroup" : 8 ,
"PeerAudioInputMusicGroup" : 9
} ;
2013-02-05 05:10:37 +00:00
2013-07-09 03:06:01 +00:00
// recreate eThresholdType enum from MixerDialog.h
var alert _type = {
0 : { "title" : "" , "message" : "" } , // packet jitter
1 : { "title" : "Packet Loss" , "message" : "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, click here." } , // packet loss
2 : { "title" : "" , "message" : "" } , // packet late
3 : { "title" : "" , "message" : "" } , // network jitter
2013-07-09 22:46:51 +00:00
4 : { "title" : "Session Latency" , "message" : "The latency of your audio device combined with your Internet connection has become high enough to impact your session quality. For troubleshooting tips, click here." } , // network ping
2013-07-09 03:06:01 +00:00
5 : { "title" : "" , "message" : "" } , // bitrate throttle warning
6 : { "title" : "Low Bandwidth" , "message" : "The available bandwidth on your network has become too low,and this may impact your audio quality. For troubleshooting tips, click here." } , // bandwidth low
7 : { "title" : "Input Rate" , "message" : "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click here." } , // input IO rate
8 : { "title" : "" , "message" : "" } , // input IO jitter
9 : { "title" : "Output Rate" , "message" : "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click here." } , // output IO rate
10 : { "title" : "" , "message" : "" } , // output IO jitter
2013-07-09 22:46:51 +00:00
11 : { "title" : "CPU Utilization High" , "message" : "The CPU of your computer is unable to keep up with the current processing load, and this may impact your audio quality. For troubleshooting tips, click here." } , // CPU load
2013-07-09 03:06:01 +00:00
12 : { "title" : "" , "message" : "" } , // decode violations
2013-07-20 15:38:52 +00:00
13 : { "title" : "" , "message" : "" } // last threshold
2013-07-09 03:06:01 +00:00
} ;
2012-10-29 15:10:02 +00:00
function beforeShow ( data ) {
sessionId = data . id ;
2013-02-06 04:32:56 +00:00
$ ( '#session-mytracks-container' ) . empty ( ) ;
2012-10-29 15:10:02 +00:00
}
2012-10-29 00:37:59 +00:00
2013-08-18 02:36:07 +00:00
function alertCallback ( type , text ) {
setTimeout ( function ( ) {
app . notify ( {
"title" : alert _type [ type ] . title ,
"text" : text ,
"icon_url" : "/assets/content/icon_alert_big.png"
} ) ; } , 1 ) ;
2013-07-09 03:06:01 +00:00
}
2012-10-06 16:36:05 +00:00
function afterShow ( data ) {
2013-05-31 02:07:33 +00:00
// indicate that the screen is active, so that
// body-scoped drag handlers can go active
screenActive = true ;
2013-01-30 16:50:43 +00:00
// Subscribe for callbacks on audio events
2013-08-07 20:04:22 +00:00
context . jamClient . RegisterVolChangeCallBack ( "JK.HandleVolumeChangeCallback" ) ;
2013-01-30 16:50:43 +00:00
context . jamClient . SessionRegisterCallback ( "JK.HandleBridgeCallback" ) ;
2013-07-09 03:06:01 +00:00
context . jamClient . SessionSetAlertCallback ( "JK.AlertCallback" ) ;
2012-10-29 00:37:59 +00:00
2013-02-26 03:54:09 +00:00
// 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 ( ) ;
}
function afterCurrentUserLoaded ( ) {
2013-03-02 19:02:42 +00:00
sessionModel = new context . JK . SessionModel (
context . JK . JamServer ,
context . jamClient ,
context . JK . userMe
) ;
sessionModel . subscribe ( 'sessionScreen' , sessionChanged ) ;
sessionModel . joinSession ( sessionId ) ;
2013-02-10 18:51:37 +00:00
}
2012-10-29 00:37:59 +00:00
function beforeHide ( data ) {
2013-05-31 02:07:33 +00:00
// track that the screen is inactive, to disable body-level handlers
screenActive = false ;
2013-03-02 19:02:42 +00:00
sessionModel . leaveCurrentSession ( sessionId ) ;
2013-01-31 05:23:30 +00:00
// 'unregister' for callbacks
context . jamClient . SessionRegisterCallback ( "" ) ;
2013-07-09 03:06:01 +00:00
context . jamClient . SessionSetAlertCallback ( "" ) ;
2012-10-06 16:36:05 +00:00
}
2013-03-02 19:02:42 +00:00
function sessionChanged ( ) {
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.
context . setTimeout ( renderSession , 750 ) ;
}
/ * *
* 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 .
* /
function getMixer ( mixerId ) {
var foundMixer = null ;
$ . each ( mixers , function ( index , mixer ) {
if ( mixer . id === mixerId ) {
foundMixer = mixer ;
}
} ) ;
return foundMixer ;
2012-11-03 20:25:23 +00:00
}
function renderSession ( ) {
2013-02-14 07:02:05 +00:00
$ ( '#session-mytracks-container' ) . empty ( ) ;
2013-06-24 03:08:38 +00:00
$ ( '.session-track' ) . remove ( ) ; // Remove previous tracks
2013-01-30 16:50:43 +00:00
_updateMixers ( ) ;
2012-11-03 20:25:23 +00:00
_renderTracks ( ) ;
2013-02-07 04:58:41 +00:00
_wireTopVolume ( ) ;
2013-04-10 15:01:29 +00:00
_wireTopMix ( ) ;
2013-02-07 04:58:41 +00:00
_addVoiceChat ( ) ;
2013-05-22 05:03:34 +00:00
_initDialogs ( ) ;
2013-06-24 03:08:38 +00:00
if ( $ ( '.session-livetracks .track' ) . length === 0 ) {
$ ( '.session-livetracks .when-empty' ) . show ( ) ;
}
2013-05-22 05:03:34 +00:00
}
2013-05-12 05:43:36 +00:00
2013-05-22 05:03:34 +00:00
function _initDialogs ( ) {
configureTrackDialog . initialize ( ) ;
addTrackDialog . initialize ( ) ;
2013-05-23 12:46:40 +00:00
addNewGearDialog . initialize ( ) ;
2013-01-30 16:50:43 +00:00
}
// Get the latest list of underlying audio mixer channels
function _updateMixers ( ) {
2013-01-31 16:32:32 +00:00
var mixerIds = context . jamClient . SessionGetIDs ( ) ;
2013-02-05 05:10:37 +00:00
var holder = $ . extend ( true , { } , { mixers : context . jamClient . SessionGetControlState ( mixerIds ) } ) ;
mixers = holder . mixers ;
2013-04-10 15:01:29 +00:00
// Always add a hard-coded simplified 'mixer' for the L2M mix
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
}
2013-02-14 07:02:05 +00:00
function _mixerForClientId ( clientId , groupIds ) {
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 ] ) {
foundMixer = mixer ;
return false ;
}
}
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
}
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 = [ ] ;
2013-02-07 04:58:41 +00:00
$ . each ( mixers , function ( index , mixer ) {
2013-02-26 03:54:09 +00:00
if ( 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
}
2013-02-26 03:54:09 +00:00
if ( mixer . group _id === ChannelGroupIds . MonitorGroup ) {
2013-03-14 03:29:57 +00:00
mixerIds . push ( mixer . id ) ;
2013-02-07 04:58:41 +00:00
}
} ) ;
2013-07-31 23:39:10 +00:00
var faderId = mixerIds . join ( ',' ) ;
$ ( '#volume' ) . attr ( 'mixer-id' , faderId ) ;
var faderOpts = {
faderId : faderId ,
faderType : "horizontal" ,
width : 50 ,
style : {
"background-image" : "none" ,
"background-repeat" : "no-repeat" ,
"height" : "24px"
}
} ;
context . JK . FaderHelpers . renderFader ( "#volume" , faderOpts ) ;
context . JK . FaderHelpers . subscribe ( faderId , faderChanged ) ;
// Visually update fader to underlying mixer start value.
2013-08-07 20:04:22 +00:00
// Always do this, even if gainPercent is zero.
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 ( )
} ;
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"
}
} ;
context . JK . FaderHelpers . renderFader ( faderId , faderOpts ) ;
context . JK . FaderHelpers . subscribe ( faderId , l2mChanged ) ;
// Visually update fader to underlying mixer start value.
2013-08-07 20:04:22 +00:00
context . JK . FaderHelpers . setFaderValue ( faderId , gainPercent ) ;
2013-07-31 23:39:10 +00:00
}
/ * *
* This has a specialized jamClient call , so custom handler .
* /
function l2mChanged ( faderId , newValue , dragging ) {
// TODO - assuming -80 to 20 db range on l2m.
var dbValue = newValue - 80 ;
context . jamClient . SessionSetMasterLocalMix ( dbValue ) ;
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.
$ . each ( mixers , function ( index , mixer ) {
2013-02-26 03:54:09 +00:00
if ( mixer . group _id === ChannelGroupIds . AudioInputChatGroup ) {
2013-02-08 05:08:05 +00:00
var $voiceChat = $ ( '#voice-chat' ) ;
$voiceChat . show ( ) ;
$voiceChat . attr ( 'mixer-id' , mixer . id ) ;
$ ( '#voice-chat .voicechat-mute' ) . attr ( 'mixer-id' , mixer . id ) ;
2013-02-13 05:30:07 +00:00
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
2013-07-31 23:39:10 +00:00
var faderOpts = {
faderId : mixer . id ,
faderType : "horizontal" ,
width : 50
} ;
context . JK . FaderHelpers . renderFader ( "#voice-chat .voicechat-gain" , faderOpts ) ;
context . JK . FaderHelpers . subscribe ( mixer . id , faderChanged ) ;
2013-08-07 20:04:22 +00:00
context . JK . FaderHelpers . setFaderValue ( mixer . id , gainPercent ) ;
2013-02-13 05:30:07 +00:00
if ( mixer . mute ) {
var $mute = $voiceChat . find ( '.voicechat-mute' ) ;
_toggleVisualMuteControl ( $mute , true ) ;
}
2013-02-08 05:08:05 +00:00
}
} ) ;
2013-02-07 04:58:41 +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.
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 ;
}
2013-05-15 05:59:09 +00:00
// loop through all tracks for each participant
$ . each ( participant . tracks , function ( index , track ) {
var instrumentIcon = context . JK . getInstrumentIcon45 ( track . instrument _id ) ;
var photoUrl = context . JK . resolveAvatarUrl ( participant . user . photo _url ) ;
var myTrack = false ;
// Default trackData to participant + no Mixer state.
var trackData = {
trackId : track . id ,
2013-05-22 11:48:37 +00:00
connection _id : track . connection _id ,
2013-05-15 05:59:09 +00:00
clientId : participant . client _id ,
name : name ,
instrumentIcon : instrumentIcon ,
avatar : photoUrl ,
latency : "good" ,
gainPercent : 0 ,
muteClass : 'muted' ,
mixerId : ""
} ;
var mixer = _mixerForClientId (
participant . client _id ,
[
ChannelGroupIds . AudioInputMusicGroup ,
ChannelGroupIds . UserMusicInputGroup
] ) ;
if ( mixer ) {
myTrack = ( mixer . group _id === ChannelGroupIds . AudioInputMusicGroup ) ;
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var muteClass = "enabled" ;
if ( mixer . mute ) {
muteClass = "muted" ;
}
trackData . gainPercent = gainPercent ;
trackData . muteClass = muteClass ;
trackData . mixerId = mixer . id ;
} else { // No mixer to match, yet
lookingForMixers [ participant . client _id ] = true ;
if ( ! ( lookingForMixersTimer ) ) {
lookingForMixersTimer = context . setInterval ( lookForMixers , 300 ) ;
}
2013-02-10 02:00:29 +00:00
}
2013-05-22 05:03:34 +00:00
_addTrack ( index , trackData ) ;
2013-05-15 05:59:09 +00:00
// Show settings icons only for my tracks
if ( myTrack ) {
$ ( 'div[mixer-id="' + mixer . id + '"].track-icon-settings' ) . show ( ) ;
2013-08-14 05:02:24 +00:00
console . log ( "Adding myTrack " + trackData . trackId ) ;
2013-05-24 01:16:00 +00:00
myTracks . push ( trackData ) ;
2013-02-10 00:33:47 +00:00
}
2013-05-24 01:16:00 +00:00
// TODO: UNCOMMENT THIS WHEN TESTING LOCALLY IN BROWSER
2013-08-15 05:12:59 +00:00
//myTracks.push(trackData);
2013-05-15 05:59:09 +00:00
} ) ;
2012-11-03 20:25:23 +00:00
} ) ;
2013-05-22 05:03:34 +00:00
configureTrackDialog = new context . JK . ConfigureTrackDialog ( app , myTracks , sessionId , sessionModel ) ;
addTrackDialog = new context . JK . AddTrackDialog ( app , myTracks , sessionId , sessionModel ) ;
2013-05-23 12:46:40 +00:00
addNewGearDialog = new context . JK . AddNewGearDialog ( app ) ;
2013-05-12 05:43:36 +00:00
2013-08-13 23:35:18 +00:00
// hide "Add Track" link if there are 2 tracks:
2013-08-13 23:35:40 +00:00
// # NO LONGER HIDING ADD TRACK even when there are 2 tracks (VRFS-537)
2013-08-15 05:12:59 +00:00
$ ( '#div-add-track' ) . click ( function ( ) {
if ( myTracks . length === 2 ) {
$ ( '#btn-error-ok' ) . click ( function ( ) {
app . layout . closeDialog ( 'error-dialog' ) ;
} ) ;
context . JK . showErrorDialog ( app , "You can only have a maximum of 2 personal tracks per session." , "max # of tracks" ) ;
}
else {
app . layout . showDialog ( 'add-track' ) ;
2013-05-22 05:03:34 +00:00
addTrackDialog . showDialog ( ) ;
2013-08-15 05:12:59 +00:00
}
} ) ;
2012-11-03 20:25:23 +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 ( ) ;
var keysToDelete = [ ] ;
for ( var key in lookingForMixers ) {
2013-02-26 03:54:09 +00:00
var mixer = _mixerForClientId (
key ,
[
ChannelGroupIds . AudioInputMusicGroup ,
ChannelGroupIds . UserMusicInputGroup
] ) ;
2013-02-14 07:02:05 +00:00
if ( mixer ) {
2013-08-03 18:30:45 +00:00
var vuOpts = $ . extend ( { } , trackVuOpts ) ;
var faderOpts = $ . extend ( { } , trackFaderOpts ) ;
faderOpts . faderId = mixer . id ;
var baseSelector = 'div.track[client-id="' + key + '"]' ;
var vuLeftSelector = baseSelector + " .track-vu-left" ;
var vuRightSelector = baseSelector + " .track-vu-right" ;
var faderSelector = baseSelector + " .track-gain" ;
2013-02-14 07:02:05 +00:00
keysToDelete . push ( key ) ;
var gainPercent = percentFromMixerValue (
mixer . range _low , mixer . range _high , mixer . volume _left ) ;
var $track = $ ( 'div.track[client-id="' + key + '"]' ) ;
2013-08-03 18:30:45 +00:00
// Set mixer-id attributes and render VU/Fader
context . JK . VuHelpers . renderVU ( vuLeftSelector , vuOpts ) ;
2013-08-05 03:00:23 +00:00
$track . find ( '.track-vu-left' ) . attr ( 'mixer-id' , mixer . id + '_vul' ) ;
2013-08-03 18:30:45 +00:00
context . JK . VuHelpers . renderVU ( vuRightSelector , vuOpts ) ;
2013-08-05 03:00:23 +00:00
$track . find ( '.track-vu-right' ) . attr ( 'mixer-id' , mixer . id + '_vur' ) ;
2013-08-03 18:30:45 +00:00
context . JK . FaderHelpers . renderFader ( faderSelector , faderOpts ) ;
context . JK . FaderHelpers . subscribe ( mixer . id , faderChanged ) ;
2013-02-14 07:02:05 +00:00
$track . find ( '.track-icon-mute' ) . attr ( 'mixer-id' , mixer . id ) ;
$track . find ( '.track-icon-settings' ) . attr ( 'mixer-id' , mixer . id ) ;
// Set gain position
2013-08-02 19:34:29 +00:00
context . JK . FaderHelpers . setFaderValue ( mixer . id , gainPercent ) ;
2013-02-14 07:02:05 +00:00
// Set mute state
_toggleVisualMuteControl ( $track . find ( '.track-icon-mute' ) , mixer . mute ) ;
}
}
for ( var i = 0 ; i < keysToDelete . length ; i ++ ) {
delete lookingForMixers [ keysToDelete [ i ] ] ;
}
if ( context . JK . dlen ( lookingForMixers ) === 0 ||
lookingForMixersCount > 10 ) {
lookingForMixersCount = 0 ;
lookingForMixers = { } ;
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.
function _updateVU ( mixerId , value ) {
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" , "" ) ;
var mixer = getMixer ( pureMixerId ) ;
if ( mixer ) {
if ( ! ( mixer . stereo ) ) { // mono track
if ( mixerId . substr ( - 4 ) === "_vul" ) {
// Do the left
selector = '#tracks [mixer-id="' + pureMixerId + '_vul"]' ;
context . JK . VuHelpers . updateVU ( selector , value ) ;
// Do the right
selector = '#tracks [mixer-id="' + pureMixerId + '_vur"]' ;
context . JK . VuHelpers . updateVU ( selector , value ) ;
} // otherwise, it's a mono track, _vur event - ignore.
} else { // stereo track
selector = '#tracks [mixer-id="' + mixerId + '"]' ;
context . JK . VuHelpers . updateVU ( selector , value ) ;
}
}
2013-01-30 16:50:43 +00:00
}
2013-05-22 05:03:34 +00:00
function _addTrack ( index , trackData ) {
2013-07-20 15:38:52 +00:00
var parentSelector = '#session-mytracks-container' ;
var $destination = $ ( parentSelector ) ;
2013-02-05 05:10:37 +00:00
if ( trackData . clientId !== app . clientId ) {
2013-07-20 15:38:52 +00:00
parentSelector = '#session-livetracks-container' ;
$destination = $ ( parentSelector ) ;
2013-06-24 03:08:38 +00:00
$ ( '.session-livetracks .when-empty' ) . hide ( ) ;
2013-02-05 05:10:37 +00:00
}
2012-10-21 23:03:46 +00:00
var template = $ ( '#template-session-track' ) . html ( ) ;
2012-12-07 00:28:48 +00:00
var newTrack = context . JK . fillTemplate ( template , trackData ) ;
2013-02-05 05:10:37 +00:00
$destination . append ( newTrack ) ;
2013-05-22 05:03:34 +00:00
2013-07-26 14:46:38 +00:00
// Render VU meters and gain fader
2013-07-20 15:38:52 +00:00
// Find the last child (just-appended):
var trackCount = $ ( parentSelector + ' .session-track' ) . length ;
2013-07-26 14:46:38 +00:00
var selectorPrefix = parentSelector + ' .session-track:nth-child(' + String ( trackCount ) + ')' ;
2013-08-03 18:30:45 +00:00
var vuOpts = $ . extend ( { } , trackVuOpts ) ;
var faderOpts = $ . extend ( { } , trackFaderOpts ) ;
faderOpts . faderId = trackData . mixerId ;
2013-07-26 14:46:38 +00:00
var vuLeftSelector = selectorPrefix + ' .track-vu-left' ;
var vuRightSelector = selectorPrefix + ' .track-vu-right' ;
var faderSelector = selectorPrefix + ' .track-gain' ;
2013-07-20 15:38:52 +00:00
context . JK . VuHelpers . renderVU ( vuLeftSelector , vuOpts ) ;
context . JK . VuHelpers . renderVU ( vuRightSelector , vuOpts ) ;
2013-07-26 14:46:38 +00:00
context . JK . FaderHelpers . renderFader ( faderSelector , faderOpts ) ;
context . JK . FaderHelpers . subscribe ( trackData . mixerId , faderChanged ) ;
// Visually update fader to underlying mixer start value.
if ( trackData . gainPercent ) {
context . JK . FaderHelpers . setFaderValue ( trackData . mixerId , trackData . gainPercent ) ;
2013-08-07 20:04:22 +00:00
} else {
context . JK . FaderHelpers . setFaderValue ( trackData . mixerId , 0 ) ;
2013-07-26 14:46:38 +00:00
}
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 + '"]' ) ;
if ( index === 0 ) {
$closeButton . hide ( ) ;
}
else {
$closeButton . click ( deleteTrack ) ;
}
2013-05-12 05:43:36 +00:00
$ ( 'div[mixer-id="' + trackData . mixerId + '"].track-icon-settings' ) . click ( function ( ) {
2013-05-16 05:15:16 +00:00
// call this to initialize Voice Chat tab
2013-05-22 05:03:34 +00:00
configureTrackDialog . showVoiceChatPanel ( true ) ;
configureTrackDialog . showMusicAudioPanel ( true ) ;
2013-05-12 05:43:36 +00:00
} ) ;
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
}
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 .
* /
function faderChanged ( faderId , newValue , dragging ) {
var mixerIds = faderId . split ( ',' ) ;
$ . each ( mixerIds , function ( i , v ) {
2013-08-02 21:16:49 +00:00
var broadcast = ! ( dragging ) ; // If fader is still dragging, don't broadcast
fillTrackVolumeObject ( v , broadcast ) ;
2013-07-26 14:46:38 +00:00
setMixerVolume ( v , newValue ) ;
} ) ;
}
2013-08-07 20:04:22 +00:00
function handleVolumeChangeCallback ( mixerId , isLeft , value ) {
// Visually update mixer
// TODO: Use mixer's range
var faderValue = percentFromMixerValue ( - 80 , 20 , value ) ;
context . JK . FaderHelpers . setFaderValue ( mixerId , faderValue ) ;
fillTrackVolumeObject ( mixerId , false ) ; // don't broadcast
setMixerVolume ( mixerId , faderValue ) ;
}
2013-01-31 05:23:30 +00:00
function handleBridgeCallback ( ) {
var eventName = null ;
var mixerId = null ;
var value = null ;
var tuples = arguments . length / 3 ;
for ( var i = 0 ; i < tuples ; i ++ ) {
eventName = arguments [ 3 * i ] ;
mixerId = arguments [ ( 3 * i ) + 1 ] ;
value = arguments [ ( 3 * i ) + 2 ] ;
var vuVal = 0.0 ;
if ( eventName === 'left_vu' || eventName === 'right_vu' ) {
// 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
vuVal = ( value + 80 ) / 100 ;
if ( eventName === 'left_vu' ) {
2013-01-31 16:32:32 +00:00
mixerId = mixerId + "_vul" ;
2013-01-31 05:23:30 +00:00
} else {
2013-01-31 16:32:32 +00:00
mixerId = mixerId + "_vur" ;
2013-01-31 05:23:30 +00:00
}
_updateVU ( mixerId , vuVal ) ;
2013-02-15 05:15:36 +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.
2013-01-31 16:32:32 +00:00
} else {
// Examples of other events
// Add media file track: "add", "The_Abyss_4T", 0
logger . debug ( 'non-vu event: ' + eventName + ',' + mixerId + ',' + value ) ;
2013-01-31 05:23:30 +00:00
}
2013-01-30 16:50:43 +00:00
}
}
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 ) {
context . location = "#/home" ;
} ,
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
}
2013-01-31 16:32:32 +00:00
function _toggleVisualMuteControl ( $control , muting ) {
if ( muting ) {
$control . removeClass ( 'enabled' ) ;
$control . addClass ( 'muted' ) ;
} else {
$control . removeClass ( 'muted' ) ;
$control . addClass ( 'enabled' ) ;
}
}
function _toggleAudioMute ( mixerId , muting ) {
2013-03-15 02:44:51 +00:00
fillTrackVolumeObject ( mixerId ) ;
2013-01-31 16:32:32 +00:00
context . trackVolumeObject . mute = muting ;
context . jamClient . SessionSetControlState ( mixerId ) ;
}
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 ( ',' ) ;
$ . each ( mixerIds , function ( i , v ) {
_toggleAudioMute ( v , muting ) ;
} ) ;
2013-01-31 16:32:32 +00:00
_toggleVisualMuteControl ( $control , muting ) ;
}
2013-03-24 20:47:45 +00:00
function fillTrackVolumeObject ( mixerId , broadcast ) {
2013-03-15 02:44:51 +00:00
_updateMixers ( ) ;
2013-02-03 22:47:17 +00:00
var mixer = null ;
2013-03-24 20:47:45 +00:00
var _broadcast = true ;
if ( broadcast !== undefined ) {
_broadcast = broadcast ;
}
2013-02-03 22:47:17 +00:00
for ( var i = 0 ; i < mixers . length ; i ++ ) {
mixer = mixers [ i ] ;
if ( mixer . id === mixerId ) {
context . trackVolumeObject . clientID = mixer . client _id ;
2013-03-24 20:47:45 +00:00
context . trackVolumeObject . broadcast = _broadcast ;
2013-02-03 22:47:17 +00:00
context . trackVolumeObject . master = mixer . master ;
context . trackVolumeObject . monitor = mixer . monitor ;
context . trackVolumeObject . mute = mixer . mute ;
context . trackVolumeObject . name = mixer . name ;
context . trackVolumeObject . record = mixer . record ;
context . trackVolumeObject . volL = mixer . volume _left ;
context . trackVolumeObject . volR = mixer . volume _right ;
// trackVolumeObject doesn't have a place for range min/max
currentMixerRangeMin = mixer . range _low ;
currentMixerRangeMax = mixer . range _high ;
break ;
}
}
}
2013-02-10 02:00:29 +00:00
// Given a mixer's min/max and current value, return it as
// a percent from 0-100. Return an integer.
function percentFromMixerValue ( min , max , value ) {
2013-08-07 20:04:22 +00:00
try {
var range = Math . abs ( max - min ) ;
var magnitude = value - min ;
var percent = Math . round ( 100 * ( magnitude / range ) ) ;
return percent ;
} catch ( err ) {
return 0 ;
}
2013-02-10 02:00:29 +00:00
}
// Given a mixer's min/max and a percent value, return it as
// the mixer's value. Returns an integer.
function percentToMixerValue ( min , max , percent ) {
var range = Math . abs ( max - min ) ;
var multiplier = percent / 100 ; // Change 85 into 0.85
var value = min + ( multiplier * range ) ;
// Protect against percents < 0 and > 100
if ( value < min ) {
value = min ;
}
if ( value > max ) {
value = max ;
}
return value ;
}
2013-02-03 22:47:17 +00:00
2013-02-10 02:00:29 +00:00
// Given a volume percent (0-100), set the underlying
2013-02-03 19:48:39 +00:00
// audio volume level of the passed mixerId to the correct
// value.
function setMixerVolume ( mixerId , volumePercent ) {
2013-02-03 22:47:17 +00:00
// The context.trackVolumeObject has been filled with the mixer values
// that go with mixerId, and the range of that mixer
// has been set in currentMixerRangeMin-Max.
// All that needs doing is to translate the incoming percent
// into the real value ont the sliders range. Set Left/Right
// volumes on trackVolumeObject, and call SetControlState to stick.
2013-02-10 02:00:29 +00:00
var sliderValue = percentToMixerValue (
currentMixerRangeMin , currentMixerRangeMax , volumePercent ) ;
2013-02-03 22:47:17 +00:00
context . trackVolumeObject . volL = sliderValue ;
context . trackVolumeObject . volR = sliderValue ;
2013-04-10 15:01:29 +00:00
// Special case for L2M mix:
if ( mixerId === '__L2M__' ) {
context . jamClient . SessionSetMasterLocalMix ( sliderValue ) ;
} else {
context . jamClient . SessionSetControlState ( mixerId ) ;
}
2013-02-03 19:48:39 +00:00
}
2012-10-06 16:36:05 +00:00
function events ( ) {
$ ( '#session-contents' ) . on ( "click" , '[action="delete"]' , deleteSession ) ;
2013-01-31 16:32:32 +00:00
$ ( '#tracks' ) . on ( 'click' , 'div[control="mute"]' , toggleMute ) ;
2013-03-15 02:44:51 +00:00
2013-05-12 05:43:36 +00:00
$ ( '.voicechat-settings' ) . click ( function ( ) {
2013-05-16 05:15:16 +00:00
// call this to initialize Music Audio tab
2013-05-22 05:03:34 +00:00
configureTrackDialog . showMusicAudioPanel ( true ) ;
configureTrackDialog . showVoiceChatPanel ( true ) ;
2013-05-18 05:59:25 +00:00
} ) ;
2012-10-06 16:36:05 +00:00
}
2012-10-14 15:48:56 +00:00
this . initialize = function ( ) {
2013-02-15 05:15:36 +00:00
context . jamClient . SetVURefreshRate ( 150 ) ;
2012-10-14 15:48:56 +00:00
events ( ) ;
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 ,
2012-10-29 15:10:02 +00:00
'beforeHide' : beforeHide
2012-10-14 15:48:56 +00:00
} ;
app . bindScreen ( 'session' , screenBindings ) ;
2012-10-06 16:36:05 +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
} ;
2013-06-11 01:53:49 +00:00
this . refreshCurrentSession = function ( ) {
sessionModel . refreshCurrentSession ( ) ;
} ;
2013-08-07 20:04:22 +00:00
context . JK . HandleVolumeChangeCallback = handleVolumeChangeCallback ;
2013-01-30 16:50:43 +00:00
context . JK . HandleBridgeCallback = handleBridgeCallback ;
2013-07-09 03:06:01 +00:00
context . JK . AlertCallback = alertCallback ;
2013-01-30 16:50:43 +00:00
2012-10-06 16:36:05 +00:00
} ;
} ) ( window , jQuery ) ;