Skip to content

Commit

Permalink
Merge pull request #39 from DolbyIO/feature/merge-debug-features-into…
Browse files Browse the repository at this point in the history
…-main

Merge debug features into main
  • Loading branch information
aravind-raveendran authored Oct 17, 2023
2 parents 36b3e97 + d301e72 commit 376ab33
Show file tree
Hide file tree
Showing 25 changed files with 628 additions and 211 deletions.
4 changes: 0 additions & 4 deletions Sources/DolbyIORTSCore/Builder/StreamSourceBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,6 @@ final class StreamSourceBuilder {
}

func build() throws -> StreamSource {
guard !hasMissingAudioTrack else {
throw BuildError.missingAudioTrack
}

guard !hasMissingVideoTrack, let videoTrack = videoTrack else {
throw BuildError.missingVideoTrack
}
Expand Down
29 changes: 28 additions & 1 deletion Sources/DolbyIORTSCore/Manager/MillicastLoggerHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,43 @@ import os
final class MillicastLoggerHandler: NSObject {

private static let logger = Logger.make(category: String(describing: MillicastLoggerHandler.self))

private var logFilePath: String?

override init() {
super.init()
MCLogger.setDelegate(self)
MCLogger.disableWebsocketLogs(true)
}

func setLogFilePath(filePath: String?) {
logFilePath = filePath
}
}

extension MillicastLoggerHandler: MCLoggerDelegate {
func onLog(withMessage message: String!, level: MCLogLevel) {
Self.logger.debug("🪵 onLog - \(message), log-level - \(level.rawValue)")

guard
let logFilePath = logFilePath,
let messageData = "\(String(describing: message))\n".data(using: .utf8)
else {
Self.logger.error("🪵 Error writing file - no file path provided")
return
}

let fileURL = URL(fileURLWithPath: logFilePath, isDirectory: false)
do {
if FileManager.default.fileExists(atPath: fileURL.path) {
let fileHandle = try FileHandle(forWritingTo: fileURL)
fileHandle.seekToEndOfFile()
fileHandle.write(messageData)
fileHandle.closeFile()
} else {
try messageData.write(to: fileURL, options: .atomicWrite)
}
} catch {
Self.logger.error("🪵 Error writing file - \(error.localizedDescription)")
}
}
}
32 changes: 12 additions & 20 deletions Sources/DolbyIORTSCore/Manager/SubscriptionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,13 @@ protocol SubscriptionManagerProtocol: AnyObject {
func unprojectAudio(for source: StreamSource)
}

struct SubscriptionConfiguration {
let autoReconnect = false
let videoJitterMinimumDelayMs: UInt = 20
let statsDelayMs: UInt = 1000
let forcePlayoutDelay = false
let disableAudio = false
let rtcEventLogOutputPath: String? = nil
}

final class SubscriptionManager: SubscriptionManagerProtocol {

private enum Defaults {
static let subscribeURL = "https://director.millicast.com/api/director/subscribe"
static let productionSubscribeURL = "https://director.millicast.com/api/director/subscribe"
static let developmentSubscribeURL = "https://director-dev.millicast.com/api/director/subscribe"
}

private static let logger = Logger.make(category: String(describing: SubscriptionManager.self))

private var subscriber: MCSubscriber!
Expand Down Expand Up @@ -99,7 +93,7 @@ final class SubscriptionManager: SubscriptionManagerProtocol {
return false
}

let credentials = self.makeCredentials(streamName: streamName, accountID: accountID)
let credentials = self.makeCredentials(streamName: streamName, accountID: accountID, useDevelopmentServer: configuration.useDevelopmentServer)

self.subscriber.setCredentials(credentials)

Expand Down Expand Up @@ -226,31 +220,29 @@ private extension SubscriptionManager {

func makeSubscriber(with configuration: SubscriptionConfiguration) -> MCSubscriber? {
let subscriber = MCSubscriber.create()

subscriber?.enableStats(true)


let options = MCClientOptions()
options.autoReconnect = configuration.autoReconnect
options.videoJitterMinimumDelayMs = Int32(configuration.videoJitterMinimumDelayMs)
options.videoJitterMinimumDelayMs = Int32(configuration.videoJitterMinimumDelayInMs)
options.statsDelayMs = Int32(configuration.statsDelayMs)
if let rtcEventLogOutputPath = configuration.rtcEventLogOutputPath {
if let rtcEventLogOutputPath = configuration.rtcEventLogPath {
options.rtcEventLogOutputPath = rtcEventLogOutputPath
}
options.disableAudio = configuration.disableAudio
options.forcePlayoutDelay = configuration.forcePlayoutDelay
options.forcePlayoutDelay = configuration.noPlayoutDelay

subscriber?.setOptions(options)
subscriber?.enableStats(true)
subscriber?.enableStats(configuration.enableStats)

return subscriber
}

func makeCredentials(streamName: String, accountID: String) -> MCSubscriberCredentials {
func makeCredentials(streamName: String, accountID: String, useDevelopmentServer: Bool) -> MCSubscriberCredentials {
let credentials = MCSubscriberCredentials()
credentials.accountId = accountID
credentials.streamName = streamName
credentials.token = ""
credentials.apiUrl = Defaults.subscribeURL
credentials.apiUrl = useDevelopmentServer ? Defaults.developmentSubscribeURL : Defaults.productionSubscribeURL

return credentials
}
Expand Down
1 change: 0 additions & 1 deletion Sources/DolbyIORTSCore/Model/StreamDetail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ public struct StreamDetail: Equatable, Identifiable {
public let id = UUID()
public let streamName: String
public let accountID: String
public var streamId: String { "\(self.accountID)/\(self.streamName)" }

public init(streamName: String, accountID: String) {
self.streamName = streamName
Expand Down
13 changes: 9 additions & 4 deletions Sources/DolbyIORTSCore/Model/StreamState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ public enum StreamState: Equatable {
self = .connected

case let .subscribed(state):
self = .subscribed(
sources: state.sources,
numberOfStreamViewers: state.numberOfStreamViewers
)
let streamSources = state.sources
if !streamSources.isEmpty {
self = .subscribed(
sources: streamSources,
numberOfStreamViewers: state.numberOfStreamViewers
)
} else {
self = .error(.connectFailed(reason: ""))
}

case .stopped:
self = .stopped
Expand Down
83 changes: 59 additions & 24 deletions Sources/DolbyIORTSCore/Model/StreamingStatistics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,46 @@
import Foundation
import MillicastSDK

public struct AllStreamingStatistics : Equatable, Hashable {
public struct StreamingStatistics : Equatable, Hashable {
public let roundTripTime: Double?
public var videoStatsInboundRtpList: [StatsInboundRtp]?
public var audioStatsInboundRtpList: [StatsInboundRtp]?
public var videoStatsInboundRtp: StatsInboundRtp?
public var audioStatsInboundRtp: StatsInboundRtp?
}

public struct StreamingStatistics : Equatable, Hashable {
public struct AllStreamStatistics : Equatable, Hashable {
public let roundTripTime: Double?
public let audioStatsInboundRtp: StatsInboundRtp?
public let videoStatsInboundRtp: StatsInboundRtp?
public var videoStatsInboundRtpList: [StatsInboundRtp]
public var audioStatsInboundRtpList: [StatsInboundRtp]
}

public struct StatsInboundRtp : Equatable, Hashable {
public let sid: String
public let kind: String
public let sid: String
public let mid: String
public let decoderImplementation: String?
public let trackIdentifier: String
public let decoder: String?
public let processingDelay: Double
public let decodeTime: Double
public let frameWidth: Int
public let frameHeight: Int
public let fps: Int
public let audioLevel: Int
public let totalEnergy: Double
public let framesReceived: Int
public let framesDecoded: Int
public let framesDropped: Int
public let jitterBufferEmittedCount: Int
public let jitterBufferDelay: Double
public let jitterBufferTargetDelay: Double
public let jitterBufferMinimumDelay: Double
public let nackCount: Int
public let bytesReceived: Int
public let totalSampleDuration: Double
public let codec: String?
public let jitter: Double
public let packetsReceived: Double
public let packetsLost: Double
public let packetsReceived: Int
public let packetsLost: Int
public let timestamp: Double
public var codecName: String?

Expand All @@ -44,7 +53,7 @@ public struct StatsInboundRtp : Equatable, Hashable {
}
}

extension AllStreamingStatistics {
extension AllStreamStatistics {
init?(_ report: MCStatsReport) {
let receivedType = MCRemoteInboundRtpStreamStats.get_type()
guard let remoteInboundStreamStatsList = report.getStatsOf(receivedType) as? [MCRemoteInboundRtpStreamStats] else {
Expand All @@ -60,50 +69,76 @@ extension AllStreamingStatistics {
let codecType = MCCodecsStats.get_type()
let codecStatsList = report.getStatsOf(codecType) as? [MCCodecsStats]

videoStatsInboundRtpList = [StatsInboundRtp]()
let videos = inboundRtpStreamStatsList
.filter { $0.kind == "video" }
.map {
StatsInboundRtp($0, codecStatsList: codecStatsList)
}
videoStatsInboundRtpList = [StatsInboundRtp]()
audioStatsInboundRtpList = [StatsInboundRtp]()
videoStatsInboundRtpList?.append(contentsOf: videos)
videoStatsInboundRtpList.append(contentsOf: videos)

audioStatsInboundRtpList = [StatsInboundRtp]()
let audios = inboundRtpStreamStatsList
.filter { $0.kind == "audio" }
.map {
StatsInboundRtp($0, codecStatsList: codecStatsList)
}
audioStatsInboundRtpList?.append(contentsOf: audios)
audioStatsInboundRtpList.append(contentsOf: audios)
}
}

extension StatsInboundRtp {
init(_ stats: MCInboundRtpStreamStats, codecStatsList: [MCCodecsStats]?) {
sid = stats.sid as String
kind = stats.kind as String
sid = stats.sid as String
mid = stats.mid as String
decoder = stats.decoder_implementation as String?
decoderImplementation = stats.decoder_implementation as String?
frameWidth = Int(stats.frame_width)
frameHeight = Int(stats.frame_height)
fps = Int(stats.frames_per_second)
audioLevel = Int(stats.audio_level)
totalEnergy = stats.total_audio_energy
bytesReceived = Int(stats.bytes_received)
framesReceived = Int(stats.frames_received)
packetsReceived = Int(stats.packets_received)
framesDecoded = Int(stats.frames_decoded)
framesDropped = Int(stats.frames_dropped)
jitterBufferEmittedCount = Int(stats.jitter_buffer_emitted_count)
jitter = stats.jitter * 1000
processingDelay = Self.msNormalised(
numerator: stats.total_processing_delay,
denominator: stats.frames_decoded
)
decodeTime = Self.msNormalised(
numerator: stats.total_decode_time,
denominator: stats.frames_decoded
)
jitterBufferDelay = Self.msNormalised(
numerator: stats.jitter_buffer_delay,
denominator: stats.jitter_buffer_emitted_count
)
jitterBufferTargetDelay = Self.msNormalised(
numerator: stats.jitter_buffer_target_delay,
denominator: stats.jitter_buffer_emitted_count
)
jitterBufferMinimumDelay = Self.msNormalised(
numerator: stats.jitter_buffer_minimum_delay,
denominator: stats.jitter_buffer_emitted_count
)
nackCount = Int(stats.nack_count)
bytesReceived = Int(stats.bytes_received)
packetsLost = Int(stats.packets_lost)
trackIdentifier = stats.track_identifier as String
decoder = stats.decoder_implementation as String?
audioLevel = Int(stats.audio_level)
totalEnergy = stats.total_audio_energy
totalSampleDuration = stats.total_samples_duration
codec = stats.codec_id as String?
jitter = stats.jitter
packetsReceived = Double(stats.packets_received)
packetsLost = Double(stats.packets_lost)
timestamp = Double(stats.timestamp)

if let codecStats = codecStatsList?.first(where: { $0.sid == stats.codec_id }) {
codecName = codecStats.mime_type as String
} else {
codecName = nil
}
}

private static func msNormalised(numerator: Double, denominator: UInt) -> Double {
denominator == 0 ? 0 : numerator * 1000 / Double(denominator)
}
}
49 changes: 49 additions & 0 deletions Sources/DolbyIORTSCore/Model/SubscriptionConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// SubscriptionConfiguration.swift
//

import Foundation

public struct SubscriptionConfiguration {
public enum Constants {
public static let useDevelopmentServer = false
public static let autoReconnect = true
public static let videoJitterMinimumDelayInMs: UInt = 20
public static let statsDelayMs: UInt = 1000
public static let noPlayoutDelay = false
public static let disableAudio = false
public static let enableStats = true
}

public let useDevelopmentServer: Bool
public let autoReconnect: Bool
public let videoJitterMinimumDelayInMs: UInt
public let statsDelayMs: UInt
public let noPlayoutDelay: Bool
public let disableAudio: Bool
public let rtcEventLogPath: String?
public let sdkLogPath: String?
public let enableStats: Bool

public init(
useDevelopmentServer: Bool = Constants.useDevelopmentServer,
autoReconnect: Bool = Constants.autoReconnect,
videoJitterMinimumDelayInMs: UInt = Constants.videoJitterMinimumDelayInMs,
statsDelayMs: UInt = Constants.statsDelayMs,
noPlayoutDelay: Bool = Constants.noPlayoutDelay,
disableAudio: Bool = Constants.disableAudio,
rtcEventLogPath: String? = nil,
sdkLogPath: String? = nil,
enableStats: Bool = Constants.enableStats
) {
self.useDevelopmentServer = useDevelopmentServer
self.autoReconnect = autoReconnect
self.videoJitterMinimumDelayInMs = videoJitterMinimumDelayInMs
self.statsDelayMs = statsDelayMs
self.noPlayoutDelay = noPlayoutDelay
self.disableAudio = disableAudio
self.rtcEventLogPath = rtcEventLogPath
self.sdkLogPath = sdkLogPath
self.enableStats = enableStats
}
}
7 changes: 6 additions & 1 deletion Sources/DolbyIORTSCore/Model/VideoQuality.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

import Foundation

public enum VideoQuality: Equatable {
public enum VideoQuality: String, Equatable, CaseIterable, Identifiable {

case auto
case high
case medium
Expand Down Expand Up @@ -35,4 +36,8 @@ public enum VideoQuality: Equatable {
return "Low"
}
}

public var id: String {
return rawValue
}
}
Loading

0 comments on commit 376ab33

Please sign in to comment.