Last active
February 18, 2021 12:58
-
-
Save jumbo-in-Jap/7ceb26ed131ff9783517233ba97047e0 to your computer and use it in GitHub Desktop.
SkyWayStatsManager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.ntt.ecl.webrtc.sample_p2p_videochat; | |
import android.system.ErrnoException; | |
import android.util.Log; | |
import org.json.JSONArray; | |
import java.util.ArrayList; | |
import java.util.Date; | |
import java.util.List; | |
class SkyWayStatsConfig{ | |
// min: 5000 | |
int interval = 5000; | |
double fractionLostUnStableThresholdsRate = 0.8; | |
double fractionLostCriticalThresholdsRate = 1.0; | |
double jitterUnStableThresholdsMs = 50; | |
double jitterCriticalThresholdsMs = 100; | |
double rttUnStableThresholdsMs = 400; | |
double rttCriticalThresholdsMs = 800; | |
} | |
public class SkyWayStats { | |
public CodecInfo codecInfo = new CodecInfo(); | |
public List<StatsInfo> audioStatsInfoArray = new ArrayList<>(); | |
public SkyWayStats(){ | |
} | |
public StatsInfo addStats(SkyWayStatsConfig config, | |
int bytesReceived, | |
int bytesSent, | |
double packetsLost, | |
double packetsReceived, | |
double remoteInboundPacketsLost, | |
double remoteInboundJitter, | |
double remoteInboundRoundTripTime) { | |
StatsInfo info = new StatsInfo(); | |
info.bytesReceived = bytesReceived; | |
info.bytesSent = bytesSent; | |
info.packetsReceived = packetsReceived; | |
info.remoteInboundPacketsLost = remoteInboundPacketsLost; | |
info.remoteInboundJitter = remoteInboundJitter; | |
info.roundTripTime = remoteInboundRoundTripTime; | |
info.packetsLost = packetsLost; | |
if (audioStatsInfoArray.size() > 0){ | |
int lastIndex = this.audioStatsInfoArray.size() - 1; | |
double bytesReceivedDelta = bytesReceived - this.audioStatsInfoArray.get(lastIndex).bytesReceived; | |
long timeDelta = info.timestamp.getTime() - this.audioStatsInfoArray.get(lastIndex).timestamp.getTime(); | |
double bitrate = bytesReceivedDelta / timeDelta * 9 * 1000; | |
info.bitrate = bitrate; | |
double packetLostDelta = packetsLost - this.audioStatsInfoArray.get(lastIndex).packetsLost; | |
double packetReceivedDelta = packetsReceived - this.audioStatsInfoArray.get(lastIndex).packetsReceived; | |
info.fractionLost = packetLostDelta / packetReceivedDelta; | |
} | |
// check condition | |
if (info.fractionLost >= config.fractionLostCriticalThresholdsRate) { | |
info.condition = Condition.Critical; | |
info.msg = "bad network condition"; | |
}else if (info.fractionLost >= config.fractionLostUnStableThresholdsRate){ | |
info.condition = Condition.Stable; | |
info.msg = "bad network condition"; | |
} | |
log("bytesReceived: " + bytesReceived | |
+ " bytesSent: " + bytesSent | |
+ " packetsLost: " + packetsLost | |
+ " packetsReceived: " + packetsReceived | |
+ " remoteInboundPacketLoss: " + remoteInboundPacketsLost | |
+ " remoteInboundJitter: "+ remoteInboundJitter | |
+ " fractionLost: "+ info.fractionLost | |
+ " bitrate: " + info.bitrate | |
+ " remoteInboundRoundTripTime: " + remoteInboundRoundTripTime | |
); | |
this.audioStatsInfoArray.add(info); | |
return info; | |
} | |
private void log(String msg){ | |
Log.d("skyway-stats-manager", msg); | |
} | |
// internal classes | |
class CodecInfo{ | |
public String inboundAudioCodec; | |
public String inboundVideoCodec; | |
public String outboundAudioCodec; | |
public String outboundVideoCodec; | |
} | |
class StatsInfo { | |
public Date timestamp = new Date(); | |
public int bytesReceived = 0; | |
public int bytesSent = 0; | |
public double packetsLost = 0; | |
public double packetsReceived = 0; | |
public double remoteInboundPacketsLost = 0; | |
public double remoteInboundJitter = 0; | |
public double fractionLost = 0; | |
public double bitrate = 0; | |
public double roundTripTime = 0; | |
public Condition condition = Condition.Stable; | |
public String msg; | |
} | |
enum Condition { | |
Stable, | |
UnStable, | |
Critical | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.ntt.ecl.webrtc.sample_p2p_videochat; | |
import android.util.Log; | |
import org.json.JSONArray; | |
import org.json.JSONObject; | |
import java.util.TimerTask; | |
import java.util.Timer; | |
import io.skyway.Peer.Browser.MediaStream; | |
import io.skyway.Peer.MediaConnection; | |
import io.skyway.Peer.StatsCollectorCallback; | |
interface SkyWayStatsCallback { | |
void on(SkyWayStats.StatsInfo info); | |
} | |
public class SkyWayStatsManager { | |
private MediaConnection _mediaConnection; | |
public SkyWayStatsConfig _config; | |
public SkyWayStats skyWayStats; | |
private SkyWayStatsCallback callback; | |
public SkyWayStatsManager(MediaConnection mediaConnection, SkyWayStatsConfig config){ | |
this._mediaConnection = mediaConnection; | |
this._config = config; | |
this.skyWayStats = new SkyWayStats(); | |
Timer timer = new Timer(false); | |
TimerTask task = new TimerTask() { | |
@Override | |
public void run() { | |
if (mediaConnection.isOpen()){ | |
getStats(); | |
} | |
} | |
}; | |
timer.schedule(task, config.interval, config.interval); | |
} | |
private void getStats() { | |
// log("run stats"); | |
this._mediaConnection.getStats(new StatsCollectorCallback() { | |
@Override | |
public void onStatsDelivered(JSONArray jsonArray) { | |
try{ | |
JSONObject inboundAudioStream = getStatTable(jsonArray, "RTCInboundRTPAudioStream"); | |
JSONObject outboundAudioStream = getStatTable(jsonArray, "RTCOutboundRTPAudioStream"); | |
JSONObject remoteInboundAudioStream = getStatTable(jsonArray, "RTCRemoteInboundRtpAudioStream"); | |
// setCodec | |
// if (skyWayStats.codecInfo.inboundAudioCodec == null) { | |
// String inboundAudioCodec = getStatTable(jsonArray, inboundAudioStream.getString("codecId")).getString("mimeType"); | |
// String outboundAudioCodec = getStatTable(jsonArray, outboundAudioStream.getString("codecId")).getString("mimeType"); | |
// skyWayStats.codecInfo.inboundAudioCodec = inboundAudioCodec; | |
// skyWayStats.codecInfo.outboundAudioCodec = outboundAudioCodec; | |
// log("inbound codec: " + inboundAudioCodec + " outbound codec: " + outboundAudioCodec); | |
// } | |
// addStats | |
int bytesReceived = inboundAudioStream.getInt("bytesReceived"); | |
int bytesSent = outboundAudioStream.getInt("bytesSent"); | |
double packetsLost = inboundAudioStream.getDouble("packetsLost"); | |
double packetsReceived = inboundAudioStream.getDouble("packetsReceived"); | |
double remoteInboundJitter = remoteInboundAudioStream.getDouble("jitter"); | |
double remoteInboundPacketsLost = remoteInboundAudioStream.getDouble("packetsLost"); | |
double remoteInboundRoundTripTime = remoteInboundAudioStream.getDouble("roundTripTime"); | |
SkyWayStats.StatsInfo statsInfo = skyWayStats.addStats( | |
_config, | |
bytesReceived, | |
bytesSent, | |
packetsLost, | |
packetsReceived, | |
remoteInboundPacketsLost, | |
remoteInboundJitter, | |
remoteInboundRoundTripTime | |
); | |
callback.on(statsInfo); | |
}catch(Exception e){ | |
log("failed to get stats"); | |
} | |
} | |
}); | |
} | |
private JSONObject getStatTable(JSONArray jsonArray, String idPrefix) { | |
try{ | |
for (int i = 0; i < jsonArray.length(); i++) { | |
JSONObject table = jsonArray.getJSONObject(i); | |
if (table.getString("id").contains(idPrefix)){ | |
return table; | |
} | |
} | |
}catch(Exception e){ | |
return null; | |
} | |
return null; | |
} | |
public void setBadConditionListener(SkyWayStatsCallback l) { | |
this.callback = l; | |
} | |
private void log(String msg){ | |
Log.d("skyway-stats-manager", msg); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SkyWayStatsConfig config = new SkyWayStatsConfig(); | |
config.interval = 5000; | |
SkyWayStatsManager manager = new SkyWayStatsManager(_mediaConnection, config); | |
manager.setBadConditionListener(new SkyWayStatsCallback() { | |
@Override | |
public void on(SkyWayStats.StatsInfo info) { | |
handler.post(new Runnable() { | |
@Override | |
public void run() { | |
Button button = (Button)findViewById(R.id.switchCameraAction); | |
if (info.condition != SkyWayStats.Condition.Stable){ | |
Log.d("skyway-stats-manager", "bad condition: " + info.condition + " / " + info.msg); | |
button.setText("bad condition"); | |
}else{ | |
button.setText("good condition"); | |
} | |
} | |
}); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment