Skip to content

Commit

Permalink
Update NetworkMonitoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
shogo4405 committed Aug 20, 2024
1 parent 1be51af commit 0cf042a
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 13 deletions.
4 changes: 2 additions & 2 deletions SRTHaishinKit/SRTStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ extension SRTStream: HKStream {
}
}

public func dispatch(_ event: NetworkMonitorEvent) {
bitrateStorategy?.adjustBitrate(event, stream: self)
public func dispatch(_ event: NetworkMonitorEvent) async {
await bitrateStorategy?.adjustBitrate(event, stream: self)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/HKStream/HKStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ public protocol HKStream: Actor, MediaMixerOutput {
func attachAudioPlayer(_ audioPlayer: AudioPlayer?)

/// Dispatch a network monitor event.
func dispatch(_ event: NetworkMonitorEvent)
func dispatch(_ event: NetworkMonitorEvent) async
}
65 changes: 63 additions & 2 deletions Sources/HKStream/HKStreamBitRateStrategy.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,73 @@
import Foundation

/// A type with a network bitrate strategy representation.
public protocol HKStreamBitRateStrategy {
public protocol HKStreamBitRateStrategy: Sendable {
/// The mamimum video bitRate.
var mamimumVideoBitRate: Int { get }
/// The mamimum audio bitRate.
var mamimumAudioBitRate: Int { get }

/// Adjust a bitRate.
func adjustBitrate(_ event: NetworkMonitorEvent, stream: some HKStream)
func adjustBitrate(_ event: NetworkMonitorEvent, stream: some HKStream) async
}

/// An actor provides an algorithm that focuses on video bitrate control.
public final actor HKStreamVideoAdaptiveBitRateStrategy: HKStreamBitRateStrategy {
/// The status counts threshold for restoring the status
public static let statusCountsThreshold: Int = 15

public let mamimumVideoBitRate: Int
public let mamimumAudioBitRate: Int = 0
private var sufficientBWCounts: Int = 0
private var zeroBytesOutPerSecondCounts: Int = 0

/// Creates a new instance.
public init(mamimumVideoBitrate: Int) {
self.mamimumVideoBitRate = mamimumVideoBitrate
}

public func adjustBitrate(_ event: NetworkMonitorEvent, stream: some HKStream) async {
switch event {
case .status:
var videoSettings = await stream.videoSettings
if videoSettings.bitRate == mamimumVideoBitRate {
return
}
if Self.statusCountsThreshold <= sufficientBWCounts {
let incremental = mamimumVideoBitRate / 10
videoSettings.bitRate = min(videoSettings.bitRate + incremental, mamimumVideoBitRate)
await stream.setVideoSettings(videoSettings)
sufficientBWCounts = 0
} else {
sufficientBWCounts += 1
}
case .publishInsufficientBWOccured(let report):
sufficientBWCounts = 0
var videoSettings = await stream.videoSettings
let audioSettings = await stream.audioSettings
if 0 < report.currentBytesOutPerSecond {
let bitRate = Int(report.currentBytesOutPerSecond * 8) / (zeroBytesOutPerSecondCounts + 1)
videoSettings.bitRate = max(bitRate - audioSettings.bitRate, mamimumVideoBitRate / 10)
videoSettings.frameInterval = 0.0
sufficientBWCounts = 0
zeroBytesOutPerSecondCounts = 0
} else {
switch zeroBytesOutPerSecondCounts {
case 2:
videoSettings.frameInterval = VideoCodecSettings.frameInterval10
case 4:
videoSettings.frameInterval = VideoCodecSettings.frameInterval05
default:
break
}
await stream.setVideoSettings(videoSettings)
zeroBytesOutPerSecondCounts += 1
}
case .reset:
var videoSettings = await stream.videoSettings
zeroBytesOutPerSecondCounts = 0
videoSettings.bitRate = mamimumVideoBitRate
await stream.setVideoSettings(videoSettings)
}
}
}
7 changes: 4 additions & 3 deletions Sources/Network/NetworkMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ public final actor NetworkMonitor {
previousTotalBytesOut = totalBytesOut
previousQueueBytesOut.append(queueBytesOut)
let eventReport = NetworkMonitorReport(
totalBytesIn: totalBytesIn,
totalBytesOut: totalBytesOut,
currentQueueBytesOut: queueBytesOut,
currentBytesInPerSecond: currentBytesInPerSecond,
currentBytesOutPerSecond: currentBytesOutPerSecond,
totalBytesIn: totalBytesIn
currentBytesOutPerSecond: currentBytesOutPerSecond
)
defer {
previousQueueBytesOut.removeFirst()
Expand All @@ -59,7 +60,7 @@ public final actor NetworkMonitor {
if total == measureInterval - 1 {
return .publishInsufficientBWOccured(report: eventReport)
} else if total == 0 {
return .publishSufficientBWOccured(report: eventReport)
return .status(report: eventReport)
}
}
return .status(report: eventReport)
Expand Down
6 changes: 5 additions & 1 deletion Sources/Network/NetworkMonitorEvent.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import Foundation

/// An enumeration that indicate the network monitor event.
public enum NetworkMonitorEvent: Sendable {
/// To update statistics.
case status(report: NetworkMonitorReport)
/// To publish sufficient bandwidth occured.
case publishInsufficientBWOccured(report: NetworkMonitorReport)
case publishSufficientBWOccured(report: NetworkMonitorReport)
/// To reset statistics.
case reset
}
6 changes: 5 additions & 1 deletion Sources/Network/NetworkMonitorReport.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import Foundation

/// The struct represents a network statistics.
public struct NetworkMonitorReport: Sendable {
/// The statistics of total incoming bytes.
public let totalBytesIn: Int
/// The statistics of total outgoing bytes.
public let totalBytesOut: Int
/// The statistics of outgoing queue bytes per second.
public let currentQueueBytesOut: Int
/// The statistics of incoming bytes per second.
public let currentBytesInPerSecond: Int
/// The statistics of outgoing bytes per second.
public let currentBytesOutPerSecond: Int
public let totalBytesIn: Int
}
6 changes: 5 additions & 1 deletion Sources/RTMP/RTMPConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ public actor RTMPConnection {
}
}
for stream in streams {
await stream.dispatch(.reset)
await stream.createStream()
}
return result
Expand Down Expand Up @@ -426,11 +427,14 @@ public actor RTMPConnection {

private func dispatch(_ event: NetworkMonitorEvent) {
switch event {
case .status(let report), .publishInsufficientBWOccured(let report), .publishSufficientBWOccured(let report):
case .status(let report), .publishInsufficientBWOccured(let report):
if windowSizeS * (sequence + 1) <= report.totalBytesIn {
doOutput(sequence == 0 ? .zero : .one, chunkStreamId: .control, message: RTMPAcknowledgementMessage(sequence: UInt32(report.totalBytesIn)))
sequence += 1
}
case .reset:
// noop
break
}
for stream in streams {
Task { await stream.dispatch(event) }
Expand Down
4 changes: 2 additions & 2 deletions Sources/RTMP/RTMPStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -763,8 +763,8 @@ extension RTMPStream: HKStream {
self.bitrateStorategy = bitrateStorategy
}

public func dispatch(_ event: NetworkMonitorEvent) {
bitrateStorategy?.adjustBitrate(event, stream: self)
public func dispatch(_ event: NetworkMonitorEvent) async {
await bitrateStorategy?.adjustBitrate(event, stream: self)
currentFPS = frameCount
frameCount = 0
info.update()
Expand Down

0 comments on commit 0cf042a

Please sign in to comment.