Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement]Handle video property on VoIP push notification #641

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@ fileprivate func content() {
callType: .default,
callId: UUID().uuidString,
members: [.init(userId: name)],
ring: true
ring: true,

// hasVideo: A boolean indicating if the call
// will be video or only audio. Still requires
// appropriate setting of ``CallSettings`.`
video: true
)
}
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/StreamVideo/Call.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ public class Call: @unchecked Sendable, WSEventsSubscriber {
/// - maxDuration: An optional integer representing the maximum duration of the call in seconds.
/// - maxParticipants: An optional integer representing the maximum number of participants allowed in the call.
/// - backstage: An optional backstage request.
/// - video: A boolean indicating if the call will be video or only audio. Still requires appropriate
/// setting of ``CallSettings`.`
/// - Returns: A `CallResponse` object representing the created call.
/// - Throws: An error if the call creation fails.
@discardableResult
Expand All @@ -238,7 +240,8 @@ public class Call: @unchecked Sendable, WSEventsSubscriber {
notify: Bool = false,
maxDuration: Int? = nil,
maxParticipants: Int? = nil,
backstage: BackstageSettingsRequest? = nil
backstage: BackstageSettingsRequest? = nil,
video: Bool? = nil
) async throws -> CallResponse {
var membersRequest = [MemberRequest]()
memberIds?.forEach {
Expand Down Expand Up @@ -268,7 +271,8 @@ public class Call: @unchecked Sendable, WSEventsSubscriber {
members: membersRequest,
settingsOverride: settingsOverride,
startsAt: startsAt,
team: team
team: team,
video: video
),
notify: notify,
ring: ring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,26 @@ open class CallKitPushNotificationAdapter: NSObject, PKPushRegistryDelegate, Obs
case displayName = "call_display_name"
case createdByName = "created_by_display_name"
case createdById = "created_by_id"
case video
}

/// Represents the content of a VoIP push notification.
public struct Content {
var cid: String
var localizedCallerName: String
var callerId: String
var hasVideo: Bool

public init(
cid: String,
localizedCallerName: String,
callerId: String
callerId: String,
hasVideo: Bool
) {
self.cid = cid
self.localizedCallerName = localizedCallerName
self.callerId = callerId
self.hasVideo = hasVideo
}
}

Expand Down Expand Up @@ -107,6 +111,7 @@ open class CallKitPushNotificationAdapter: NSObject, PKPushRegistryDelegate, Obs
content.cid,
localizedCallerName: content.localizedCallerName,
callerId: content.callerId,
hasVideo: content.hasVideo,
completion: { error in
if let error {
log.error(error)
Expand All @@ -130,7 +135,8 @@ open class CallKitPushNotificationAdapter: NSObject, PKPushRegistryDelegate, Obs
return .init(
cid: "unknown",
localizedCallerName: defaultCallText,
callerId: defaultCallText
callerId: defaultCallText,
hasVideo: false
)
}

Expand All @@ -148,10 +154,21 @@ open class CallKitPushNotificationAdapter: NSObject, PKPushRegistryDelegate, Obs
fallback: defaultCallText
)

let hasVideo: Bool = {
if let booleanValue = streamDict[PayloadKey.video.rawValue] as? Bool {
return booleanValue
} else if let stringValue = streamDict[PayloadKey.video.rawValue] as? String {
return stringValue == "true"
} else {
return false
}
}()

return .init(
cid: cid,
localizedCallerName: localizedCallerName,
callerId: callerId
callerId: callerId,
hasVideo: hasVideo
)
}
}
Expand Down
11 changes: 8 additions & 3 deletions Sources/StreamVideo/CallKit/CallKitService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,21 @@ open class CallKitService: NSObject, CXProviderDelegate, @unchecked Sendable {
/// - cid: The call ID.
/// - localizedCallerName: The localized caller name.
/// - callerId: The caller's identifier.
/// - hasVideo: Indicator if call is video or audio.
/// - completion: A closure to be called upon completion.
@MainActor
open func reportIncomingCall(
ipavlidakis marked this conversation as resolved.
Show resolved Hide resolved
_ cid: String,
localizedCallerName: String,
callerId: String,
hasVideo: Bool = false,
completion: @escaping (Error?) -> Void
) {
let (callUUID, callUpdate) = buildCallUpdate(
cid: cid,
localizedCallerName: localizedCallerName,
callerId: callerId
callerId: callerId,
hasVideo: hasVideo
)

callProvider.reportNewIncomingCall(
Expand All @@ -136,6 +139,7 @@ open class CallKitService: NSObject, CXProviderDelegate, @unchecked Sendable {
cid:\(cid)
callerId:\(callerId)
callerName:\(localizedCallerName)
hasVideo: \(hasVideo)
"""
)

Expand Down Expand Up @@ -573,7 +577,8 @@ open class CallKitService: NSObject, CXProviderDelegate, @unchecked Sendable {
private func buildCallUpdate(
cid: String,
localizedCallerName: String,
callerId: String
callerId: String,
hasVideo: Bool
) -> (UUID, CXCallUpdate) {
let update = CXCallUpdate()
let idComponents = cid.components(separatedBy: ":")
Expand All @@ -589,7 +594,7 @@ open class CallKitService: NSObject, CXProviderDelegate, @unchecked Sendable {

update.localizedCallerName = localizedCallerName
update.remoteHandle = CXHandle(type: .generic, value: callerId)
update.hasVideo = supportsVideo
update.hasVideo = hasVideo
update.supportsDTMF = false

if supportsHolding {
Expand Down
8 changes: 6 additions & 2 deletions Sources/StreamVideoSwiftUI/CallViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ open class CallViewModel: ObservableObject {
/// - maxParticipants: An optional integer representing the maximum number of participants allowed in the call.
/// - startsAt: An optional date when the call starts.
/// - backstage: An optional request for setting up backstage.
/// - video: A boolean indicating if the call will be video or only audio. Still requires appropriate
/// setting of ``CallSettings`.`
public func startCall(
callType: String,
callId: String,
Expand All @@ -337,7 +339,8 @@ open class CallViewModel: ObservableObject {
maxParticipants: Int? = nil,
startsAt: Date? = nil,
backstage: BackstageSettingsRequest? = nil,
customData: [String: RawJSON]? = nil
customData: [String: RawJSON]? = nil,
video: Bool? = nil
) {
outgoingCallMembers = members
callingState = ring ? .outgoing : .joining
Expand Down Expand Up @@ -368,7 +371,8 @@ open class CallViewModel: ObservableObject {
custom: customData,
ring: ring,
maxDuration: maxDuration,
maxParticipants: maxParticipants
maxParticipants: maxParticipants,
video: video
)
let timeoutSeconds = TimeInterval(
callData.settings.ring.autoCancelTimeoutMs / 1000
Expand Down
3 changes: 2 additions & 1 deletion Sources/StreamVideoSwiftUI/Models/CallEventsHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public class CallEventsHandler {
caller: caller,
type: type,
members: members,
timeout: TimeInterval(ringEvent.call.settings.ring.autoCancelTimeoutMs / 1000)
timeout: TimeInterval(ringEvent.call.settings.ring.autoCancelTimeoutMs / 1000),
video: ringEvent.video
)
return .incoming(incomingCall)
case let .typeCallSessionStartedEvent(callSessionStartedEvent):
Expand Down
5 changes: 4 additions & 1 deletion Sources/StreamVideoSwiftUI/Models/IncomingCall.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@ public struct IncomingCall: Identifiable, Sendable, Equatable {
public let type: String
public let members: [Member]
public let timeout: TimeInterval
public let video: Bool

public init(
id: String,
caller: User,
type: String,
members: [Member],
timeout: TimeInterval
timeout: TimeInterval,
video: Bool = false
) {
self.id = id
self.caller = caller
self.type = type
self.members = members
self.timeout = timeout
self.video = video
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ final class IncomingCallView_Tests: StreamVideoUITestCase {
caller: members.first!.user,
type: callType,
members: members,
timeout: 15000
timeout: 15000,
video: false
)
let view = IncomingCallView(
callInfo: callInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ final class CallKitPushNotificationAdapterTests: XCTestCase {
.init(
cid: "123",
localizedCallerName: "TestUser",
callerId: "test_user"
callerId: "test_user",
hasVideo: false
)
)
}
Expand All @@ -109,7 +110,8 @@ final class CallKitPushNotificationAdapterTests: XCTestCase {
.init(
cid: "123",
localizedCallerName: "TestUser",
callerId: "test_user"
callerId: "test_user",
hasVideo: false
),
displayName: "Stream Group Call"
)
Expand All @@ -132,7 +134,7 @@ final class CallKitPushNotificationAdapterTests: XCTestCase {
) {
let pushPayload = MockPKPushPayload()
pushPayload.stubType = contentType
pushPayload.stubDictionaryPayload = content.map { [
var payload: [String: Any] = content.map { [
"stream": [
"call_cid": $0.cid,
"call_display_name": displayName,
Expand All @@ -141,6 +143,13 @@ final class CallKitPushNotificationAdapterTests: XCTestCase {
]
] } ?? [:]

if let hasVideo = content?.hasVideo, var streamPayload = payload["stream"] as? [String: Any] {
streamPayload["video"] = hasVideo
payload["stream"] = streamPayload
}

pushPayload.stubDictionaryPayload = payload

let completionWasCalledExpectation = expectation(description: "Completion was called.")
completionWasCalledExpectation.isInverted = content == nil
subject.pushRegistry(
Expand Down Expand Up @@ -169,6 +178,12 @@ final class CallKitPushNotificationAdapterTests: XCTestCase {
file: file,
line: line
)
XCTAssertEqual(
callKitService.reportIncomingCallWasCalled?.hasVideo,
content.hasVideo,
file: file,
line: line
)
callKitService.reportIncomingCallWasCalled?.completion(nil)
} else {
XCTAssertNil(
Expand Down
Loading
Loading