ã¯ã©ã€ã¢ã³ãã®èŠ³æž¬å¯èœæ§ïŒãŠã§ã
Vonage Video SDKã¯ãã»ãšãã©ã®ãŠãŒã¹ã±ãŒã¹ã§æšå¥šãããé«ã¬ãã«ã®çµ±èšAPIãéããŠã詳现ãªã¹ããªãŒã å質ã¡ããªã¯ã¹ãå ¬éããŸãããã®APIã¯ãé³å£°ããããªããããã¯ãŒã¯ãããã³éä¿¡è åŽã®çµ±èšãããã¢æ¥ç¶ã®é·ç§»ããŸããã§å®å®ãããŸãŸãçµ±äžãããã»ãã·ã§ã³èªè圢åŒã§æäŸããŸããé«åºŠãªãããã°ã®ããã«ãSDKã¯æªåŠçã®ãã¢æ¥ç¶ããŒã¿ãåæ ããçã®WebRTCçµ±èšã¬ããŒããžã®ã¢ã¯ã»ã¹ãæäŸããŸãã
SDKã¯ãŸãããããªãã·ã£ãŒãšãµãã¹ã¯ã©ã€ããŒã®äž¡æ¹ã«å¯ŸããŠãæ¥ç¶ã®å¥å šæ§ããã€ã¬ãã«ã§è©äŸ¡ãããããã¯ãŒã¯ã»ã³ã³ãã£ã·ã§ã³ã»ã¡ããªã¯ã¹ãå ¬éããŸãããããã®ã¡ããªã¯ã¹ã«ã¯ããããã¯ãŒã¯ã»ã³ã³ãã£ã·ã§ã³ã»ã¹ã³ã¢ããã®ã¹ã³ã¢ã®çç±ãããã³ãµãã¹ã¯ã©ã€ãã«ã€ããŠã¯ã芳å¯ãããåé¡ã®åå ãæ¥ç¶ã®ã©ã¡ãã«ãããã瀺ããã°ã©ããŒã·ã§ã³ã»ãœãŒã¹ãå«ãŸããŸããåç § ãããã¯ãŒã¯ã®ç¶æ ãšå£åã®åå 詳现ã¯ãã¡ãã
ãªãŒãã£ãªããããªãã¡ãã£ã¢ãªã³ã¯çµ±èšAPI
Vonage Video Web SDKã¯ããããªãã·ã£ãŒãšãµãã¹ã¯ã©ã€ããŒã®äž¡æ¹ã«å¯ŸããŠããªãŒãã£ãªããããªãã¡ãã£ã¢ãªã³ã¯ã®çµ±èšæ å ±ã宿çã«éä¿¡ããŸãããããã«ã¯ããã±ããæ°ããããã¬ãŒãããã¬ãŒã ã¬ãŒãããŒã¿ãäžæåæ¢/ããªãŒãºã¡ããªã¯ã¹ãã³ãŒããã¯æ å ±ãããã³åž¯åå¹ æšå®ããããã¯ãŒã¯ç¶æ ã¹ã³ã¢ãªã³ã°ãªã©ã®ãã©ã³ã¹ããŒãã¬ãã«ã®ãããã¯ãŒã¯ã¡ããªã¯ã¹ãå«ãŸããŸãã
åºç瀟ã®çµ±èšãåã
ã«ã€ã㊠Publisher.getStats() ã¡ãœããã¯
ãªããžã§ã¯ãã®é
åãæäŸããŸãã
ã«ãŒãã£ã³ã°ãããã»ãã·ã§ã³( ãªãŒãã³ããŒã¯
ã¡ãã£ã¢ã»ã«ãŒã¿ãŒ)ããã®é
åã«ã¯1ã€ã®ãªããžã§ã¯ããå«ãŸããVonage Video Media Routerã«éä¿¡ãããåäžã®ãªãŒãã£ãªã»ãããªã»ã¹ããªãŒã ã®çµ±èšæ
å ±ãå®çŸ©ããŸãã
ãã®é
åã«ã¯ãVonage Video Media Router ã«éä¿¡ãããåäžã®ãªãŒãã£ãªã»ãããªã»ã¹ããªãŒã ã®çµ±èšæ
å ±ãå®çŸ©ãã 1 ã€ã®ãªããžã§ã¯ããå«ãŸããŸããäžç¶ã»ãã·ã§ã³ã®å Žåã
ã«ã¯ãå
¬éã¹ããªãŒã ã®å å
¥è
ããšã®ãªããžã§ã¯ããå«ãŸããŸãã
以äžã®ã³ãŒãã§ã¯ããããªãã·ã£ãŒã®ã¹ããªãŒã ã®ã¡ããªã¯ã¹ãæ¯ç§ãã°ããŠããŸãïŒ
window.setInterval(() => {
publisher.getStats((error, statsArray) => {
if (error) {
console.error(error);
return;
}
statsArray.forEach(statsContainer => {
const stats = statsContainer.stats;
const connectionId = stats.connectionId || 'routed';
console.log(`\nStats for ${connectionId}`);
if (stats.video) {
const video = stats.video;
if (video.layers && video.layers.length > 0) {
console.log(`Video layers: ${video.layers.length}`);
video.layers.forEach((layer, index) => {
console.log(` Layer ${index}: ${layer.width}x${layer.height}`);
console.log(` encodedFrameRate: ${layer.encodedFrameRate} fps`);
console.log(` bitrate: ${layer.bitrate} bps`);
console.log(` totalBitrate: ${layer.totalBitrate} bps`);
console.log(` codec: ${layer.codec}`);
console.log(` scalabilityMode: ${layer.scalabilityMode}`);
if (layer.qualityLimitationReason) {
console.log(` qualityLimitationReason: ${layer.qualityLimitationReason}`);
}
});
}
console.log('transport estimated bandwidth:', stats.mediaLink.transport.connectionEstimatedBandwidth, 'bps');
console.log('network condition:', stats.mediaLink.transport.networkCondition);
console.log('network condition reason:', stats.mediaLink.transport.networkConditionReason);
}
});
});
}, 1000);
ãããªãã·ã£ãŒã§ã®ãããªå質ã€ãã³ãã®åä¿¡
ãšã®çµ±èšããŒãªã³ã°ã«å ã Publisher.getStats()ã賌èªããããšã§ããããªãã·ã£ãŒããããªã®åè³ªã«æå³ã®ããå€åãæ€åºãããšãã«ããªã¢ã«ã¿ã€ã ã§éç¥ãèãããšãã§ããŸãã videoQualityChanged ã€ãã³ããéå¬ããïŒ
publisher.on('videoQualityChanged', ({ reason, statsContainer }) => {
console.log('Video quality change reason:', reason);
const { stats } = statsContainer;
if (stats.video && stats.video.layers) {
stats.video.layers.forEach((layer) => {
console.log(
`Resolution: ${layer.width}x${layer.height}, FPS: ${layer.frameRate}`
);
});
}
});
ãããªãã·ã£ãŒã§ã®ãããã¯ãŒã¯ç¶æ³ã€ãã³ãã®åä¿¡
ãããªãã·ã£ãŒã®ãããã¯ãŒã¯ç¶æ
å€åã€ãã³ããåãåãã«ã¯ networkConditionChanged ã€ãã³ããéå¬ããïŒ
publisher.on('networkConditionChanged', ({ reason, statsContainer }) => {
const { stats } = statsContainer;
console.log('Network condition changed.');
console.log(`Network Condition: ${stats.mediaLink.transport.networkCondition}, Reason: ${stats.mediaLink.transport.networkConditionReason}`);
});
ãã®ã€ãã³ãã¯ããããªãã·ã£ãŒã«å¯ŸããŠãããã¯ãŒã¯ç¶æ
ã®é倧ãªå€åãæ€ç¥ããããšãã«ããªã¬ãŒãããããã®ã€ãã³ã㯠statsContainer ãªããžã§ã¯ãã«ã¯ã圱é¿ãåãããµãã¹ã¯ã©ã€ãã®ã¡ãã£ã¢ãªã³ã¯çµ±èšãå«ãŸããŸãããªã¬ãŒãããã»ãã·ã§ã³ã§ã¯ã圱é¿ãåãããµãã¹ã¯ã©ã€ãã®çµ±èšã®ã¿ãã€ãã³ãã«å«ãŸããŸãã
賌èªè ã®çµ±èšæ å ±ã®ååŸ
ã«ã€ã㊠getStats() ã¡ãœããã¯ããµãã¹ã¯ã©ã€ãã®ã¹ããªãŒã ã«é¢ããæ
å ±ãæäŸããŸãã
ãµãã¹ã¯ã©ã€ãã®ã¹ããªãŒã ã«é¢ããæ
å ±ãæäŸããŸãã
以äžã®ã³ãŒãã¯ãå å ¥è ã®ã¹ããªãŒã ã«ã€ããŠã1ç§ããšã«ããã€ãã®ã¡ããªã¯ã¹ãèšé²ããïŒ
window.setInterval(() => {
subscriber.getStats((error, stats) => {
if (error) {
console.error('Error getting subscriber stats: ', error.message);
return;
}
const video = stats.video;
if (video) {
console.log('video bitrate:', video.bitrate, 'bps');
console.log('video totalBitrate:', video.totalBitrate, 'bps');
console.log('decoded frame rate:', video.decodedFrameRate, 'fps');
console.log('codec:', video.codec);
console.log('res:', `${video.width}x${video.height}`);
console.log('freezeCount:', video.freezeCount);
console.log('totalFreezesDuration:', video.totalFreezesDuration, 'ms');
console.log('pauseCount:', video.pauseCount);
console.log('totalPausesDuration:', video.totalPausesDuration, 'ms');
}
});
}, 1000);
å å ¥è ã®ãããªå質ã€ãã³ãã®åä¿¡
ãèŽãããšãã§ããã videoQualityChanged ã€ãã³ãã§ããããªç»è³ªã®èããäžæãå€åãæ€åºããããšãã«éç¥ãããŸãã
subscriber.on('videoQualityChanged', ({ reason, stats }) => {
if (reason === 'videoInterruption') {
console.warn('Video playback was interrupted');
if (stats.video.freezeCount > 0) {
console.log(`Freeze count: ${stats.video.freezeCount}`);
}
if (stats.video.pauseCount > 0) {
console.log(`Pause count: ${stats.video.pauseCount}`);
}
}
});
å å ¥è ã®ãããã¯ãŒã¯ç¶æ ã€ãã³ãã®åä¿¡
ãµãã¹ã¯ã©ã€ããŒã®ãããã¯ãŒã¯æ¡ä»¶å€æŽã€ãã³ããåãåãã«ã¯ã以äžã®ããã«ãªãã¹ã³ããã networkConditionChanged ã€ãã³ããéå¬ããïŒ
subscriber.on('networkConditionChanged', ({ reason, stats }) => {
console.log('Network condition changed.');
console.log(`Degradation source: ${stats.mediaLink.networkDegradationSource}`);
if (stats.mediaLink.networkDegradationSource === 'local') {
console.log(`Network Condition: ${stats.mediaLink.transport.networkCondition}, Reason: ${stats.mediaLink.transport.networkConditionReason}`);
} else if (stats.mediaLink.networkDegradationSource === 'remote') {
console.log(`Network Condition: ${stats.mediaLink.remotePublisherTransport.networkCondition}, Reason: ${stats.mediaLink.remotePublisherTransport.networkConditionReason}`);
}
});
ãã®ã€ãã³ãã¯ããµãã¹ã¯ã©ã€ããŒãŸãã¯ãªã¢ãŒããããªãã·ã£ãŒã®ãããã¯ãŒã¯ç¶ æ
ã®é倧ãªå€åãæ€ç¥ããããšãã«ããªã¬ãŒãããããã®ã€ãã³ã㯠stats ãªããžã§ã¯ãã«ã¯ãããŒã«ã«ããã³ãªã¢ãŒãã®ãã©ã³ã¹ããŒãã»ã¡ããªã¯ã¹ãšå£åãœãŒã¹ãå«ãã¡ãã£ã¢ãªã³ã¯çµ±èšãå«ãŸããŸãã
æ¢ç¥ã®åé¡
å質å¶éã®ããªã¬ãŒãšãªãå®éã®å€ãæ¡ä»¶ã¯å®è£ ã«åºæã§ããããã©ãŠã¶ããã©ãããã©ãŒã ã«ãã£ãŠç°ãªãå ŽåããããŸããäŸãã°
- ç»é¢å
±æã®ãããªã¹ããªãŒã ã¯
videoQualityChangedã€ãã³ããéå¬ããã - Firefoxã¯ä»¥äžããµããŒãããŠããŸããã
qualityLimitationReasonãã®ããããã®ããããã£ã¯ãããªãã·ã£ãŒã®çµ±èšã«ã¯ååšããªãããŸãvideoQualityChangedçç±ã®ããåºæ¥äºbandwidth,cpuãããŠotherã¯ãã®ãã©ãŠã¶ã§ã¯ãµããŒããããŠããŸããã - ããŒããŠã§ã¢ã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã«ãããããªãšã³ã³ãŒãã£ã³ã°ãšå°çšãããªãšã³ã³ãŒããŒããmacOSã®ããªã¬ãŒãé²ã
cpuå¶éãããã
çµ±èšããŒã¿æ§é
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãVideo API ãæäŸããæ§é äœãšããããã£ã®æŠèŠã説æããŸãããã¹ãŠã® Video SDK ãã©ãããã©ãŒã ãåãçµ±èšæ å ±ã»ãããå ¬éããŠããŸãããåãã©ãããã©ãŒã ã§åã ã®ãã£ãŒã«ãã®æ§é ãååã®ä»ãæ¹ã«è¥å¹²ã®éããããå ŽåããããŸãããããã®éãã¯ãåºæ¬çãªã¡ããªã¯ã¹ã®éãã§ã¯ãªãããã©ãããã©ãŒã åºæã® SDK ã®èšèšèŠçŽãåæ ããŠããŸãã
å©çšå¯èœãªçµ±èšãšããã衚ããã®ã«ã€ããŠã®ãã©ãããã©ãŒã ã«äŸåããªã説æã«ã€ããŠã¯ã以äžãåç §ã®ããšã 顧客ã®èŠ³æž¬å¯èœæ§ã®æŠèŠ.
åºçç€Ÿçµ±èš (stats)
åºç瀟ã«é¢ããçµ±èšæ å ±ãæäŸããŸãã
connectionId- ã®idããããã£ãšäžèŽãããã¯ã©ã€ã¢ã³ãæ¥ç¶ã®äžæãªIDãconnectionããããã£ã®connectionCreatedã»ãã·ã§ã³ãªããžã§ã¯ãããªã¢ãŒãã¯ã©ã€ã¢ã³ãã«ãã£ã¹ãããããã€ãã³ã(ãªã¬ãŒãããã»ãã·ã§ã³ã§ã®ã¿äœ¿çšå¯èœ)ãsubscriberId- ã®idããããã£ãšäžèŽããã賌èªè ã®äžæãªIDãSubscriberãªããžã§ã¯ãããµãã¹ã¯ã©ã€ãããŠããã¯ã©ã€ã¢ã³ãã®ã¢ããªã§äœ¿çšããããšãã§ããŸãïŒãªã¬ãŒã»ãã·ã§ã³ã§ã®ã¿äœ¿çšå¯èœïŒã
åºç瀟ãªãŒãã£ãªçµ±èš (stats.audio)
ãããªãã·ã£ãŒã®ãªãŒãã£ãªãã©ãã¯ã«é¢ããçµ±èšãæäŸããŸãã
bytesSent- éä¿¡ããããªãŒãã£ãªã»ãã€ãã®åèšãpacketsLost- å å ¥è ãŸãã¯ã¡ãã£ã¢ã»ã«ãŒã¿ãŒã«å°éããªãã£ããªãŒãã£ãªã»ãã±ããã®åèšãpacketsSent- éä¿¡ããããªãŒãã£ãªãã±ããã®åèšãtimestamp- çµ±èšæ å ±ãåéãããUnixã¿ã€ã ã¹ã¿ã³ãïŒmsïŒã
åºç瀟ãããªçµ±èš (stats.video)
ãããã®ãã£ãŒã«ãã¯ããããªãã·ã£ãŒã®çŸåšã®ãããªããã©ãŒãã³ã¹ã衚ããŠããŸãïŒ
bytesSent- éä¿¡ããããããªã»ãã€ãã®åèšãpacketsLost- å å ¥è ãŸãã¯ã¡ãã£ã¢ã«ãŒã¿ãŒã«å°éããªãã£ããããªãã±ããã®åèšãpacketsSent- éä¿¡ããããããªãã±ããã®åèšãlayers- ã¢ã¯ãã£ããªãããªãšã³ã³ãŒãã£ã³ã°ã¬ã€ã€ãŒãé«è§£å床ããäœè§£å床ã®é ã«äžŠã¹ããªã¹ãã
ãããªãã·ã£ãŒãããªã¬ã€ã€ãŒçµ±èš (stats.video.layers)
1ã€ã®ãµã€ãã«ãã£ã¹ãã»ã¬ã€ã€ãŒãŸãã¯SVCã¬ã€ã€ãŒã衚ãã
width- ãšã³ã³ãŒããããå¹ ïŒãã¯ã»ã«ïŒãheight- ãšã³ã³ãŒããããé«ãããã¯ã»ã«ã§è¡šããencodedFrameRate- ãã®ã¬ã€ã€ãŒã®å®éã®ãšã³ã³ãŒããã¬ãŒã ã¬ãŒããbitrate- ãã€ããŒãã®ãããã¬ãŒãïŒbpsïŒãtotalBitrate- RTPããããŒãšããã£ã³ã°ãå«ããããã¬ãŒãïŒbpsïŒãscalabilityMode- ã¹ã±ãŒã©ããªãã£èšå®ïŒäŸïŒSVCã®å Žåã¯ãL1T3ãããµã€ãã«ãã£ã¹ãã®å Žåã¯ãL3T3ãïŒãcodec- ãã®ã¬ã€ã€ãŒã«äœ¿çšãããã³ãŒããã¯ãqualityLimitationReason- ãšã³ã³ãŒããŒãå質ã調æŽããçç± (ã垯åå¹ ãããCPUããããã®ä»ã)ã
åºç瀟ã¡ãã£ã¢ãªã³ã¯çµ±èš (stats.mediaLink.transport)
ã«ã€ã㊠transport ãªããžã§ã¯ãã¯ãåã
ã®ãã©ãã¯ãã¬ã€ã€ãŒã§ã¯ãªãããªãŒãã£ãªãããªãã©ã³ã¹ããŒãå
šäœã«é©çšããããã¢ã³ãã¯ã·ã§ã³ã¬ãã«ã®ãããã¯ãŒã¯æšå®ã¡ããªã¯ã¹ãæäŸããã
connectionEstimatedBandwidth- æ¥ç¶ã§å©çšå¯èœãªã¢ãããªã³ã¯åž¯åå¹ ã®æšå®å€ïŒbpsïŒãnetworkCondition- çŸåšã®ãããã¯ãŒã¯ã»ã³ã³ãã£ã·ã§ã³ã»ã¹ã³ã¢"unknown","critical","warning","fair","good"ãããã¯"excellent").networkConditionReason- ãããã¯ãŒã¯ç¶æ³ã«åœ±é¿ãäžããäž»ãªçç±"none","unknown","bandwidth"ãããã¯"packetLoss").
å å
¥è
ãããªçµ±èš (stats.video)
ãããã®ãã£ãŒã«ãã¯ãå å ¥è ã®ãªã¢ã«ã¿ã€ã ã®ãããªåä¿¡ããã³ãã³ãŒãæ§èœã瀺ãïŒ
bytesReceived- åä¿¡ãããããªã»ãã€ãã®åèšãpacketsLost- å å ¥è ã«å±ããªãã£ããããªãã±ããã®åèšãpacketsReceived- åä¿¡ãããããªãã±ããã®åèšãtimestamp- çµ±èšæ å ±ãåéãããUnixã¿ã€ã ã¹ã¿ã³ãïŒmsïŒãdecodedFrameRate- ãã³ãŒããŒãçæããå®éã®ãã¬ãŒã ã¬ãŒãïŒfpsïŒãbitrate- ãã€ããŒãã®ãããã¬ãŒãïŒããã/ç§ïŒãtotalBitrate- RTPããããŒãšããã£ã³ã°ãå«ããããã¬ãŒãïŒbpsïŒãcodec- ãã®å å ¥è ã«äœ¿çšãããŠããã³ãŒããã¯ãpauseCount- 5ç§ä»¥äžãã¬ãŒã ãã¬ã³ããªã³ã°ãããªãã£ãããŒãºã®æ°ãtotalPausesDuration- å šäŒæ¢ã®çŽ¯ç©æéïŒmsïŒãfreezeCount- çãããªãŒãºã®æ°ïŒWebRTCçµ±èšã®å®çŸ©ããïŒãtotalFreezesDuration- ãã¹ãŠã®ããªãŒãºã®çŽ¯ç©æéïŒmsïŒã
å å
¥è
éä¿¡åŽæšå®(stats.senderStats)
ãããã®ã¡ããªã¯ã¹ã¯ãéä¿¡è ã®éä¿¡æ¥ç¶ã«ã€ããŠå ±åããã垯åå¹ ã®æšå®å€ãæäŸããïŒ
connectionMaxAllocatedBitrate- éä¿¡åŽã«å²ãåœãŠãããæå€§ãããã¬ãŒãïŒbpsïŒãconnectionEstimatedBandwidth- éä¿¡åŽã®çŸåšã®æšå®ã¢ãããªã³ã¯åž¯åå¹ ïŒbpsïŒã
å å
¥è
ã¡ãã£ã¢ãªã³ã¯çµ±èš (stats.mediaLink)
ã«ã€ã㊠mediaLink ãªããžã§ã¯ãã¯ããµãã¹ã¯ã©ã€ããŒã®æ¥ç¶ã«å¯Ÿãããã©ã³ã¹ããŒã㬠ãã«ãšãããã¯ãŒã¯ã®ãã°ã¬ãŒãæ
å ±ãæäŸãããããã¯ãããªãã·ã£ãŒã® mediaLink.transport ããŒã«ã«ãšãªã¢ãŒãã®ãã©ã³ã¹ããŒãã«å ããå£åãœãŒã¹ã®ã€ã³ãžã±ãŒã¿ãŒãããïŒ
transport- ãã®ãµãã¹ã¯ã©ã€ããŒã®ããŠã³ãªã³ã¯æ¥ç¶ã®ããŒã«ã«ãã©ã³ã¹ããŒãçµ±èšïŒãããªãã·ã£ãŒã®stats.mediaLink.transport).éä¿¡åŽã®çµ±èšãé³å£°ãã©ãŒã«ããã¯ãç¡å¹ã«ãªã£ãŠããå Žåãå¶éãããããšããããremotePublisherTransport- ã¢ãããªã³ã¯æ¥ç¶ã®ãªã¢ãŒããããªãã·ã£ãŒãã©ã³ã¹ããŒãçµ±èšïŒãããªãã·ã£ãŒã®stats.mediaLink.transport).éä¿¡åŽã®çµ±èšãé³å£°ãã©ãŒã«ããã¯ãç¡å¹ã«ãªã£ãŠããå Žåãå¶éãããããšããããnetworkDegradationSource- ããããã°ãã©ã¡ãã®åŽããããã¯ãŒã¯ã®å£åãåŒãèµ·ããããã瀺ããåãåŸãå€ïŒ"none","local","remote"ãããã¯"bothOrUnclear".éä¿¡åŽã®çµ±èšãé³å£°ãã©ãŒã«ããã¯ãç¡å¹ã«ãªã£ãŠããå Žåãå¶éãããããšããããŸãã
é話å質ã¢ãã¿ãªã³ã°
ã³ã¢çµ±èšAPIã«å ããOpenTok.jsã¯é話å質ã®å€åãç£èŠãã察å¿ããããã®è¿œå æ©èœãæäŸããŸãããããã®æ©èœã¯ãã¢ããªã±ãŒã·ã§ã³ãããã€ã¹ã®å¶çŽããããã¯ãŒã¯ç¶æ³ã«é©å¿ããŠããã©ãŒãã³ã¹ãæé©åããã®ã«åœ¹ç«ã¡ãŸãã
CPUããã©ãŒãã³ã¹ç£èŠ
ã¢ããªã±ãŒã·ã§ã³ã¯ããã©ãããã©ãŒã ã®ç°ãªãæ§ã ãªã¢ãã€ã«ããã€ã¹ããã¹ã¯ãããããã€ã¹äžã§å®è¡ãããå¯èœæ§ããããããã«ãããã€ã¹ã®ããŒããŠã§ã¢ä»æ§ã¯åäžã§ã¯ãªããäŸãã°ãããã¢ãã€ã«ã»ããã€ã¹ã¯å€ãã®ãã¹ã¯ãããã»ããã€ã¹ãããCPUæ§èœãåªããŠãããããããªããããã®éãããããªãã
CPUãGPUãRAMãããŒããŠã§ã¢ã»ãšã³ã³ãŒã/ãã³ãŒããªã©ã倿°ã®ããŒããŠã§ã¢æ§æãå¯èœãªããããã¥ãŒãã³ã°ãå¿ èŠã«ãªãå ŽåããããŸããæ§èœã®äœãããã€ã¹ã¯ãCPUã«è² è·ã®ãããæ©èœãç¡å¹ã«ããããã«èšå®ã§ããæ§èœã®é«ãããã€ã¹ã¯ãããæ²¡å ¥æã®ããäœéšãããã©ã«ãã«ããããšãã§ããŸãã
CPUããã©ãŒãã³ã¹ã®å€åã®æ€åº
ã»ãã·ã§ã³ãã¢ãã¿ãŒããããšã§ãããã€ã¹ã®CPUè² è·ã®å€åãæ€åºããããšãã§ããŸãã cpuPerformanceChanged
ã€ãã³ããå«ãããã®ã€ãã³ãã«ã¯ cpuPerformanceState ããããã£ã«èšå®ãããïŒ
'nominal'- ãã®è£ 眮ã¯è¿œå ã®ä»äºãåŒãåããããšãã§ããã'fair'- ããã«ããã¡ã³ãæèŒããããã€ã¹ã®å Žåããã¡ã³ãäœåããé³ãèãããããã«ãªãããšãããã'serious'- ããã€ã¹ã¯ã¹ãã¬ã¹ãåããŠããããããªãœãŒã¹ïŒCPUãªã©ïŒã®ã¹ãããã«ãçºçããå¯èœæ§ãããã'critical'- ããã€ã¹ã«ã¯éåžžã«å€§ããªã¹ãã¬ã¹ãããã£ãŠãããããã軜æžããªããšåé¡ãçºçããå¯èœæ§ãããã
詳ãã㯠ãã®W3C仿§.
CPUããã©ãŒãã³ã¹ã®å€åã«åºã¥ãã¢ããªã±ãŒã·ã§ã³ã®æé©å
ãã®ã€ãã³ãã«å¿çããŠãã¢ããªã±ãŒã·ã§ã³ã¯ãŠãŒã¶ãŒã«ãªãœãŒã¹ã®æ¶è²»ãéç¥ããã ãªã©ã®èšç®éã®å€ãããã»ã¹ãç¡å¹ã«ããããšãã§ããã ãããªãã©ã³ã¹. ã»ãã·ã§ã³ãèŠã cpuPerformanceChanged.
以äžã®ã³ãŒãã¯ãCPUã 'critical' ããã©ãŒãã³ã¹ç¶æ
ãš
ã«æ»ã£ãããåã³æå¹ã«ããŸãã 'fair' ãŸãã¯ãã以äžïŒ
let isVideoDisabledByCPU = false;
session.on('cpuPerformanceChanged', (event) => {
if (event.cpuPerformanceState === 'critical') {
// The application should alert the user why their video is being disabled
publisher.publishVideo(false);
isVideoDisabledByCPU = true;
} else if (event.cpuPerformanceState === 'nominal' || event.cpuPerformanceState === 'fair') {
if (isVideoDisabledByCPU) {
publisher.publishVideo(true);
isVideoDisabledByCPU = false;
}
}
})
å¹³åæèŠã¹ã³ã¢ïŒMOSïŒ
ãŠãŒã¶ãŒããµãŒãã¹ããæããçµéšã®è³ªã¯ã以äžã®æ¹æ³ã§è©äŸ¡ããããšãã§ããã å¹³åæèŠã¹ã³ã¢ (MOSïŒã
æ Œä»ãã·ã¹ãã
MOSã¯æ£ã®æ°ã§è¡šããããã¹ã³ã¢ã¯1ïŒæãåè³ªãæªãïŒãã5ïŒæãå質ãè¯ãïŒã®éã§ããïŒ
- 5ïŒExcellentïŒ - ãŠãŒã¶ãŒãäœéšã§ããæé«ã®å質ã«å¯Ÿããä»®æ³çãªäžéã
- 4 (Good) - ããéæå¯èœãªè©äŸ¡ãVonageãŠãŒã¶ãŒã¯ãã®ã¬ãã«ã®å質ãæåŸ ã§ããŸãã
- 3 (Fair) - å質ã¯åé¡ãªãã
- 2 (Poor) - å質ãåãå ¥ããããã
- 1ïŒæªãïŒ - åè³ªã¯ææªã
ã¢ã«ãŽãªãºã
MOSã¬ãŒãã£ã³ã°ã¯ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã«åœ±é¿ãäžããïŒãããŠäœäžããããïŒããã€ãã®èŠçŽ ãèæ ®ã«å ¥ããŠããŸãããããã®èŠå ã«ã¯ä»¥äžã®ãã®ãå«ãŸããŸãïŒãã ãããããã«éå®ããããã®ã§ã¯ãããŸããïŒïŒ
- ãã±ãããã¹ - ãã±ãããã¹ãã¡ãã£ã¢ã®å質ãå£åããã
- ãããã¬ãŒã - ãããã¬ãŒããé«ãã»ã©ãã¡ãã£ã¢ã®å¿ å®åºŠã¯é«ããªãã
- ãããã¯ãŒã¯é å»¶ - å°çãé ããããã±ããã¯ãããããããå¯èœæ§ããããé³å£°ã®æ¬ èœãæ åã®ä¹±ãã«ã€ãªãããŸãã
é話å質ã®å€åã«åºã¥ãã¢ããªã±ãŒã·ã§ã³ã®æé©å
ãµãã¹ã¯ã©ã€ããŒã䜿ã ã¯ãªãªãã£ã¹ã³ã¢å€æŽ ã€ãã³ãã§ããªãŒãã£ãªãšãããªã®å質ã®å€åãç£èŠãããããããã¡ãã£ã¢å質ã®å€åãç£èŠããã ãã§ã¯äžååã§ããé話ã¢ããªã±ãŒã·ã§ã³ã®ãªã¢ã«ã¿ã€ã ã®æ§è³ªãèãããšãæé«ã®ãŠãŒã¶ãŒäœéšãç¶ç¶çã«æäŸããããã«ã¢ããªã±ãŒã·ã§ã³ããã¥ãŒãã³ã°ããããšã«ãã£ãŠã芳å¯ãããå€åã«å¯Ÿå¿ããããšãå¿ èŠã§ãã
åçŽãªãã¥ãŒãªã¹ãã£ãã¯ã以äžã«ç€ºããã¢ããªã±ãŒã·ã§ã³ã¯ãªãœãŒã¹å¶çŽã«åºã¥ããŠåçã«æé©åãããã
// We want to know if the CPU is overloaded. If it is, then we
// can disable certain features so that the best call possible
// can still take place.
let isCpuOverloaded = false;
session.on('cpuPerformanceChanged', (event) => {
isCpuOverloaded = event.cpuPerformanceState === 'critical';
});
// We monitor for changes in call quality. This allows us to
// tune our application, taking into account multiple factors
// (inlined below)
subscriber.on('qualityScoreChanged', (event) => {
const { qualityScore } = event;
const isVideoQualityBad = qualityScore.video < 2;
if (!isVideoQualityBad && !isCpuOverloaded) {
// Subscribe to the highest quality video since the CPU isn't taxed
// and the quality received is good
subscriber.setPreferredResolution('1280x720');
subscriber.setPreferredFrameRate(30);
}
else if (isVideoQualityBad && !isCpuOverloaded) {
// Even though the CPU isn't taxed, the video quality received is
// bad. This might be due to (hopefully) intermittent network issues, so
// we subscribe to lower quality video.
subscriber.setPreferredResolution('320x180');
subscriber.setPreferredFrameRate(7);
}
else if (isVideoQualityBad && isCpuOverloaded) {
// The video quality received is bad and the CPU not being overloaded.
// Let's disable video for now.
// We can enable video once conditions improve. See statement below.
subscriber.subscribeToVideo(false);
}
else {
// Enable video
subscriber.subscribeToVideo(true);
}
});
é話åãã¹ãã«ãããé話åè³ªã®æšå®
Vonageãã㪠ãŠã§ãçšãããã¯ãŒã¯ã»ãã¹ãã»ã©ã€ãã©ãª ã䜿çšããŠãã¯ã©ã€ã¢ã³ãããªãŒãã£ãªãšãããªã®å
¬éããµããŒãããŠãããã©ããã確èªããã¯ã©ã€ã¢ã³ãã®å
¬éã¹ããªãŒã ã®ãªãŒãã£ãªãšãããªã®æšå®MOSã¹ã³ã¢ãå ±åããŸãããã®ã©ã€ãã©ãªã¯ Publisher.getRtcStatsReport() ãã㊠Subscriber.subscriber.getStats() ã®æ¹æ³ã§MOSã¹ã³ã¢ãç®åºããã
éä¿¡åŽçµ±èš
åç § éä¿¡åŽçµ±èšã®æŠèŠ.
éä¿¡åŽçµ±èšã®æå¹å
éä¿¡è
åŽã®çµ±èšæ
å ±ã¯ã賌èªè
ãåãåããéä¿¡è
åŽã®çµ±èšæ
å ±ãåãåãã«ã¯ãã¹ããªãŒã ã®ãããªãã·ã£ãŒã« publishSenderStats ããããã£ã true ã§ã® OT.initPublisher ã³ãŒã«ïŒ
const publisher = OT.initPublisher({
publishSenderStats: true
});
ãã publishSenderStats ãæå¹ã§ãªãå Žåããã®ãããªãã·ã£ãŒã«å¯ŸããŠéä¿¡è
çµ±èšãã£ã³ãã«ã¯çºè¡ãããŸãããããã©ã«ãå€ã¯ false.
éä¿¡åŽçµ±èšã®åä¿¡
ãããªãã·ã£ãŒãéä¿¡è
åŽã®çµ±èšæ
å ±ãæå¹ã«ããŠããå Žåã賌èªè
ã¯èªåçã« Subscriber.getStats() åè¿°.ãã® senderStats ããããã£ã¯2ã€ã®ææšãæäŸããŸãïŒ
connectionMaxAllocatedBitrate- æ¥ç¶æã«æšå®å¯èœãªæå€§ãããã¬ãŒãïŒbpsïŒconnectionEstimatedBandwidth- çŸåšã®æšå®æ¥ç¶åž¯åå¹ (bps)
ãããã®ã¡ããªã¯ã¹ã¯ããªãŒãã£ãªã»ãããªã»ãã³ãã«ããšã«èšç®ãããããããããªãšãªãŒãã£ãªã®äž¡æ¹ã®çµ±èšã«åãå€ã衚瀺ãããŸããæåã® getStats ãããã¯ãŒã¯é
å»¶ã®ãããéä¿¡è
çµ±èšãå«ãŸããªãå Žåãããã
subscriber.getStats((stats) => {
if (stats.senderStats) {
console.log(`Connection max allocated bitrate: ${stats.senderStats.connectionMaxAllocatedBitrate} bps`);
console.log(`Connection current estimated bandwidth: ${stats.senderStats.connectionEstimatedBandwidth} bps`);
}
});
æ¢ç¥ã®åé¡
ã»ãã·ã§ã³ããªã¬ãŒãããŠããå ŽåããŸãã¯åå è ã2人ã ãã®ç¹å®ã®ã«ãŒãã£ã³ã°ã»ã»ããã¢ããã§ããããªãã·ã£ãŒãFirefoxã䜿çšããŠããå Žåããã©ãŠã¶ã®å¶éã«ããéä¿¡åŽã®çµ±èšãå©çšã§ããªãããšããããŸãã
ãããã¯ãŒã¯ã®ç¶æ ãšå£åã®åå
SDKã¯ããããªãã·ã£ãŒãšãµãã¹ã¯ã©ã€ããŒã®äž¡æ¹ã«å¯ŸããŠãã³ã³ãã£ã·ã§ã³ã®ã¹ã³ã¢ããã®ã¹ã³ã¢ãé§åããçç±ããµãã¹ã¯ã©ã€ããŒã®å£åãœãŒã¹ãå«ããªã¢ã«ã¿ã€ã ã®ãããã¯ãŒã¯ã»ã³ã³ãã£ã·ã§ã³ã»ã¡ããªã¯ã¹ãæäŸããŸãããããã¯ãŒã¯ã»ã³ã³ãã£ã·ã§ã³ã»ã¢ãã«ãã¹ã³ã¢ãçç±ãããã³ãããæå¹ã«ããæ¹æ³ã®è©³çްã«ã€ããŠã¯ 顧客ã®èŠ³æž¬å¯èœæ§ã®æŠèŠ.
ãããã¯ãŒã¯ã»ã³ã³ãã£ã·ã§ã³ã»ããŒã¿ã¯2ã€ã®ãã£ã³ãã«ããå ¥æã§ããïŒ
- 宿çãªçµ±èšïŒ ã¡ãã£ã¢ãªã³ã¯çµ±èšã€ãã³ãã«ã¯ã以äžã®ãã©ã³ã¹ããŒãã¡ããªã¯ã¹ãå«ãŸããŸãã
connectionEstimatedBandwidth,networkConditionãããŠnetworkConditionReason.å å ¥è ã®çµ±èšãå ¬éremotePublisherTransportãããŠnetworkDegradationSource. - ãããã¯ãŒã¯ç¶æ ã®å€æŽã€ãã³ãïŒ äž¡åœã®å°çšã€ãã³ã åºç瀟 ãã㊠å¥çŽè ã¯ããããã¯ãŒã¯ç¶æ ã®é倧ãªå€åãæ€åºããããšãã«ããªã¬ãŒãããã
以äžã®äŸã§ã¯ãå å ¥è ãããã¯ãŒã¯ã®ç¶æ ããŒã¿ã䜿çšããŠãå£åã®åå ãç¹å®ããæ¹æ³ã瀺ããŠããŸãïŒ
subscriber.on('networkConditionChanged', ({ reason, stats }) => {
console.log('Network condition changed.');
console.log(`Degradation source: ${stats.mediaLink.networkDegradationSource}`);
if (stats.mediaLink.networkDegradationSource === 'local') {
console.log(`Network Condition: ${stats.mediaLink.transport.networkCondition}, Reason: ${stats.mediaLink.transport.networkConditionReason}`);
} else if (stats.mediaLink.networkDegradationSource === 'remote') {
console.log(`Network Condition: ${stats.mediaLink.remotePublisherTransport.networkCondition}, Reason: ${stats.mediaLink.remotePublisherTransport.networkConditionReason}`);
});
RTCçµ±èšã¬ããŒã
ãããªãã·ã£ãŒã®äœã¬ãã«ã®ãã¢æ¥ç¶çµ±èšãååŸããã«ã¯ Publisher.getRtcStatsReport() ã¡ãœãããåŒã³åºãããã®ã¡ãœããã¯ãããã¹ãè¿ãã RtcStatsReport ãªããžã§ã¯ããè¿ããŸãïŒ
publisher.getRtcStatsReport()
.then((stats) => stats.forEach(console.log))
.catch(console.log);
ãµãã¹ã¯ã©ã€ãã®äœã¬ãã«ã®ãã¢æ¥ç¶çµ±èšãååŸããã«ã¯ Subscriber.getRtcStatsReport() ã¡ãœãããåŒã³åºãããã®ã¡ãœããã¯ãããã¹ãè¿ãã RtcStatsReport ãªããžã§ã¯ããè¿ããŸãïŒ
subscriber.getRtcStatsReport()
.then((stats) => stats.forEach(console.log))
.catch(console.log);