Skip to content

Commit

Permalink
Fix: Layer selection logic for iOS and tvOS apps
Browse files Browse the repository at this point in the history
  • Loading branch information
aravind-raveendran committed Feb 6, 2024
1 parent 3fc3bba commit 317fadd
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,32 @@ extension RTSDataStore: SubscriptionManagerDelegate {
public func onStreamLayers(_ mid: String?, activeLayers: [MCLayerData]?, inactiveLayers: [String]?) {
Task {
await MainActor.run {
layerActiveMap = activeLayers?.filter { layer in
// For H.264 there are no temporal layers and the id is set to 255. For VP8 use the first temporal layer.
return layer.temporalLayerId == 0 || layer.temporalLayerId == 255
var layersForSelection: [MCLayerData] = []

// Simulcast active layers
if let simulcastLayers = activeLayers?.filter({ !$0.encodingId.isEmpty }), !simulcastLayers.isEmpty {
// Select the max (best) temporal layer Id from a specific encodingId
let dictionaryOfLayersMatchingEncodingId = Dictionary(grouping: simulcastLayers, by: { $0.encodingId })
dictionaryOfLayersMatchingEncodingId.forEach { (_: String, layers: [MCLayerData]) in
// Picking the layer matching the max temporal layer id - represents the layer with the best FPS
if let layerWithBestFrameRate = layers.first(where: { $0.temporalLayerId == $0.maxTemporalLayerId }) ?? layers.last {
layersForSelection.append(layerWithBestFrameRate)
}
}
layersForSelection.sort(by: >)
}
// Using SVC layer selection logic
else if let simulcastLayers = activeLayers?.filter({ $0.spatialLayerId != nil }) {
let dictionaryOfLayersMatchingSpatialLayerId = Dictionary(grouping: simulcastLayers, by: { $0.spatialLayerId! })
dictionaryOfLayersMatchingSpatialLayerId.forEach { (_: NSNumber, layers: [MCLayerData]) in
// Picking the layer matching the max temporal layer id - represents the layer with the best FPS
if let layerWithBestFrameRate = layers.first(where: { $0.spatialLayerId == $0.maxSpatialLayerId }) ?? layers.last {
layersForSelection.append(layerWithBestFrameRate)
}
}
}

layerActiveMap = layersForSelection
activeStreamType.removeAll()

switch layerActiveMap?.count {
Expand Down Expand Up @@ -341,3 +362,14 @@ extension RTSDataStore: SubscriptionManagerDelegate {
return codecStats.mime_type as String
}
}

extension MCLayerData: Comparable {
public static func < (lhs: MCLayerData, rhs: MCLayerData) -> Bool {
switch (lhs.encodingId.lowercased(), rhs.encodingId.lowercased()) {
case ("h", "m"), ("l", "m"), ("h", "s"), ("l", "s"), ("m", "s"):
return false
default:
return true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,32 @@ extension RTSDataStore: SubscriptionManagerDelegate {
public func onStreamLayers(_ mid: String?, activeLayers: [MCLayerData]?, inactiveLayers: [String]?) {
Task {
await MainActor.run {
layerActiveMap = activeLayers?.filter { layer in
// For H.264 there are no temporal layers and the id is set to 255. For VP8 use the first temporal layer.
return layer.temporalLayerId == 0 || layer.temporalLayerId == 255
var layersForSelection: [MCLayerData] = []

// Simulcast active layers
if let simulcastLayers = activeLayers?.filter({ !$0.encodingId.isEmpty }), !simulcastLayers.isEmpty {
// Select the max (best) temporal layer Id from a specific encodingId
let dictionaryOfLayersMatchingEncodingId = Dictionary(grouping: simulcastLayers, by: { $0.encodingId })
dictionaryOfLayersMatchingEncodingId.forEach { (_: String, layers: [MCLayerData]) in
// Picking the layer matching the max temporal layer id - represents the layer with the best FPS
if let layerWithBestFrameRate = layers.first(where: { $0.temporalLayerId == $0.maxTemporalLayerId }) ?? layers.last {
layersForSelection.append(layerWithBestFrameRate)
}
}
layersForSelection.sort(by: >)
}
// Using SVC layer selection logic
else if let simulcastLayers = activeLayers?.filter({ $0.spatialLayerId != nil }) {
let dictionaryOfLayersMatchingSpatialLayerId = Dictionary(grouping: simulcastLayers, by: { $0.spatialLayerId! })
dictionaryOfLayersMatchingSpatialLayerId.forEach { (_: NSNumber, layers: [MCLayerData]) in
// Picking the layer matching the max temporal layer id - represents the layer with the best FPS
if let layerWithBestFrameRate = layers.first(where: { $0.spatialLayerId == $0.maxSpatialLayerId }) ?? layers.last {
layersForSelection.append(layerWithBestFrameRate)
}
}
}

layerActiveMap = layersForSelection

activeStreamType.removeAll()

Expand Down Expand Up @@ -341,3 +363,14 @@ extension RTSDataStore: SubscriptionManagerDelegate {
return codecStats.mime_type as String
}
}

extension MCLayerData: Comparable {
public static func < (lhs: MCLayerData, rhs: MCLayerData) -> Bool {
switch (lhs.encodingId.lowercased(), rhs.encodingId.lowercased()) {
case ("h", "m"), ("l", "m"), ("h", "s"), ("l", "s"), ("m", "s"):
return false
default:
return true
}
}
}

0 comments on commit 317fadd

Please sign in to comment.