192 lines
5.9 KiB
CoffeeScript
192 lines
5.9 KiB
CoffeeScript
$ = jQuery
|
|
context = window
|
|
logger = context.JK.logger
|
|
rest = context.JK.Rest()
|
|
EVENTS = context.JK.EVENTS
|
|
MIX_MODES = context.JK.MIX_MODES
|
|
|
|
SessionActions = @SessionActions
|
|
MixerActions = @MixerActions
|
|
|
|
SessionStatThresholds = gon.session_stat_thresholds
|
|
NetworkThresholds = SessionStatThresholds.network
|
|
SystemThresholds = SessionStatThresholds.system
|
|
AudioThresholds = SessionStatThresholds.audio
|
|
AggregateThresholds = SessionStatThresholds.aggregate
|
|
|
|
@SessionStatsStore = Reflux.createStore(
|
|
{
|
|
listenables: @SessionStatsActions
|
|
rawStats: null,
|
|
parentStats: null
|
|
clientsWithAudio: null
|
|
|
|
init: ->
|
|
# Register with the app store to get @app
|
|
this.listenTo(context.AppStore, this.onAppInit)
|
|
|
|
onAppInit: (@app) ->
|
|
|
|
onPushStats: (stats, parentStats) ->
|
|
@rawStats = stats
|
|
@parentStats = parentStats
|
|
@changed()
|
|
|
|
classify: (holder, field, threshold) ->
|
|
value = holder[field]
|
|
fieldLevel = field + '_level'
|
|
fieldThreshold = threshold[field]
|
|
|
|
if value? && fieldThreshold?
|
|
|
|
if fieldThreshold.inverse
|
|
if fieldThreshold.zero_is_good
|
|
holder[fieldLevel] = 'good'
|
|
else if value <= fieldThreshold.poor
|
|
holder[fieldLevel] = 'poor'
|
|
@participantClassification = 3
|
|
else if value <= fieldThreshold.warn
|
|
holder[fieldLevel] = 'warn'
|
|
@participantClassification = 2 if @participantClassification == 1
|
|
else
|
|
holder[fieldLevel] = 'good'
|
|
else if fieldThreshold.eql
|
|
if value == fieldThreshold.poor
|
|
holder[fieldLevel] = 'poor'
|
|
@participantClassification = 3
|
|
else if value == fieldThreshold.warn
|
|
holder[fieldLevel] = 'warn'
|
|
@participantClassification = 2 if @participantClassification == 1
|
|
else
|
|
holder[fieldLevel] = 'good'
|
|
else
|
|
if value >= fieldThreshold.poor
|
|
holder[fieldLevel] = 'poor'
|
|
@participantClassification = 3
|
|
else if value >= fieldThreshold.warn
|
|
holder[fieldLevel] = 'warn'
|
|
@participantClassification = 2 if @participantClassification == 1
|
|
else
|
|
holder[fieldLevel] = 'good'
|
|
|
|
classifyStats: (statBag) ->
|
|
container = {}
|
|
self = null
|
|
for participant in statBag
|
|
if participant.id == @app.clientId
|
|
self = participant
|
|
break
|
|
|
|
for participant in statBag
|
|
|
|
aggregate = {}
|
|
|
|
@participantClassification = 1 # 1=good, 2=warn, 3=poor
|
|
|
|
total_latency = 0
|
|
|
|
if participant.cpu?
|
|
system = {cpu: participant.cpu}
|
|
|
|
@classify(system, 'cpu', SystemThresholds)
|
|
|
|
participant.system = system
|
|
|
|
network = participant.network
|
|
|
|
if network?
|
|
if network.audio_bitrate_rx > 0 && network.audio_bitrate_tx > 0
|
|
@clientsWithAudio[participant.id] = true
|
|
|
|
@classify(network, 'audiojq_median', NetworkThresholds)
|
|
@classify(network, 'jitter_var', NetworkThresholds)
|
|
@classify(network, 'audio_bitrate_rx', NetworkThresholds)
|
|
@classify(network, 'audio_bitrate_tx', NetworkThresholds)
|
|
@classify(network, 'video_rtpbw_tx', NetworkThresholds)
|
|
@classify(network, 'video_rtpbw_rx', NetworkThresholds)
|
|
@classify(network, 'ping', NetworkThresholds)
|
|
@classify(network, 'pkt_loss', NetworkThresholds)
|
|
@classify(network, 'wifi', NetworkThresholds)
|
|
|
|
total_latency += network.ping / 2
|
|
total_latency += network.audiojq_median * 2.5
|
|
aggregate.one_way = network.ping / 2
|
|
aggregate.jq = network.audiojq_median * 2.5
|
|
|
|
if network.using_ars_path == 0
|
|
network.ars_vs_p2p = 'P2P'
|
|
if network.preferred_path == 'p2p'
|
|
network.ars_vs_p2p_level = 'good'
|
|
else
|
|
network.ars_vs_p2p_level = 'warn'
|
|
else
|
|
network.ars_vs_p2p = 'ARS'
|
|
if network.preferred_path == 'p2p'
|
|
network.ars_vs_p2p_level = 'warn'
|
|
else
|
|
network.ars_vs_p2p_level = 'good'
|
|
console.log("NETWORK!", network)
|
|
else
|
|
total_latency = null
|
|
|
|
audio = participant.audio
|
|
|
|
if audio?
|
|
if audio.cpu?
|
|
system = {cpu: audio.cpu}
|
|
@classify(system, 'cpu', SystemThresholds)
|
|
participant.system = system
|
|
|
|
if audio.in_latency? and audio.out_latency?
|
|
audio.latency = audio.in_latency + audio.out_latency
|
|
|
|
|
|
@classify(audio, 'framesize', AudioThresholds)
|
|
@classify(audio, 'latency', AudioThresholds)
|
|
@classify(audio, 'input_jitter', AudioThresholds)
|
|
@classify(audio, 'output_jitter', AudioThresholds)
|
|
@classify(audio, 'audio_in_type', AudioThresholds)
|
|
|
|
if total_latency != null
|
|
total_latency += audio.out_latency
|
|
total_latency += self.audio.in_latency
|
|
aggregate.their_out_latency = audio.out_latency
|
|
aggregate.your_in_latency = self.audio.in_latency
|
|
else
|
|
total_latency = null
|
|
|
|
if participant.id != @app.clientId
|
|
|
|
aggregate.latency = total_latency
|
|
|
|
@classify(aggregate, 'latency', AggregateThresholds)
|
|
|
|
participant.aggregate = aggregate
|
|
|
|
switch @participantClassification
|
|
when 1 then participant.classification = 'good'
|
|
when 2 then participant.classification = 'warn'
|
|
when 3 then participant.classification = 'poor'
|
|
else
|
|
participant.classification = 'unknown'
|
|
|
|
container[participant.id] = participant
|
|
|
|
return container
|
|
|
|
changed: () ->
|
|
@clientsWithAudio = {}
|
|
@stats = {}
|
|
|
|
@stats = @classifyStats(@rawStats)
|
|
if @parentStats
|
|
@stats.parent = @classifyStats(@parentStats)
|
|
else
|
|
@stats.parent = null
|
|
|
|
MixerActions.clientsWithAudio(@clientsWithAudio)
|
|
|
|
# see if we can reset noAudio
|
|
@trigger(@stats)
|
|
}
|
|
) |