Skip to content

Commit

Permalink
updated engine property to agoraEngine, lowered compatability of rtc …
Browse files Browse the repository at this point in the history
…engine, updated video streaming article, and inline docs
  • Loading branch information
maxxfrazer committed Jul 6, 2023
1 parent b074005 commit 07dcb0b
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 136 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ let package = Package(
.library(name: "SwiftUIRtc", targets: ["SwiftUIRtc"]),
],
dependencies: [
.package(url: "https://github.com/AgoraIO/AgoraRtcEngine_iOS", from: "4.1.0"),
.package(url: "https://github.com/AgoraIO/AgoraRtcEngine_iOS", from: "4.0.0"),
],
targets: [
.target(
Expand Down
140 changes: 69 additions & 71 deletions Sources/SwiftUIRtc/AgoraManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,114 +8,112 @@
import Foundation
import AgoraRtcKit

/**
* ``AgoraManager`` is a class that provides an interface to the Agora RTC Engine Kit.
* It conforms to the `ObservableObject` and `AgoraRtcEngineDelegate` protocols.
*
* Use AgoraManager to set up and manage Agora RTC sessions, manage the client's role,
* and control the * client's connection to the Agora RTC server.
* */
/// ``AgoraManager`` is a class that provides an interface to the Agora RTC Engine Kit.
/// It conforms to the `ObservableObject` and `AgoraRtcEngineDelegate` protocols.
///
/// Use AgoraManager to set up and manage Agora RTC sessions, manage the client's role,
/// and control the client's connection to the Agora RTC server.
open class AgoraManager: NSObject, ObservableObject, AgoraRtcEngineDelegate {
/// The Agora App ID for the session.
public let appId: String
/// The client's role in the session.
public var role: AgoraClientRole = .audience {
didSet { engine.setClientRole(role) }
didSet { agoraEngine.setClientRole(role) }
}
/// Integer ID of the local user.
@Published public private(set) var localUserId: UInt = 0
@Published public var localUserId: UInt = 0
/// The Agora RTC Engine Kit for the session.
public var engine: AgoraRtcEngineKit {
public var agoraEngine: AgoraRtcEngineKit {
let eng = AgoraRtcEngineKit.sharedEngine(withAppId: appId, delegate: self)
eng.enableVideo()
eng.setClientRole(role)
return eng
}
@available(*, deprecated, renamed: "agoraEngine")
public var engine: AgoraRtcEngineKit { self.agoraEngine }

/// The set of all users in the channel.
@Published public var allUsers: Set<UInt> = []

/**
* Initializes a new instance of `AgoraManager` with the specified app ID and client role.
*
* - Parameters:
* - appId: The Agora App ID for the session.
* - role: The client's role in the session. The default value is `.audience`.
*/
/// Initializes a new instance of `AgoraManager` with the specified app ID and client role.
///
/// - Parameters:
/// - appId: The Agora App ID for the session.
/// - role: The client's role in the session. The default value is `.audience`.
public init(appId: String, role: AgoraClientRole = .audience) {
self.appId = appId
self.role = role
}

/**
* Joins a channel, starting the connection to an RTC session.
* - Parameters:
* - channel: Name of the channel to join.
* - token: Token to join the channel, this can be nil for an weak security testing session.
* - uid: User ID of the local user. This can be 0 to allow the engine to automatically assign an ID.
* - info: Info is currently unused by RTC, it is reserved for future use.
*/
open func joinChannel(_ channel: String, token: String? = nil, uid: UInt = 0, info: String? = nil) {
self.engine.joinChannel(byToken: token, channelId: channel, info: info, uid: uid)
/// Joins a channel, starting the connection to an RTC session.
/// - Parameters:
/// - channel: Name of the channel to join.
/// - token: Token to join the channel, this can be nil for an weak security testing session.
/// - uid: User ID of the local user. This can be 0 to allow the engine to automatically assign an ID.
/// - info: Info is currently unused by RTC, it is reserved for future use.
/// - Returns: 0 if no error joining channel, &lt; 0 if there was an error.
@discardableResult
open func joinChannel(
_ channel: String, token: String? = nil, uid: UInt = 0, info: String? = nil
) -> Int32 {
self.agoraEngine.joinChannel(byToken: token, channelId: channel, info: info, uid: uid)
}

/**
* Leaves the channel and stops the preview for the session.
*
* - Parameter leaveChannelBlock: An optional closure that will be called when the client leaves the channel.
* The closure takes an * `AgoraChannelStats` object as its parameter.
*
*
* This method also empties all entries in ``allUsers``,
*/
open func leaveChannel(leaveChannelBlock: ((AgoraChannelStats) -> Void)? = nil) {
self.engine.leaveChannel(leaveChannelBlock)
self.engine.stopPreview()
AgoraRtcEngineKit.destroy()
/// Leaves the channel and stops the preview for the session.
///
/// - Parameter leaveChannelBlock: An optional closure that will be called when the client leaves the channel.
/// The closure takes an `AgoraChannelStats` object as its parameter.
///
/// This method also empties all entries in ``allUsers``,
@discardableResult
open func leaveChannel(
leaveChannelBlock: ((AgoraChannelStats) -> Void)? = nil
) -> Int32 {
let leaveErr = self.agoraEngine.leaveChannel(leaveChannelBlock)
self.agoraEngine.stopPreview()
defer { AgoraRtcEngineKit.destroy() }
self.allUsers.removeAll()
return leaveErr
}

/**
* The delegate is telling us that the local user has successfully joined the channel.
* - Parameters:
* - engine: The Agora RTC engine kit object.
* - channel: The channel name.
* - uid: The ID of the user joining the channel.
* - elapsed: The time elapsed (ms) from the user calling `joinChannel` until this method is called.
*
* If the client's role is `.broadcaster`, this method also adds the broadcaster's userId (``localUserId``) to the ``allUsers`` set.
*/
open func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
/// The delegate is telling us that the local user has successfully joined the channel.
/// - Parameters:
/// - engine: The Agora RTC engine kit object.
/// - channel: The channel name.
/// - uid: The ID of the user joining the channel.
/// - elapsed: The time elapsed (ms) from the user calling `joinChannel` until this method is called.
///
/// If the client's role is `.broadcaster`, this method also adds the broadcaster's userId (``localUserId``) to the ``allUsers`` set.
open func rtcEngine(
_ engine: AgoraRtcEngineKit, didJoinChannel channel: String,
withUid uid: UInt, elapsed: Int
) {
self.localUserId = uid
if self.role == .broadcaster {
self.allUsers.insert(uid)
}
}

/**
* The delegate is telling us that a remote user has joined the channel.
*
* - Parameters:
* - engine: The Agora RTC engine kit object.
* - uid: The ID of the user joining the channel.
* - elapsed: The time elapsed (ms) from the user calling `joinChannel` until this method is called.
*
* This method adds the remote user to the `allUsers` set.
*/
/// The delegate is telling us that a remote user has joined the channel.
///
/// - Parameters:
/// - engine: The Agora RTC engine kit object.
/// - uid: The ID of the user joining the channel.
/// - elapsed: The time elapsed (ms) from the user calling `joinChannel` until this method is called.
///
/// This method adds the remote user to the `allUsers` set.
open func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
self.allUsers.insert(uid)
}

/**
* The delegate is telling us that a remote user has left the channel.
*
* - Parameters:
* - engine: The Agora RTC engine kit object.
* - uid: The ID of the user who left the channel.
* - reason: The reason why the user left the channel.
*
* This method removes the remote user from the `allUsers` set.
*/
/// The delegate is telling us that a remote user has left the channel.
///
/// - Parameters:
/// - engine: The Agora RTC engine kit object.
/// - uid: The ID of the user who left the channel.
/// - reason: The reason why the user left the channel.
///
/// This method removes the remote user from the `allUsers` set.
open func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
self.allUsers.remove(uid)
}
Expand Down
85 changes: 37 additions & 48 deletions Sources/SwiftUIRtc/AgoraVideoCanvasView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,24 @@ extension AgoraRtcVideoCanvas: ObservableObject {}
/// while avoiding a strong dependency on ``AgoraManager``.
public protocol CanvasViewHelper: AnyObject {
/// Instance of the Agora RTC Engine
var engine: AgoraRtcEngineKit { get }
var agoraEngine: AgoraRtcEngineKit { get }
/// Id of the local user in the channel.
var localUserId: UInt { get }
}

/// Add the ``CanvasViewHelper`` protocol to ``AgoraManager``.
extension AgoraManager: CanvasViewHelper {}

/**
* AgoraVideoCanvasView is a UIViewRepresentable struct that provides a view for displaying remote or local video in an Agora RTC session.
*
* Use AgoraVideoCanvasView to create a view that displays the video stream from a remote user or the local user's camera in an Agora RTC session.
* You can specify the render mode, crop area, and setup mode for the view.
*/
/// AgoraVideoCanvasView is a UIViewRepresentable struct that provides a view for displaying remote or local video in an Agora RTC session.
///
/// Use AgoraVideoCanvasView to create a view that displays the video stream from a remote user or the local user's camera in an Agora RTC session.
/// You can specify the render mode, crop area, and setup mode for the view.
public struct AgoraVideoCanvasView: VIEW_REP {
/// The `AgoraRtcVideoCanvas` object that represents the video canvas for the view.
@StateObject var canvas = AgoraRtcVideoCanvas()

/**
* Reference to a protocol ``CanvasViewHelper`` that helps with fetching the engine instance,
* as well as the local user's ID. ``AgoraManager`` conforms to this protocol.
*/
/// Reference to a protocol ``CanvasViewHelper`` that helps with fetching the engine instance, as well as the local user's ID.
/// ``AgoraManager`` conforms to this protocol.
public weak var manager: CanvasViewHelper?
/// The user ID of the remote user whose video to display, or `0` to display the local user's video.
public let uid: UInt
Expand All @@ -57,18 +54,16 @@ public struct AgoraVideoCanvasView: VIEW_REP {
/// The setup mode for the view.
public var setupMode: AgoraVideoViewSetupMode = .replace

/**
* Create a new AgoraRtcVideoCanvas, for displaying a remote or local video stream in a SwiftUI view.
*
* - Parameters:
* - manager: An instance of an object that conforms to ``CanvasViewHelper``, such as ``AgoraManager``.
* - uid: The user ID for the video stream.
* - renderMode: The render mode for the video stream, which determines how the video is scaled and displayed.
* - cropArea: The portion of the video stream to display, specified as a CGRect with values between 0 and 1.
* - setupMode: The mode for setting up the video view, which determines whether to replace or merge with existing views.
*
* - Returns: An AgoraVideoCanvasView instance, which can be added to a SwiftUI view hierarchy.
*/
/// Create a new AgoraRtcVideoCanvas, for displaying a remote or local video stream in a SwiftUI view.
///
/// - Parameters:
/// - manager: An instance of an object that conforms to ``CanvasViewHelper``, such as ``AgoraManager``.
/// - uid: The user ID for the video stream.
/// - renderMode: The render mode for the video stream, which determines how the video is scaled and displayed.
/// - cropArea: The portion of the video stream to display, specified as a CGRect with values between 0 and 1.
/// - setupMode: The mode for setting up the video view, which determines whether to replace or merge with existing views.
///
/// - Returns: An AgoraVideoCanvasView instance, which can be added to a SwiftUI view hierarchy.
public init(
manager: CanvasViewHelper, uid: UInt,
renderMode: AgoraVideoRenderMode = .hidden,
Expand All @@ -86,24 +81,20 @@ public struct AgoraVideoCanvasView: VIEW_REP {
self.uid = uid
}
#if os(macOS)
/**
* Creates and configures a `NSView` for the view. This UIView will be the view the video is rendered onto.
*
* - Parameter context: The `NSViewRepresentable` context.
*
* - Returns: A `NSView` for displaying the video stream.
*/
/// Creates and configures a `NSView` for the view. This UIView will be the view the video is rendered onto.
///
/// - Parameter context: The `NSViewRepresentable` context.
///
/// - Returns: A `NSView` for displaying the video stream.
public func makeNSView(context: Context) -> VIEW_CLASS {
setupCanvasView()
}
#elseif os(iOS)
/**
* Creates and configures a `UIView` for the view. This UIView will be the view the video is rendered onto.
*
* - Parameter context: The `UIViewRepresentable` context.
*
* - Returns: A `UIView` for displaying the video stream.
*/
/// Creates and configures a `UIView` for the view. This UIView will be the view the video is rendered onto.
///
/// - Parameter context: The `UIViewRepresentable` context.
///
/// - Returns: A `UIView` for displaying the video stream.
public func makeUIView(context: Context) -> VIEW_CLASS {
setupCanvasView()
}
Expand All @@ -119,17 +110,15 @@ public struct AgoraVideoCanvasView: VIEW_REP {
canvasView.isHidden = false
if self.uid == self.manager?.localUserId {
// Start the local video preview
manager?.engine.startPreview()
manager?.engine.setupLocalVideo(canvas)
manager?.agoraEngine.startPreview()
manager?.agoraEngine.setupLocalVideo(canvas)
} else {
manager?.engine.setupRemoteVideo(canvas)
manager?.agoraEngine.setupRemoteVideo(canvas)
}
return canvasView
}

/**
* Updates the `AgoraRtcVideoCanvas` object for the view with new values, if necessary.
*/
/// Updates the `AgoraRtcVideoCanvas` object for the view with new values, if necessary.
func updateCanvasValues() {
if canvas.renderMode == renderMode, canvas.cropArea == cropArea, canvas.setupMode == setupMode {
return
Expand All @@ -139,13 +128,13 @@ public struct AgoraVideoCanvasView: VIEW_REP {
if canvas.cropArea != cropArea { canvas.cropArea = cropArea }
if canvas.setupMode != setupMode { canvas.setupMode = setupMode }

if self.uid == 0 { manager?.engine.setupLocalVideo(canvas)
} else { manager?.engine.setupRemoteVideo(canvas) }
if self.canvas.uid == self.uid { return }
self.canvas.uid = self.uid
if self.uid == self.manager?.localUserId { manager?.agoraEngine.setupLocalVideo(canvas)
} else { self.manager?.agoraEngine.setupRemoteVideo(canvas) }
}

/**
* Updates the Canvas view.
*/
/// Updates the Canvas view.
#if os(iOS)
public func updateUIView(_ uiView: VIEW_CLASS, context: Context) {
self.updateCanvasValues()
Expand Down
Loading

0 comments on commit 07dcb0b

Please sign in to comment.