-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4ea71ae
commit e211a41
Showing
40 changed files
with
2,321 additions
and
319 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
LocalPackages/RTSCore/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
File renamed without changes.
Large diffs are not rendered by default.
Oops, something went wrong.
7 changes: 4 additions & 3 deletions
7
rts-viewer-tvos/RTSViewer.xcworkspace/xcshareddata/swiftpm/Package.resolved
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
{ | ||
"originHash" : "55c5bb51783dcbfad1b8b5bd2888d3846f22b84ddc7759242400a1260ba1846f", | ||
"pins" : [ | ||
{ | ||
"identity" : "millicast-sdk-swift-package", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/millicast/millicast-sdk-swift-package", | ||
"state" : { | ||
"revision" : "d20cb45ff24acbc16191d4df6a0e4be9daa26e24", | ||
"version" : "2.0.0-beta.7" | ||
"revision" : "a36748fd8b8d8fe8d94608f42972e5002d2dd9f5", | ||
"version" : "2.0.0" | ||
} | ||
} | ||
], | ||
"version" : 2 | ||
"version" : 3 | ||
} |
This file was deleted.
Oops, something went wrong.
395 changes: 395 additions & 0 deletions
395
rts-viewer-tvos/RTSViewer/Managers/VideoTracksManager.swift
Large diffs are not rendered by default.
Oops, something went wrong.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// | ||
// SourcedChannel.swift | ||
// | ||
|
||
import Combine | ||
import Foundation | ||
import os | ||
import RTSCore | ||
|
||
class Channel: ObservableObject, Identifiable, Hashable, Equatable { | ||
private static let logger = Logger( | ||
subsystem: Bundle.main.bundleIdentifier!, | ||
category: String(describing: Channel.self) | ||
) | ||
|
||
@Published var currentlyFocusedChannel: Channel? { | ||
didSet { | ||
guard let currentlyFocusedChannel else { return } | ||
isFocusedChannel = currentlyFocusedChannel.id == id | ||
} | ||
} | ||
|
||
@Published var isFocusedChannel: Bool = false { | ||
didSet { | ||
if isFocusedChannel { | ||
enableSound() | ||
} else { | ||
disableSound() | ||
} | ||
} | ||
} | ||
|
||
@Published private(set) var streamStatistics: StreamStatistics? | ||
@Published var showStatsView: Bool = false | ||
@Published var videoQualityList = [VideoQuality]() | ||
@Published var selectedVideoQuality: VideoQuality = .auto | ||
|
||
let id: UUID | ||
let streamConfig: StreamConfig | ||
let subscriptionManager: SubscriptionManager | ||
let videoTracksManager: VideoTracksManager | ||
let source: StreamSource | ||
private var cancellables = [AnyCancellable]() | ||
private var layersEventsObserver: Task<Void, Never>? | ||
|
||
init(unsourcedChannel: UnsourcedChannel, source: StreamSource) { | ||
self.id = unsourcedChannel.id | ||
self.streamConfig = unsourcedChannel.streamConfig | ||
self.subscriptionManager = unsourcedChannel.subscriptionManager | ||
self.videoTracksManager = unsourcedChannel.videoTracksManager | ||
self.source = source | ||
|
||
observeStreamStatistics() | ||
observeLayerEvents() | ||
startSelectedQualityObserver() | ||
} | ||
|
||
func shouldShowStatsView(showStats: Bool) { | ||
showStatsView = showStats | ||
} | ||
|
||
func enableVideo(with quality: VideoQuality = .auto) { | ||
let displayLabel = source.sourceId.displayLabel | ||
let viewId = "\(ChannelGridView.self).\(displayLabel)" | ||
Task { | ||
Self.logger.debug("♼ Channel Grid view: Video view appear for \(self.source.sourceId)") | ||
await self.videoTracksManager.enableTrack(for: self.source, with: quality, on: viewId) | ||
} | ||
} | ||
|
||
func disableVideo() { | ||
let displayLabel = source.sourceId.displayLabel | ||
let viewId = "\(ChannelGridView.self).\(displayLabel)" | ||
Task { | ||
Self.logger.debug("♼ Channel Grid view: Video view disappear for \(self.source.sourceId)") | ||
await self.videoTracksManager.disableTrack(for: self.source, on: viewId) | ||
} | ||
} | ||
|
||
func enableSound() { | ||
Task { | ||
try? await self.source.audioTrack?.enable() | ||
Self.logger.debug("♼ Channel \(self.source.sourceId) audio enabled") | ||
} | ||
} | ||
|
||
func disableSound() { | ||
Task { | ||
try? await self.source.audioTrack?.disable() | ||
Self.logger.debug("♼ Channel \(self.source.sourceId) audio disabled") | ||
} | ||
} | ||
|
||
func updateFocusedChannel(with channel: Channel) { | ||
currentlyFocusedChannel = channel | ||
} | ||
|
||
static func == (lhs: Channel, rhs: Channel) -> Bool { | ||
return lhs.id == rhs.id | ||
} | ||
|
||
func hash(into hasher: inout Hasher) { | ||
return hasher.combine(id) | ||
} | ||
} | ||
|
||
private extension Channel { | ||
func observeStreamStatistics() { | ||
Task { [weak self] in | ||
guard let self else { return } | ||
await subscriptionManager.$streamStatistics | ||
.sink { statistics in | ||
guard let statistics else { return } | ||
Task { | ||
self.streamStatistics = statistics | ||
} | ||
} | ||
.store(in: &cancellables) | ||
} | ||
} | ||
|
||
func observeLayerEvents() { | ||
Task { [weak self] in | ||
guard let self, | ||
layersEventsObserver == nil else { return } | ||
|
||
Self.logger.debug("♼ Registering layer events for \(source.sourceId)") | ||
let layerEventsObservationTask = Task { | ||
for await layerEvent in self.source.videoTrack.layers() { | ||
guard !Task.isCancelled else { return } | ||
|
||
let videoQualities = layerEvent.layers() | ||
.map(VideoQuality.init) | ||
.reduce([.auto]) { $0 + [$1] } | ||
Self.logger.debug("♼ Received layers \(videoQualities.count)") | ||
self.videoQualityList = videoQualities | ||
} | ||
} | ||
|
||
layersEventsObserver = layerEventsObservationTask | ||
|
||
_ = await layerEventsObservationTask.value | ||
} | ||
} | ||
|
||
func startSelectedQualityObserver() { | ||
Task { [weak self] in | ||
guard let self else { return } | ||
await self.videoTracksManager.selectedVideoQualityPublisher | ||
.map { $0[self.source.sourceId] ?? .auto } | ||
.receive(on: DispatchQueue.main) | ||
.sink { quality in | ||
self.selectedVideoQuality = quality | ||
} | ||
.store(in: &cancellables) | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// | ||
// PlayFromConfigs.swift | ||
// | ||
|
||
import Foundation | ||
|
||
struct StreamConfig { | ||
let apiUrl: String | ||
let streamName: String | ||
let accountId: String | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// UnsourcedChannel.swift | ||
// | ||
|
||
import Foundation | ||
import RTSCore | ||
|
||
struct UnsourcedChannel: Identifiable, Hashable, Equatable { | ||
let id = UUID() | ||
let streamConfig: StreamConfig | ||
let subscriptionManager: SubscriptionManager | ||
let videoTracksManager: VideoTracksManager | ||
|
||
static func == (lhs: UnsourcedChannel, rhs: UnsourcedChannel) -> Bool { | ||
return lhs.id == rhs.id | ||
} | ||
|
||
public func hash(into hasher: inout Hasher) { | ||
return hasher.combine(id) | ||
} | ||
} |
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
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
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
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
Oops, something went wrong.