2015-12-09 17:32:24 +00:00
context = window
ChannelGroupIds = context . JK . ChannelGroupIds
MixerActions = @ MixerActions
ptrCount = 0
2015-12-14 21:05:23 +00:00
window . aggregate_latency_calc = (stats) -> ` < span > Total Latency is calculated as : < br / > their gear output delay ( { Math . round ( stats . aggregate . their_out_latency ) } ms ) < br > < span className = " plusone " > + < /span><br/ > your gear input delay ( { Math . round ( stats . aggregate . your_in_latency ) } ms ) < br / > < span className = " plusone " > + < / span > < /br>internet delay ({Math.round(stats.aggregate.one_way)}ms)<br/ > < span className = " plusone " > + < /span><br/ > delay caused by jitter queue ( { Math . round ( stats . aggregate . jq ) } ms ) . < / span > `
2015-12-10 11:21:59 +00:00
StatsInfo = {
2015-12-14 21:05:23 +00:00
2015-12-12 03:14:00 +00:00
aggregate: {
latency: {
2015-12-14 21:05:23 +00:00
good: (user, stats) -> ` < span > { user . possessive } one - way , total latency from him to you is very good . < br / > < br / > { window . aggregate_latency_calc ( stats ) } < / span > ` ,
warn: (user, stats) -> ` < span > { user . possessive } one - way , total latency from him to you is typical . < br / > < br / > { window . aggregate_latency_calc ( stats ) } < / span > ` ,
poor: (user, stats) -> ` < span > { user . possessive } one - way , total latency from him to you is poor . < br / > < br / > { window . aggregate_latency_calc ( stats ) } < / span > `
2015-12-12 03:14:00 +00:00
}
} ,
2015-12-10 11:21:59 +00:00
system: {
cpu: {
2015-12-11 02:52:13 +00:00
good: (user, stats) -> " #{ user . possessive } computer processor is not overworked by JamKazam or the your system. " ,
warn: (user, stats) -> " #{ user . possessive } computer processor is being heavily used. There is little spare capacity, and this means your processor may not be able to handle all of it ' s tasks, causing audio quality, latency, and other issues. " ,
poor: (user, stats) -> " #{ user . possessive } computer processor is being very heavily used. There is little spare capacity, and this means your processor may not be able to handle all of it ' s tasks, causing audio quality, latency, and other issues. "
}
} ,
network: {
wifi: {
2015-12-14 21:05:23 +00:00
good: (user, stats) -> " #{ user . name } is using a wired connection. " ,
2015-12-11 02:52:13 +00:00
warn: (user, stats) -> " #{ user . name } is using Wi-Fi, which will create audio quality issues and additional latency. " ,
poor: (user, stats) -> " #{ user . name } is using Wi-Fi, which will create audio quality issues and additional latency. " ,
2015-12-10 11:21:59 +00:00
} ,
2015-12-14 21:05:23 +00:00
audio_bitrate_rx: {
2015-12-11 02:52:13 +00:00
good: (user, stats) -> " #{ user . name } has enough bandwidth to send you a high quality audio stream. " ,
2015-12-14 21:05:23 +00:00
warn: (user, stats) -> " #{ user . name } has enough bandwidth to send you a degraded, but sufficient, audio stream. " ,
2015-12-11 02:52:13 +00:00
poor: (user, stats) -> " #{ user . name } has not enough bandwidth to send you a decent quality audio stream. " ,
} ,
2015-12-14 21:05:23 +00:00
audio_bitrate_tx: {
good: (user, stats) -> " You have enough bandwidth to send you a high quality audio stream. " ,
warn: (user, stats) -> " You have enough bandwidth to send you a degraded, but sufficient, audio stream. " ,
poor: (user, stats) -> " You have not enough bandwidth to send you a decent quality audio stream. " ,
} ,
video_rtpbw_rx: {
2021-01-17 01:37:34 +00:00
good: (user, stats) -> " #{ user . name } has enough bandwidth to send you a high quality video stream. " ,
warn: (user, stats) -> " #{ user . name } has enough bandwidth to send you a degraded, but sufficient, video stream. " ,
poor: (user, stats) -> " #{ user . name } has not enough bandwidth to send you a decent quality video stream. " ,
2015-12-14 21:21:14 +00:00
} ,
video_rtpbw_tx: {
2015-12-14 21:05:23 +00:00
good: (user, stats) -> " You have enough bandwidth to send you a high quality video stream. " ,
warn: (user, stats) -> " You have enough bandwidth to send you a degraded, but sufficient, video stream. " ,
poor: (user, stats) -> " You have not enough bandwidth to send you a decent quality video stream. " ,
} ,
2021-02-08 04:08:51 +00:00
tx_ars_vs_p2p: {
good: (user, stats) -> " Your send network path is also the lowest latency path available " ,
warn: (user, stats) -> " Your send network path is not the lowest latency path available " ,
poor: (user, stats) -> " Your send network path is not the lowest latency path available " ,
} ,
rx_ars_vs_p2p: {
good: (user, stats) -> " Your receive network path is also the lowest latency path available " ,
warn: (user, stats) -> " Your receive network path is not the lowest latency path available " ,
poor: (user, stats) -> " Your receive network path is not the lowest latency path available " ,
2021-01-17 01:37:34 +00:00
} ,
2015-12-11 02:52:13 +00:00
ping: {
good: (user, stats) -> " The internet connection between you and #{ user . name } has very low latency. " ,
warn: (user, stats) -> " The internet connection between you and #{ user . name } has average latency, which may affect staying in sync. " ,
poor: (user, stats) -> " The internet connection between you and #{ user . name } has high latency, making it very difficult to stay in sync. " ,
2015-12-10 11:21:59 +00:00
} ,
2015-12-11 02:52:13 +00:00
pkt_loss: {
good: (user, stats) -> " The internet connection between you and #{ user . name } loses a small % of packets. It should not affect your audio quality. " ,
warn: (user, stats) -> " The internet connection between you and #{ user . name } loses a significant % of packets. This may result in periodical audio artifacts. " ,
poor: (user, stats) -> " The internet connection between you and #{ user . name } loses a high % of packets. This will result in frequent audio artifacts. " ,
} ,
audiojq_median: {
2015-12-14 21:05:23 +00:00
good: (user, stats) -> ` < span > JamKazam has to maintain a only a small buffer of audio to preserve audio quality , resulting in minimal added latency . < br / > < br / > This buffer is adding { ( 2.5 * stats . network . audiojq_median ) . toFixed ( 1 ) } ms of latency . < / span > ` ,
warn: (user, stats) -> ` < span > JamKazam has to maintain a significant buffer of audio to preserve audio quality , resulting in potentially noticeable additional latency . < br / > < br / > This buffer is adding { ( 2.5 * stats . network . audiojq_median ) . toFixed ( 1 ) } ms of latency . < / span > ` ,
poor: (user, stats) -> ` < span > JamKazam has to maintain a large buffer of audio to preserve audio quality , resulting in noticeabley added latency . < br / > < br / > This buffer is adding { ( 2.5 * stats . network . audiojq_median ) . toFixed ( 1 ) } ms of latency . < / span > ` ,
2015-12-11 02:52:13 +00:00
}
} ,
audio: {
framesize: {
good: (user, stats) -> " #{ user . possessive } gear is reading and writing audio data at a very high rate, keeping gear-added latency low. " ,
warn: (user, stats) -> " #{ user . possessive } gear is reading and writing audio at a average rate, causing a few milliseconds extra latency compared to a 2.5 Frame Size. " ,
poor: (user, stats) -> " #{ user . possessive } gear is reading and writing audio at a slow rate, causing a decent amount of latency before the internet is involved. " ,
} ,
latency: {
good: (user, stats) -> " #{ user . possessive } gear has a small amount of latency. " ,
warn: (user, stats) -> " #{ user . possessive } gear has a significant amount of latency. " ,
poor: (user, stats) -> " #{ user . possessive } gear has a large amount of latency, making it difficult to play in time. "
} ,
input_jitter: {
good: (user, stats) -> " #{ user . possessive } gear has a small amount of input jitter, meaning it is keeping good time with JamKazam as it reads in your input signal. " ,
warn: (user, stats) -> " #{ user . possessive } gear has a significant amount of input jitter, meaning it might be periodically adding delay or audio artifacts to your inputs. " ,
poor: (user, stats) -> " #{ user . possessive } gear has a large amount of input jitter, meaning it likely adding delay and audio artifacts to your inputs. " ,
} ,
output_jitter: {
2015-12-11 04:07:56 +00:00
good: (user, stats) -> " #{ user . possessive } gear has a small amount of output jitter, meaning it is keeping good time with your JamKazam as writes out your audio output. " ,
warn: (user, stats) -> " #{ user . possessive } gear has a significant amount of output jitter, meaning it might be periodically adding delay and audio artifacts to your output. " ,
2015-12-11 02:52:13 +00:00
poor: (user, stats) -> " #{ user . possessive } gear has a large amount of output jitter, meaning it likely adding delay and audio artifacts to your output. " ,
2015-12-11 04:07:56 +00:00
} ,
audio_in_type: {
good: (user, stats) -> " #{ user . name } using an ideal driver type for #{ user . possessive . toLowerCase ( ) } gear. " ,
warn: (user, stats) -> " #{ user . name } using a problematic driver type for #{ user . possessive . toLowerCase ( ) } gear. " ,
poor: (user, stats) -> " #{ user . name } using a driver type considered problematic. " ,
2015-12-10 11:21:59 +00:00
}
}
}
2015-12-09 17:32:24 +00:00
@SessionStatsHover = React . createClass ( {
propTypes: {
clientId: React . PropTypes . string
}
mixins: [ Reflux . listenTo ( @ SessionStatsStore , " onStatsChanged " ) ]
2015-12-10 11:21:59 +00:00
hover: (type, field) ->
logger . debug ( " hover! #{ type } #{ field } " )
@ setState ( { hoverType: type , hoverField : field } )
hoverOut: () ->
logger . debug ( " hover out! " )
@ setState ( { hoverType: null , hoverField: null } )
stat: (properties, type, name, field, value) ->
classes = { ' status-icon ' : true }
classifier = properties [ field + ' _level ' ]
classes [ classifier ] = true
2015-12-11 02:52:13 +00:00
` < div className = ' stat ' onMouseOver = { this . hover . bind ( this , type , field ) } > < span className = " title " > - { name } < / span > < div className = { classNames ( classes ) } > < / div > < span className = " stat-value " > { value } < / span > < / div > `
2015-12-10 11:21:59 +00:00
2015-12-09 17:32:24 +00:00
render: () ->
2015-12-10 11:21:59 +00:00
extraInfo = ' Hover over a stat to learn more. '
if @ state . hoverType ?
type = @ state . hoverType
field = @ state . hoverField
2015-12-14 21:05:23 +00:00
extraInfo = ` < span > No extra info for this metric . < / span > `
2015-12-10 11:21:59 +00:00
classifier = @ state . stats ? [ type ] ? [ field + ' _level ' ]
if classifier ?
2015-12-11 02:52:13 +00:00
info = StatsInfo [ type ] ? [ field ] ? [ classifier ] ( @ props . participant . user , @ state . stats )
2015-12-10 11:21:59 +00:00
if info ?
2015-12-14 21:05:23 +00:00
extraInfo = ` < span > { info } < / span > `
2015-12-10 11:21:59 +00:00
computerStats = [ ]
networkStats = [ ]
audioStats = [ ]
2015-12-12 03:14:00 +00:00
aggregateStats = [ ]
2015-12-10 11:21:59 +00:00
2015-12-12 03:14:00 +00:00
aggregate = @ state . stats ? . aggregate
2015-12-10 11:21:59 +00:00
network = @ state . stats ? . network
system = @ state . stats ? . system
audio = @ state . stats ? . audio
2015-12-12 03:14:00 +00:00
aggregateTag = null
2016-10-27 23:24:54 +00:00
if aggregate ? && ! this . props . myTrack
2015-12-12 03:14:00 +00:00
if aggregate . latency
2015-12-14 21:05:23 +00:00
aggregateStats . push ( @ stat ( aggregate , ' aggregate ' , ' Tot Latency ' , ' latency ' , Math . round ( aggregate . latency ) ) )
2015-12-12 03:14:00 +00:00
aggregateTag =
` < div className = " aggregate-stats stats-holder " >
{ aggregateStats }
< / div > `
2015-12-10 11:21:59 +00:00
if system ?
if system . cpu ?
computerStats . push ( @ stat ( system , ' system ' , ' Processor ' , ' cpu ' , Math . round ( system . cpu ) + ' % ' ) )
if audio ?
2015-12-12 03:14:00 +00:00
if audio . latency ?
audioStats . push ( @ stat ( audio , ' audio ' , ' Latency ' , ' latency ' , audio . latency . toFixed ( 1 ) + ' ms ' ) )
if audio . input_jitter ?
2015-12-14 21:05:23 +00:00
audioStats . push ( @ stat ( audio , ' audio ' , ' Input Jitter ' , ' input_jitter ' , audio . input_jitter . toFixed ( 2 ) + ' ms ' ) )
2015-12-12 03:14:00 +00:00
if audio . output_jitter ?
2015-12-14 21:05:23 +00:00
audioStats . push ( @ stat ( audio , ' audio ' , ' Output Jitter ' , ' output_jitter ' , audio . output_jitter . toFixed ( 2 ) + ' ms ' ) )
2015-12-12 03:14:00 +00:00
2015-12-11 04:07:56 +00:00
if audio . audio_in_type ?
2015-12-11 02:52:13 +00:00
audio_type = ' ? '
audio_long = audio . audio_in_type . toLowerCase ( )
if audio_long . indexOf ( ' asio ' ) > - 1
audio_type = ' ASIO '
else if audio_long . indexOf ( ' wdm ' ) > - 1
audio_type = ' WDM '
else if audio_long . indexOf ( ' core ' ) > - 1
2015-12-11 04:07:56 +00:00
audio_type = ' CoreAudio '
2016-10-27 23:24:54 +00:00
else if audio_long . indexOf ( ' alsa ' ) > - 1
audio_type = ' JamBlaster '
2015-12-11 04:07:56 +00:00
audioStats . push ( @ stat ( audio , ' audio ' , ' Gear Driver ' , ' audio_in_type ' , audio_type ) )
if audio . framesize ?
2020-09-01 18:33:04 +00:00
framesize = audio . framesize + ' ms '
2015-12-11 04:07:56 +00:00
audioStats . push ( @ stat ( audio , ' audio ' , ' Frame Size ' , ' framesize ' , framesize ) )
2015-12-10 11:21:59 +00:00
2015-12-11 04:07:56 +00:00
networkTag = null
2016-10-27 23:24:54 +00:00
if network ? && ! this . props . myTrack
2015-12-10 11:21:59 +00:00
if network . ping ?
networkStats . push ( @ stat ( network , ' network ' , ' Latency ' , ' ping ' , ( network . ping / 2 ) . toFixed ( 1 ) + ' ms ' ) )
2015-12-11 02:52:13 +00:00
if network . audiojq_median ?
networkStats . push ( @ stat ( network , ' network ' , ' Jitter Queue ' , ' audiojq_median ' , network . audiojq_median . toFixed ( 1 ) ) )
2015-12-12 03:14:00 +00:00
if network . jitter_var ?
2015-12-14 21:05:23 +00:00
networkStats . push ( @ stat ( network , ' network ' , ' Jitter ' , ' jitter_var ' , network . jitter_var . toFixed ( 1 ) + ' ms ' ) )
2015-12-10 11:21:59 +00:00
if network . pkt_loss ?
networkStats . push ( @ stat ( network , ' network ' , ' Packet Loss ' , ' pkt_loss ' , network . pkt_loss . toFixed ( 1 ) + ' % ' ) )
if network . wifi ?
if network . wifi
value = ' Wi-Fi '
else
2015-12-14 21:05:23 +00:00
value = ' Wired '
2015-12-10 11:21:59 +00:00
networkStats . push ( @ stat ( network , ' network ' , ' Connectivity ' , ' wifi ' , value ) )
2015-12-12 03:14:00 +00:00
if network . audio_bitrate_rx ?
networkStats . push ( @ stat ( network , ' network ' , ' Audio Bw Rx ' , ' audio_bitrate_rx ' , Math . round ( network . net_bitrate_rx ) + ' k ' ) )
if network . audio_bitrate_tx ?
networkStats . push ( @ stat ( network , ' network ' , ' Audio Bw Tx ' , ' audio_bitrate_tx ' , Math . round ( network . net_bitrate_tx ) + ' k ' ) )
if network . video_rtpbw_rx ?
networkStats . push ( @ stat ( network , ' network ' , ' Video Bw Rx ' , ' video_rtpbw_rx ' , Math . round ( network . video_rtpbw_rx ) + ' k ' ) )
if network . video_rtpbw_tx ?
networkStats . push ( @ stat ( network , ' network ' , ' Video Bw Tx ' , ' video_rtpbw_tx ' , Math . round ( network . video_rtpbw_tx ) + ' k ' ) )
2021-02-08 04:08:51 +00:00
if network . rx_ars_vs_p2p ?
networkStats . push ( @ stat ( network , ' network ' , ' RX Net Path ' , ' rx_ars_vs_p2p ' , network . rx_ars_vs_p2p ) )
if network . tx_ars_vs_p2p ?
networkStats . push ( @ stat ( network , ' network ' , ' TX Net Path ' , ' tx_ars_vs_p2p ' , network . tx_ars_vs_p2p ) )
2015-12-10 11:21:59 +00:00
2015-12-11 04:07:56 +00:00
networkTag =
` < div className = " network-stats stats-holder " >
< h3 > Internet < / h3 >
{ networkStats }
< / div > `
2015-12-10 11:21:59 +00:00
` < div className = " stats-hover " >
< h3 > Session Diagnostics & amp ; Stats: { this . props . participant . user . name } < / h3 >
2015-12-09 17:32:24 +00:00
2015-12-10 11:21:59 +00:00
< div className = " stats-area " >
2015-12-12 03:14:00 +00:00
{ aggregateTag }
2015-12-10 11:21:59 +00:00
< div className = " computer-stats stats-holder " >
< h3 > Computer < / h3 >
{ computerStats }
< / div >
< div className = " audio-stats stats-holder " >
< h3 > Audio Interface < / h3 >
{ audioStats }
< / div >
2015-12-11 04:07:56 +00:00
{ networkTag }
2015-12-10 11:21:59 +00:00
< / div >
< div className = " stats-info " >
{ extraInfo }
< / div >
2015-12-09 17:32:24 +00:00
< / div > `
onStatsChanged: (stats) ->
2015-12-10 11:21:59 +00:00
stats = window . SessionStatsStore . stats
if stats ?
2016-11-04 16:18:58 +00:00
if stats . parent ?
# if we have a parent, then use stats from the JamBlaster (parent), not ourselves. Otherwise we'll get bad stats (no Audio etc)
clientStats = stats . parent [ @ props . participant . client_id ]
else
clientStats = stats [ @ props . participant . client_id ]
2015-12-10 11:21:59 +00:00
else
clientStats = null
@ setState ( { stats: clientStats } )
2015-12-09 17:32:24 +00:00
getInitialState: () ->
2015-12-10 11:21:59 +00:00
stats = window . SessionStatsStore . stats
if stats ?
clientStats = stats [ @ props . participant . client_id ]
else
clientStats = null
{ stats: clientStats , hoverType: null , hoverField: null }
2015-12-09 17:32:24 +00:00
closeHover: (e) ->
e . preventDefault ( )
$container = $ ( this . getDOMNode ( ) ) . closest ( ' .react-holder ' )
$container . data ( ' bt ' ) . btOff ( )
} )