* VRFS-3519 - 2-player sessions working with custom mix

This commit is contained in:
Seth Call 2015-09-22 15:25:48 -05:00
parent 1733c8689d
commit 1dce984247
6 changed files with 310 additions and 227 deletions

View File

@ -72,7 +72,7 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
monitorControls: (controls, mediaSummary) -> monitorControls: (controls, mediaSummary) ->
if mediaSummary.mediaOpen || mediaSummary.jamTrack? if mediaSummary.mediaOpen || mediaSummary.jamTrack?
if mediaSummary.jamTrack? if mediaSummary.jamTrackOpen?
controls.startMonitor(PLAYBACK_MONITOR_MODE.JAMTRACK) controls.startMonitor(PLAYBACK_MONITOR_MODE.JAMTRACK)
else if mediaSummary.backingTrackOpen else if mediaSummary.backingTrackOpen
controls.startMonitor(PLAYBACK_MONITOR_MODE.MEDIA_FILE) controls.startMonitor(PLAYBACK_MONITOR_MODE.MEDIA_FILE)

View File

@ -49,6 +49,7 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
metronome: mixers.metronome metronome: mixers.metronome
recordingName: mixers.recordingName() recordingName: mixers.recordingName()
jamTrackName: mixers.jamTrackName() jamTrackName: mixers.jamTrackName()
jamTrackMixdown: session.jamTrackMixdown()
@setState(media: state, downloadingJamTrack: session.downloadingJamTrack) @setState(media: state, downloadingJamTrack: session.downloadingJamTrack)
@ -76,7 +77,8 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
creatingMixdown: false, creatingMixdown: false,
createMixdownErrors: null, createMixdownErrors: null,
editingMixdownId: null, editingMixdownId: null,
downloadingJamTrack: @props.downloadingJamTrack downloadingJamTrack: @props.downloadingJamTrack,
jamTrackMixdown: {}
} }
close: () -> close: () ->
@ -95,234 +97,255 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
mediaName = @state.media.recordedTracks[0].recordingName mediaName = @state.media.recordedTracks[0].recordingName
closeLinkText = 'close recording' closeLinkText = 'close recording'
header = `<h3>{mediaType}: {mediaName}</h3>` header = `<h3>{mediaType}: {mediaName}</h3>`
else if @state.jamTrackState.jamTrack? else if @state.media.mediaSummary.jamTrackOpen || @state.jamTrackState.jamTrack?
jamTrack = @state.jamTrackState.jamTrack if @state.media.mediaSummary.isOpener || @state.jamTrackState.jamTrack?
mediaType = "JamTrack" # if you opened the JamTrack, then you get all the good info
mediaName = jamTrack.name jamTrack = @state.jamTrackState.jamTrack
closeLinkText = 'CLOSE JAMTRACK' mediaType = "JamTrack"
mediaName = jamTrack.name
closeLinkText = 'CLOSE JAMTRACK'
selectedMixdown = jamTrack.activeMixdown
selectedMixdown = jamTrack.activeMixdown if selectedMixdown?
jamTrackTypeHeader = 'Custom Mix'
disabled = true
if selectedMixdown.client_state?
switch selectedMixdown.client_state
when 'cant_open'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying_timeout'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'download_fail'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'downloading'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = false
else
customMixName = `<h5>Creating mixdown... <img src="/assets/shared/spinner.gif" /></h5>`
if selectedMixdown?
jamTrackTypeHeader = 'Custom Mix'
disabled = true
if selectedMixdown.client_state?
switch selectedMixdown.client_state
when 'cant_open'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying_timeout'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'download_fail'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'downloading'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = false
else else
customMixName = `<h5>Creating mixdown... <img src="/assets/shared/spinner.gif" /></h5>` if SessionStore.downloadingJamTrack
downloader = `<img src="/assets/shared/spinner.gif" />`
else jamTrackTypeHeader = `<span>Full JamTrack {downloader}</span>`
if SessionStore.downloadingJamTrack
downloader = `<img src="/assets/shared/spinner.gif" />`
jamTrackTypeHeader = `<span>Full JamTrack {downloader}</span>` header = `
<div className="header">
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
header = ` myMixes = null
<div className="header"> if @state.showMyMixes
<h3>{mediaType}: {mediaName}</h3> myMixdowns = []
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
myMixes = null boundPlayClick = this.jamTrackPlay.bind(this, jamTrack);
if @state.showMyMixes
myMixdowns = []
boundPlayClick = this.jamTrackPlay.bind(this, jamTrack); active = jamTrack.last_mixdown_id == null
active = jamTrack.last_mixdown_id == null
myMixdowns.push `
<div key="full-track" className={classNames({'full-track': true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
Full JamTrack
</div>
<div className="mixdown-actions">
<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>
</div>
</div>`
for mixdown in jamTrack.mixdowns
boundPlayClick = this.mixdownPlay.bind(this, mixdown);
boundEditClick = this.mixdownEdit.bind(this, mixdown);
boundSaveClick = this.mixdownSave.bind(this, mixdown);
boundDeleteClick = this.mixdownDelete.bind(this, mixdown);
boundErrorClick = this.mixdownError.bind(this, mixdown);
boundEditKeydown = this.onEditKeydown.bind(this, mixdown);
mixdown_package = mixdown.myPackage
active = mixdown.id == jamTrack.last_mixdown_id
editing = mixdown.id == @state.editingMixdownId
# if there is a package, check it's state; otherwise let the user enqueue it
if mixdown_package
switch mixdown_package.signing_state
when 'QUIET_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'QUIET'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNING'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'SIGNING_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNED'
action = `<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>`
when 'ERROR'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
else
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
if editing
mixdownName = `<input className="edit-name" type="text" defaultValue={mixdown.name} onKeyDown={boundEditKeydown} />`
editIcon = `<img src="/assets/content/icon-save@2X.png" className="mixdown-edit" onClick={boundSaveClick}/>`
else
mixdownName = mixdown.name
editIcon = `<img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>`
myMixdowns.push ` myMixdowns.push `
<div key={mixdown.id} className={classNames({'mixdown-display': true, 'active' : active})}> <div key="full-track" className={classNames({'full-track': true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name"> <div className="mixdown-name">
{mixdownName} Full JamTrack
</div> </div>
<div className="mixdown-actions"> <div className="mixdown-actions">
{action} <img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>
</div>
</div>`
{editIcon} for mixdown in jamTrack.mixdowns
boundPlayClick = this.mixdownPlay.bind(this, mixdown);
boundEditClick = this.mixdownEdit.bind(this, mixdown);
boundSaveClick = this.mixdownSave.bind(this, mixdown);
boundDeleteClick = this.mixdownDelete.bind(this, mixdown);
boundErrorClick = this.mixdownError.bind(this, mixdown);
boundEditKeydown = this.onEditKeydown.bind(this, mixdown);
<img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} /> mixdown_package = mixdown.myPackage
</div>
active = mixdown.id == jamTrack.last_mixdown_id
editing = mixdown.id == @state.editingMixdownId
# if there is a package, check it's state; otherwise let the user enqueue it
if mixdown_package
switch mixdown_package.signing_state
when 'QUIET_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'QUIET'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNING'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'SIGNING_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNED'
action = `<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>`
when 'ERROR'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
else
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
if editing
mixdownName = `<input className="edit-name" type="text" defaultValue={mixdown.name} onKeyDown={boundEditKeydown} />`
editIcon = `<img src="/assets/content/icon-save@2X.png" className="mixdown-edit" onClick={boundSaveClick}/>`
else
mixdownName = mixdown.name
editIcon = `<img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>`
myMixdowns.push `
<div key={mixdown.id} className={classNames({'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
{mixdownName}
</div>
<div className="mixdown-actions">
{action}
{editIcon}
<img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} />
</div>
</div>`
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
mixControls = null
if @state.showCustomMixes
nameClassData = {field: true}
if @state.createMixdownErrors?
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings', jam_track: 'JamTrack'})
createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown})
mixControls = `
<div key="create-mix" className="create-mix">
<p>Use the JamTrack controls on the session screen to set levels, mute/unmute, or pan any of the parts of the JamTrack as you like. You can also use the controls below to adjust the tempo or pitch of the JamTrack. Then give your custom mix a name, and click the Create Mix button. Please note that changing the tempo or pitch of the JamTrack may take a long time, and won't be ready right away.</p>
<div className="field">
<label>Change Tempo:</label>
<select name="mix-speed">
<option value="">No change</option>
<option value="separator-1">------------</option>
<option value="-5">Slower by 5%</option>
<option value="-10">Slower by 10%</option>
<option value="-15">Slower by 15%</option>
<option value="-20">Slower by 20%</option>
<option value="-25">Slower by 25%</option>
<option value="-30">Slower by 30%</option>
<option value="-35">Slower by 35%</option>
<option value="-40">Slower by 40%</option>
<option value="-45">Slower by 45%</option>
<option value="-50">Slower by 50%</option>
<option value="-60">Slower by 60%</option>
<option value="-70">Slower by 70%</option>
<option value="-80">Slower by 80%</option>
<option value="separator-2">------------</option>
<option value="5">Faster by 5%</option>
<option value="10">Faster by 10%</option>
<option value="15">Faster by 15%</option>
<option value="20">Faster by 20%</option>
<option value="30">Faster by 30%</option>
<option value="40">Faster by 40%</option>
<option value="50">Faster by 50%</option>
</select>
</div>
<div className="field">
<label>Change Pitch:</label>
<select name="mix-pitch">
<option value="">No change</option>
<option value="separator-1">---------------</option>
<option value="-1">Down 1 Semitone</option>
<option value="-2">Down 2 Semitones</option>
<option value="-3">Down 3 Semitones</option>
<option value="-4">Down 4 Semitones</option>
<option value="-5">Down 5 Semitones</option>
<option value="-6">Down 6 Semitones</option>
<option value="-7">Down 7 Semitones</option>
<option value="-8">Down 8 Semitones</option>
<option value="-9">Down 9 Semitones</option>
<option value="-10">Down 10 Semitones</option>
<option value="-11">Down 11 Semitones</option>
<option value="-12">Down 12 Semitones</option>
<option value="separator-2">---------------</option>
<option value="1">Up 1 Semitone</option>
<option value="2">Up 2 Semitones</option>
<option value="3">Up 3 Semitones</option>
<option value="4">Up 4 Semitones</option>
<option value="5">Up 5 Semitones</option>
<option value="6">Up 6 Semitones</option>
<option value="7">Up 7 Semitones</option>
<option value="8">Up 8 Semitones</option>
<option value="9">Up 9 Semitones</option>
<option value="10">Up 10 Semitones</option>
<option value="11">Up 11 Semitones</option>
<option value="12">Up 12 Semitones</option>
</select>
</div>
<div className={classNames(nameClassData)}>
<label>Mix Name:</label>
<input type="text" name="mix-name"/>
</div>
<div className="field">
<a className={createMixClasses} onClick={this.createMix}>CREATE MIX</a>
{errorHtml}
</div>
<div className="clearall"/>
</div>`
if @state.showMyMixes
showMyMixesText = `<a onClick={this.toggleMyMixes}>hide my mixes <div className="details-arrow arrow-up" /></a>`
else
showMyMixesText = `<a onClick={this.toggleMyMixes}>show my mixes <div className="details-arrow arrow-down" /></a>`
if @state.showCustomMixes
showMixControlsText = `<a onClick={this.toggleCustomMixes}>hide mix controls <div className="details-arrow arrow-up" /></a>`
else
showMixControlsText = `<a onClick={this.toggleCustomMixes}>show mix controls <div className="details-arrow arrow-down" /></a>`
extraControls = `
<div className="extra-controls">
<h4>My Mixes {showMyMixesText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{myMixes}
</ReactCSSTransitionGroup>
<h4 className="custom-mix-header">Create Custom Mix {showMixControlsText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{mixControls}
</ReactCSSTransitionGroup>
</div>`
else
mediaType = "JamTrack"
mediaName = @state.media.jamTrackName
closeLinkText = 'CLOSE JAMTRACK'
# implies we have a mixdown
if @state.media.jamTrackMixdown.id?
jamTrackTypeHeader = 'Custom Mix'
else
jamTrackTypeHeader = 'Full JamTrack'
header = `
<div className="header">
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>` </div>`
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
mixControls = null
if @state.showCustomMixes
nameClassData = {field: true}
if @state.createMixdownErrors?
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings', jam_track: 'JamTrack'})
createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown})
mixControls = `
<div key="create-mix" className="create-mix">
<p>Use the JamTrack controls on the session screen to set levels, mute/unmute, or pan any of the parts of the JamTrack as you like. You can also use the controls below to adjust the tempo or pitch of the JamTrack. Then give your custom mix a name, and click the Create Mix button. Please note that changing the tempo or pitch of the JamTrack may take a long time, and won't be ready right away.</p>
<div className="field">
<label>Change Tempo:</label>
<select name="mix-speed">
<option value="">No change</option>
<option value="separator-1">------------</option>
<option value="-5">Slower by 5%</option>
<option value="-10">Slower by 10%</option>
<option value="-15">Slower by 15%</option>
<option value="-20">Slower by 20%</option>
<option value="-25">Slower by 25%</option>
<option value="-30">Slower by 30%</option>
<option value="-35">Slower by 35%</option>
<option value="-40">Slower by 40%</option>
<option value="-45">Slower by 45%</option>
<option value="-50">Slower by 50%</option>
<option value="-60">Slower by 60%</option>
<option value="-70">Slower by 70%</option>
<option value="-80">Slower by 80%</option>
<option value="separator-2">------------</option>
<option value="5">Faster by 5%</option>
<option value="10">Faster by 10%</option>
<option value="15">Faster by 15%</option>
<option value="20">Faster by 20%</option>
<option value="30">Faster by 30%</option>
<option value="40">Faster by 40%</option>
<option value="50">Faster by 50%</option>
</select>
</div>
<div className="field">
<label>Change Pitch:</label>
<select name="mix-pitch">
<option value="">No change</option>
<option value="separator-1">---------------</option>
<option value="-1">Down 1 Semitone</option>
<option value="-2">Down 2 Semitones</option>
<option value="-3">Down 3 Semitones</option>
<option value="-4">Down 4 Semitones</option>
<option value="-5">Down 5 Semitones</option>
<option value="-6">Down 6 Semitones</option>
<option value="-7">Down 7 Semitones</option>
<option value="-8">Down 8 Semitones</option>
<option value="-9">Down 9 Semitones</option>
<option value="-10">Down 10 Semitones</option>
<option value="-11">Down 11 Semitones</option>
<option value="-12">Down 12 Semitones</option>
<option value="separator-2">---------------</option>
<option value="1">Up 1 Semitone</option>
<option value="2">Up 2 Semitones</option>
<option value="3">Up 3 Semitones</option>
<option value="4">Up 4 Semitones</option>
<option value="5">Up 5 Semitones</option>
<option value="6">Up 6 Semitones</option>
<option value="7">Up 7 Semitones</option>
<option value="8">Up 8 Semitones</option>
<option value="9">Up 9 Semitones</option>
<option value="10">Up 10 Semitones</option>
<option value="11">Up 11 Semitones</option>
<option value="12">Up 12 Semitones</option>
</select>
</div>
<div className={classNames(nameClassData)}>
<label>Mix Name:</label>
<input type="text" name="mix-name"/>
</div>
<div className="field">
<a className={createMixClasses} onClick={this.createMix}>CREATE MIX</a>
{errorHtml}
</div>
<div className="clearall"/>
</div>`
if @state.showMyMixes
showMyMixesText = `<a onClick={this.toggleMyMixes}>hide my mixes <div className="details-arrow arrow-up" /></a>`
else
showMyMixesText = `<a onClick={this.toggleMyMixes}>show my mixes <div className="details-arrow arrow-down" /></a>`
if @state.showCustomMixes
showMixControlsText = `<a onClick={this.toggleCustomMixes}>hide mix controls <div className="details-arrow arrow-up" /></a>`
else
showMixControlsText = `<a onClick={this.toggleCustomMixes}>show mix controls <div className="details-arrow arrow-down" /></a>`
extraControls = `
<div className="extra-controls">
<h4>My Mixes {showMyMixesText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{myMixes}
</ReactCSSTransitionGroup>
<h4 className="custom-mix-header">Create Custom Mix {showMixControlsText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{mixControls}
</ReactCSSTransitionGroup>
</div>`
else if @state.media.mediaSummary.backingTrackOpen else if @state.media.mediaSummary.backingTrackOpen
mediaType = "Audio File" mediaType = "Audio File"
@ -444,14 +467,14 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
time = enqueued.queue_time time = enqueued.queue_time
if time == 0 if time == 0
alert("It will take approximately 1 minute to create your custom mix.") alert("Your custom mix will take about 1 minute to be created.")
else else
guess = Math.ceil(time / 60.0) guess = Math.ceil(time / 60.0)
if guess == 1 if guess == 1
msg = '1 minute' msg = '1 minute'
else else
msg = "#{guess} minutes" msg = "#{guess} minutes"
alert("Your custom mix will take approximately #{msg} to be created.") alert("Your custom mix will take about #{msg} to be created.")
createMix: (e) -> createMix: (e) ->

View File

@ -69,6 +69,7 @@ MIX_MODES = context.JK.MIX_MODES;
backingTracks = @session.backingTracks() backingTracks = @session.backingTracks()
recordedJamTracks = @session.recordedJamTracks() recordedJamTracks = @session.recordedJamTracks()
jamTracks = @session.jamTracks() jamTracks = @session.jamTracks()
jamTrackMixdown = @session.jamTrackMixdown()
### ###
with mixer info, we use these to decide what kind of tracks are open in the backend with mixer info, we use these to decide what kind of tracks are open in the backend
@ -92,6 +93,7 @@ MIX_MODES = context.JK.MIX_MODES;
@metronomeTrackMixers = [] @metronomeTrackMixers = []
@adhocTrackMixers = [] @adhocTrackMixers = []
groupByType = (mixers, isLocalMixer) => groupByType = (mixers, isLocalMixer) =>
for mixer in mixers for mixer in mixers
mediaType = mixer.media_type mediaType = mixer.media_type
@ -106,7 +108,10 @@ MIX_MODES = context.JK.MIX_MODES;
isJamTrack = false; isJamTrack = false;
if jamTracks if mixer.id == jamTrackMixdown.id
isJamTrack = true;
if !isJamTrack && jamTracks
# check if the ID matches that of an open jam track # check if the ID matches that of an open jam track
for jamTrack in jamTracks for jamTrack in jamTracks
if mixer.id == jamTrack.id if mixer.id == jamTrack.id
@ -186,6 +191,8 @@ MIX_MODES = context.JK.MIX_MODES;
backingTrackOpen: @backingTracks.length > 0 backingTrackOpen: @backingTracks.length > 0
metronomeOpen: @session.isMetronomeOpen() metronomeOpen: @session.isMetronomeOpen()
# figure out if any media is open # figure out if any media is open
mediaOpenSummary = false mediaOpenSummary = false
for mediaType, mediaOpen of @mediaSummary for mediaType, mediaOpen of @mediaSummary

View File

@ -22,6 +22,8 @@ if jam_instance == 0
exit 1 exit 1
end end
#Resque.redis = "localhost:6380"
# now bring in the Jam code # now bring in the Jam code
require 'jam_websockets' require 'jam_websockets'

View File

@ -147,6 +147,7 @@ module JamWebsockets
# subscribe for any messages to users # subscribe for any messages to users
@user_topic.subscribe(:ack => false) do |headers, msg| @user_topic.subscribe(:ack => false) do |headers, msg|
time_it('user_topic') {
begin begin
routing_key = headers.routing_key routing_key = headers.routing_key
user_id = routing_key["user.".length..-1] user_id = routing_key["user.".length..-1]
@ -175,6 +176,7 @@ module JamWebsockets
@log.error "unhandled error in messaging to client" @log.error "unhandled error in messaging to client"
@log.error e @log.error e
end end
}
end end
MQRouter.user_exchange = @users_exchange MQRouter.user_exchange = @users_exchange
@ -189,6 +191,7 @@ module JamWebsockets
# subscribe for any p2p messages to a client # subscribe for any p2p messages to a client
@client_topic.subscribe(:ack => false) do |headers, msg| @client_topic.subscribe(:ack => false) do |headers, msg|
time_it('p2p_topic') {
begin begin
routing_key = headers.routing_key routing_key = headers.routing_key
client_id = routing_key["client.".length..-1] client_id = routing_key["client.".length..-1]
@ -240,6 +243,7 @@ module JamWebsockets
@log.error "unhandled error in messaging to client" @log.error "unhandled error in messaging to client"
@log.error e @log.error e
end end
}
end end
MQRouter.client_exchange = @clients_exchange MQRouter.client_exchange = @clients_exchange
@ -252,6 +256,7 @@ module JamWebsockets
# subscribe for any p2p messages to a client # subscribe for any p2p messages to a client
@subscription_topic.subscribe(:ack => false) do |headers, msg| @subscription_topic.subscribe(:ack => false) do |headers, msg|
time_it('subscribe_topic') {
begin begin
routing_key = headers.routing_key routing_key = headers.routing_key
type_and_id = routing_key["subscription.".length..-1] type_and_id = routing_key["subscription.".length..-1]
@ -276,6 +281,7 @@ module JamWebsockets
@log.error "unhandled error in messaging to client for mount" @log.error "unhandled error in messaging to client for mount"
@log.error e @log.error e
end end
}
end end
MQRouter.subscription_exchange = @subscriptions_exchange MQRouter.subscription_exchange = @subscriptions_exchange
@ -397,8 +403,10 @@ module JamWebsockets
} }
client.onclose { client.onclose {
@log.debug "connection closed. marking stale: #{client.context}" time_it('ws_close') {
cleanup_client(client) @log.debug "connection closed. marking stale: #{client.context}"
cleanup_client(client)
}
} }
client.onerror { |error| client.onerror { |error|
@ -478,6 +486,7 @@ module JamWebsockets
end end
def route(client_msg, client) def route(client_msg, client)
time_it('route') {
message_type = @message_factory.get_message_type(client_msg) message_type = @message_factory.get_message_type(client_msg)
if message_type.nil? if message_type.nil?
Diagnostic.unknown_message_type(client.user_id, client_msg) Diagnostic.unknown_message_type(client.user_id, client_msg)
@ -516,7 +525,7 @@ module JamWebsockets
else else
raise SessionError, "client_msg.route_to is unknown type: #{client_msg.route_to}" raise SessionError, "client_msg.route_to is unknown type: #{client_msg.route_to}"
end end
}
end end
def handle_server_directed(client_msg, client) def handle_server_directed(client_msg, client)
@ -529,11 +538,11 @@ module JamWebsockets
elsif client_msg.type == ClientMessage::Type::HEARTBEAT elsif client_msg.type == ClientMessage::Type::HEARTBEAT
sane_logging { handle_heartbeat(client_msg.heartbeat, client_msg.message_id, client) } sane_logging { handle_heartbeat(client_msg.heartbeat, client_msg.message_id, client) }
elsif client_msg.type == ClientMessage::Type::SUBSCRIBE_BULK elsif client_msg.type == ClientMessage::Type::SUBSCRIBE_BULK
sane_logging { handle_bulk_subscribe(client_msg.subscribe_bulk, client) } time_it('subscribe_bulk') { sane_logging { handle_bulk_subscribe(client_msg.subscribe_bulk, client) } }
elsif client_msg.type == ClientMessage::Type::SUBSCRIBE elsif client_msg.type == ClientMessage::Type::SUBSCRIBE
sane_logging { handle_subscribe(client_msg.subscribe, client) } time_it('subscribe') { sane_logging { handle_subscribe(client_msg.subscribe, client) } }
elsif client_msg.type == ClientMessage::Type::UNSUBSCRIBE elsif client_msg.type == ClientMessage::Type::UNSUBSCRIBE
sane_logging { handle_unsubscribe(client_msg.unsubscribe, client) } time_it('unsubscribe') { sane_logging { handle_unsubscribe(client_msg.unsubscribe, client) } }
else else
raise SessionError, "unknown message type '#{client_msg.type}' for #{client_msg.route_to}-directed message" raise SessionError, "unknown message type '#{client_msg.type}' for #{client_msg.route_to}-directed message"
end end
@ -1198,6 +1207,7 @@ module JamWebsockets
# removes all resources associated with a client # removes all resources associated with a client
def cleanup_client(client) def cleanup_client(client)
time_it('cleanup_client') {
client.close client.close
# unregister any subscriptions # unregister any subscriptions
@ -1225,6 +1235,7 @@ module JamWebsockets
end end
end end
end end
}
end end
def stats_logged_in def stats_logged_in
@ -1245,6 +1256,16 @@ module JamWebsockets
private private
def time_it(cat, &blk)
start = Time.now
blk.call
time = Time.now - start
@log.warn("LONG TIME: #{cat}: #{time}") if time > 1
end
def sane_logging(&blk) def sane_logging(&blk)
# used around repeated transactions that cause too much ActiveRecord::Base logging # used around repeated transactions that cause too much ActiveRecord::Base logging
begin begin

View File

@ -10,6 +10,8 @@ module JamWebsockets
@count=0 @count=0
@router = Router.new @router = Router.new
@ar_base_logger = ::Logging::Repository.instance[ActiveRecord::Base] @ar_base_logger = ::Logging::Repository.instance[ActiveRecord::Base]
@last_conn_check = nil
end end
def run(options={}) def run(options={})
@ -26,6 +28,7 @@ module JamWebsockets
rabbitmq_port = options[:rabbitmq_port].to_i rabbitmq_port = options[:rabbitmq_port].to_i
allow_dynamic_registration = options[:allow_dynamic_registration].nil? ? true : options[:allow_dynamic_registration] allow_dynamic_registration = options[:allow_dynamic_registration].nil? ? true : options[:allow_dynamic_registration]
Stats::init(options) Stats::init(options)
calling_thread = options[:calling_thread] calling_thread = options[:calling_thread]
@ -61,6 +64,18 @@ module JamWebsockets
EventMachine::stop_event_loop EventMachine::stop_event_loop
end end
def check_for_em_drift(timer)
# if our timer check is a full second off, say what's up
if Time.now - @last_conn_check > timer + 1
@log.error("significant drift! Should be 2 seconds. Instead was: #{Time.now - @last_conn_check}")
end
@last_conn_check = Time.now
end
def start_websocket_listener(listen_ip, port, trust_port, trust_check, emwebsocket_debug) def start_websocket_listener(listen_ip, port, trust_port, trust_check, emwebsocket_debug)
EventMachine::WebSocket.run(:host => listen_ip, :port => port, :debug => emwebsocket_debug) do |ws| EventMachine::WebSocket.run(:host => listen_ip, :port => port, :debug => emwebsocket_debug) do |ws|
#@log.info "new client #{ws}" #@log.info "new client #{ws}"
@ -84,8 +99,11 @@ module JamWebsockets
# one cleanup on startup # one cleanup on startup
@router.periodical_check_connections @router.periodical_check_connections
EventMachine::PeriodicTimer.new(2) do @last_conn_check = Time.now
safety_net { sane_logging { @router.periodical_check_connections } } timer = 2
EventMachine::PeriodicTimer.new(timer) do
check_for_em_drift(timer)
time_it('conn_expire') { safety_net { sane_logging { @router.periodical_check_connections } } }
end end
end end
@ -94,7 +112,7 @@ module JamWebsockets
@router.periodical_check_clients @router.periodical_check_clients
EventMachine::PeriodicTimer.new(30) do EventMachine::PeriodicTimer.new(30) do
safety_net { sane_logging { @router.periodical_check_clients } } time_it('client_expire') { safety_net { sane_logging { @router.periodical_check_clients } } }
end end
end end
@ -103,13 +121,13 @@ module JamWebsockets
@router.periodical_flag_connections @router.periodical_flag_connections
EventMachine::PeriodicTimer.new(2) do EventMachine::PeriodicTimer.new(2) do
safety_net { sane_logging { @router.periodical_flag_connections } } time_it('conn_flagger') { safety_net { sane_logging { @router.periodical_flag_connections } } }
end end
end end
def start_stats_dump def start_stats_dump
EventMachine::PeriodicTimer.new(60) do EventMachine::PeriodicTimer.new(60) do
safety_net { @router.periodical_stats_dump } time_it('stats_dump') { safety_net { @router.periodical_stats_dump } }
end end
end end
@ -126,6 +144,18 @@ module JamWebsockets
@log.error("unhandled exception in EM Timer #{e}") @log.error("unhandled exception in EM Timer #{e}")
end end
end end
def time_it(cat, &blk)
start = Time.now
blk.call
time = Time.now - start
@log.warn("LONG TIME #{cat}: #{time}") if time > 1
end
def sane_logging(&blk) def sane_logging(&blk)
# used around repeated transactions that cause too much ActiveRecord::Base logging # used around repeated transactions that cause too much ActiveRecord::Base logging
# example is handling heartbeats # example is handling heartbeats