Skip to content

Commit

Permalink
[Fix]Thermal State not updating (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
ipavlidakis authored Oct 2, 2023
1 parent 444b579 commit 81523c9
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 4 deletions.
23 changes: 19 additions & 4 deletions Sources/StreamVideo/Utils/ThermalStateObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ extension LogSubsystem {
}

public final class ThermalStateObserver: ObservableObject {

public static let shared = ThermalStateObserver()

@Published public private(set) var state: ProcessInfo.ThermalState = .nominal {
/// Published property to observe the thermal state
@Published public private(set) var state: ProcessInfo.ThermalState {
didSet {
// Determine the appropriate log level based on the thermal state
let logLevel: LogLevel
switch state {
case .nominal, .fair:
Expand All @@ -26,6 +27,7 @@ public final class ThermalStateObserver: ObservableObject {
@unknown default:
logLevel = .debug
}
// Log the thermal state change with the calculated log level
log.log(
logLevel,
message: "Thermal state changed \(oldValue) → state",
Expand All @@ -35,20 +37,33 @@ public final class ThermalStateObserver: ObservableObject {
}
}

/// Cancellable object to manage notifications
private var notificationCenterCancellable: AnyCancellable?
private var thermalStateProvider: () -> ProcessInfo.ThermalState

convenience init() {
self.init { ProcessInfo.processInfo.thermalState }
}


init(thermalStateProvider: @escaping () -> ProcessInfo.ThermalState) {
// Initialize the thermal state with the current process's thermal state
self.state = thermalStateProvider()
self.thermalStateProvider = thermalStateProvider

private init() {
// Set up a publisher to monitor thermal state changes
notificationCenterCancellable = NotificationCenter
.default
.publisher(for: ProcessInfo.thermalStateDidChangeNotification)
.receive(on: DispatchQueue.global(qos: .utility))
.map { _ in ProcessInfo.processInfo.thermalState }
.map { [thermalStateProvider] _ in thermalStateProvider() }
.receive(on: DispatchQueue.main)
.assign(to: \.state, on: self)
}

/// Depending on the Device's thermal state we adapt the request participants resolution.
public var scale: CGFloat {
// Determine the appropriate scaling factor based on the thermal state
switch state {
case .nominal:
return 1
Expand Down
4 changes: 4 additions & 0 deletions StreamVideo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
400D63F72AC3273F0000BB30 /* ThermalStateObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400D63F62AC3273F0000BB30 /* ThermalStateObserverTests.swift */; };
401480302A5317640029166A /* AudioValuePercentageNormaliser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4014802F2A5317640029166A /* AudioValuePercentageNormaliser.swift */; };
401480342A5423D60029166A /* AudioValuePercentageNormaliser_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401480312A54238C0029166A /* AudioValuePercentageNormaliser_Tests.swift */; };
401480362A5447C50029166A /* LocalParticipantViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401480352A5447C50029166A /* LocalParticipantViewModifier.swift */; };
Expand Down Expand Up @@ -874,6 +875,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
400D63F62AC3273F0000BB30 /* ThermalStateObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThermalStateObserverTests.swift; sourceTree = "<group>"; };
4014802F2A5317640029166A /* AudioValuePercentageNormaliser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioValuePercentageNormaliser.swift; sourceTree = "<group>"; };
401480312A54238C0029166A /* AudioValuePercentageNormaliser_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioValuePercentageNormaliser_Tests.swift; sourceTree = "<group>"; };
401480352A5447C50029166A /* LocalParticipantViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalParticipantViewModifier.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2222,6 +2224,7 @@
84BB570D2A20D7BB0002C123 /* Mapping_Tests.swift */,
84A4DCBA2A41DC6E00B1D1BF /* AsyncAssert.swift */,
845E31072A712389004DC470 /* BroadcastUtils_Tests.swift */,
400D63F62AC3273F0000BB30 /* ThermalStateObserverTests.swift */,
);
path = Utils;
sourceTree = "<group>";
Expand Down Expand Up @@ -4214,6 +4217,7 @@
8492B87A29081E6600006649 /* StreamVideo_Mock.swift in Sources */,
84D6494729E9F2D0002CA428 /* WebRTCClient_Tests.swift in Sources */,
82E3BA532A0BAF4B001AB93E /* WebSocketClientEnvironment_Mock.swift in Sources */,
400D63F72AC3273F0000BB30 /* ThermalStateObserverTests.swift in Sources */,
8414081529F28FFC00FF2D7C /* CallSettings_Tests.swift in Sources */,
8492B87829081D1600006649 /* HTTPClient_Mock.swift in Sources */,
842747E729EECF9600E063AD /* ErrorPayload_Tests.swift in Sources */,
Expand Down
95 changes: 95 additions & 0 deletions StreamVideoTests/Utils/ThermalStateObserverTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// Copyright © 2023 Stream.io Inc. All rights reserved.
//

import Foundation
@testable import StreamVideo
import XCTest
import Combine

final class ThermalStateObserverTests: XCTestCase {

private var stubThermalState: ProcessInfo.ThermalState = .nominal
private lazy var subject: ThermalStateObserver! = .init { self.stubThermalState }

override func tearDown() {
subject = nil
super.tearDown()
}

// MARK: - init

func test_init_stateHasBeenCorrectlySetUp() {
XCTAssertEqual(ThermalStateObserver.shared.state, ProcessInfo.processInfo.thermalState)
}

// MARK: - notificationObserver

func test_notificationObserver_stateChangesWhenSystemPostsNotification() {
func assertThermalState(
_ expected: ProcessInfo.ThermalState,
file: StaticString = #file,
line: UInt = #line
) {
stubThermalState = expected

let expectation = self.expectation(description: "Notification was received")
var cancellable: AnyCancellable?
cancellable = subject
.$state
.dropFirst()
.sink {
XCTAssertEqual($0, expected, file: file, line: line)
expectation.fulfill()
cancellable?.cancel()
}

NotificationCenter
.default
.post(.init(name: ProcessInfo.thermalStateDidChangeNotification))

wait(for: [expectation], timeout: defaultTimeout)
}

assertThermalState(.fair)
assertThermalState(.serious)
assertThermalState(.critical)
assertThermalState(.nominal)
}

// MARK: - scale

func test_scale_hasExpectedValueForEachThermalState() {
func assertScale(
_ thermalState: ProcessInfo.ThermalState,
expected: CGFloat,
file: StaticString = #file,
line: UInt = #line
) {
stubThermalState = thermalState

let expectation = self.expectation(description: "Notification was received")
var cancellable: AnyCancellable?
cancellable = subject
.$state
.dropFirst()
.receive(on: DispatchQueue.main)
.sink { [subject] _ in
XCTAssertEqual(subject?.scale, expected, file: file, line: line)
expectation.fulfill()
cancellable?.cancel()
}

NotificationCenter
.default
.post(.init(name: ProcessInfo.thermalStateDidChangeNotification))

wait(for: [expectation], timeout: defaultTimeout)
}

assertScale(.nominal, expected: 1)
assertScale(.fair, expected: 1.5)
assertScale(.serious, expected: 2)
assertScale(.critical, expected: 4)
}
}

0 comments on commit 81523c9

Please sign in to comment.