Skip to content

Commit 455b6a9

Browse files
authored
Merge pull request #277 from shiguredo/feature/get-stats
統計情報取得 getStats メソッド追加
2 parents b6332a3 + e2dafad commit 455b6a9

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313

1414
- [UPDATE] libwebrtc m140.7339.2.2 に上げる
1515
- @miosakuma
16+
- [UPDATE] Statistics, StatisticsEntry をドキュメント対象として公開する
17+
- `getStats` メソッドの返り値である `Statistics` のドキュメントを生成するため
18+
- @t-miya
19+
- [ADD] MediaChannel に libwebrtc の統計情報を取得する `getStats` メソッドを追加する
20+
- @t-miya
1621

1722
## 2025.2.0
1823

Sora/MediaChannel.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,58 @@ public final class MediaChannel {
442442
}
443443
}
444444

445+
/// libwebrtc の統計情報を取得します。
446+
/// 非同期取得中に切断された場合でも安全になるよう、コールバック内で
447+
/// self の生存確認、state == .connected の再確認、peerChannel.nativeChannel が同一インスタンスかどうか、をチェックしています。
448+
///
449+
/// - parameter handler: 統計情報取得後に呼ばれるクロージャー
450+
public func getStats(handler: @escaping (Result<Statistics, Error>) -> Void) {
451+
guard state == .connected else {
452+
let message = "MediaChannel is not connected (state: \(state))"
453+
Logger.debug(type: .mediaChannel, message: message)
454+
handler(.failure(SoraError.peerChannelError(reason: message)))
455+
return
456+
}
457+
458+
guard let peerConnection = peerChannel.nativeChannel else {
459+
let message =
460+
"RTCPeerConnection is unavailable (state: \(state), nativeChannel: nil)"
461+
Logger.debug(type: .mediaChannel, message: message)
462+
handler(.failure(SoraError.peerChannelError(reason: message)))
463+
return
464+
}
465+
466+
// peerConnection.statistics クロージャはlibwebrtc 側のスレッドから遅れて呼ばれ、内部で MediaChannel をキャプチャします。
467+
// ここで self を強参照すると、MediaChannel が切断・解放されたあとでもクロージャが解放されず、deinit が遅れたり循環参照が発生する恐れがあります。
468+
// そのため [weak self] でキャプチャし、呼び出し時点で MediaChannel がまだ有効かどうかをチェックしています。
469+
// self が解放済みなら MediaChannel is unavailable エラーを返すことで安全に処理を抜けます。
470+
peerConnection.statistics { [weak self] report in
471+
guard let self else {
472+
handler(.failure(SoraError.peerChannelError(reason: "MediaChannel is unavailable")))
473+
return
474+
}
475+
476+
guard self.state == .connected else {
477+
let message = "MediaChannel is not connected (state: \(self.state))"
478+
Logger.debug(type: .mediaChannel, message: message)
479+
handler(.failure(SoraError.peerChannelError(reason: message)))
480+
return
481+
}
482+
483+
guard let currentPeerConnection = self.peerChannel.nativeChannel,
484+
currentPeerConnection === peerConnection
485+
else {
486+
let message =
487+
"RTCPeerConnection is unavailable (state: \(self.state), nativeChannel changed)"
488+
Logger.debug(type: .mediaChannel, message: message)
489+
handler(.failure(SoraError.peerChannelError(reason: message)))
490+
return
491+
}
492+
493+
handler(.success(Statistics(contentsOf: report)))
494+
}
495+
}
496+
445497
/// DataChannel を利用してメッセージを送信します
446498
public func sendMessage(label: String, data: Data) -> Error? {
447499
guard peerChannel.switchedToDataChannel else {

Sora/Statistics.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import Foundation
22
import WebRTC
33

4-
/// :nodoc:
4+
/// WebRTC の統計情報を SDK から扱いやすい形にしたコンテナーです。
55
public class Statistics {
6+
/// 収集時刻 (μs)
67
public var timestamp: CFTimeInterval
8+
9+
/// 統計エントリーの一覧
710
public var entries: [StatisticsEntry] = []
811

912
init(contentsOf report: RTCStatisticsReport) {
@@ -14,6 +17,7 @@ public class Statistics {
1417
}
1518
}
1619

20+
/// JSON へシリアライズしやすい形式を返します。
1721
public var jsonObject: Any {
1822
let json = NSMutableArray()
1923
for entry in entries {
@@ -28,11 +32,18 @@ public class Statistics {
2832
}
2933
}
3034

31-
/// :nodoc:
35+
/// 単一の WebRTC 統計エントリーを表します。
3236
public class StatisticsEntry {
37+
/// エントリー ID
3338
public var id: String
39+
40+
/// 統計種別
3441
public var type: String
42+
43+
/// 測定時刻 (μs)
3544
public var timestamp: CFTimeInterval
45+
46+
/// 生の統計値
3647
public var values: [String: NSObject]
3748

3849
init(contentsOf statistics: RTCStatistics) {

0 commit comments

Comments
 (0)