Skip to content

Commit

Permalink
Merge pull request #80 from AgoraIO-Community/uikit-logging
Browse files Browse the repository at this point in the history
4.0.1 Bump

- Bump to RTC 4.0.1
- Added missing documentation
- Added mediaOptions to join channel methods
  • Loading branch information
maxxfrazer authored Oct 7, 2022
2 parents 5907bf8 + dd46375 commit d549f82
Show file tree
Hide file tree
Showing 14 changed files with 95 additions and 68 deletions.
1 change: 0 additions & 1 deletion .github/workflows/deploy_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ jobs:
uses: actions/checkout@v3
- name: Build DocC 🛠
run: |
sudo xcode-select -s /Applications/Xcode_14.0.app;
xcodebuild docbuild -scheme AgoraUIKit -derivedDataPath /tmp/docbuild -destination 'generic/platform=iOS';
$(xcrun --find docc) process-archive \
transform-for-static-hosting /tmp/docbuild/Build/Products/Debug-iphoneos/AgoraUIKit.doccarchive \
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/swift-build-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ jobs:
DESTINATION: 'generic/platform=iOS'
- name: Pod Lint 🔎
run: pod lib lint AgoraUIKit_iOS.podspec --allow-warnings --skip-import-validation --include-podspecs='AgoraRtmControl_iOS.podspec'
- name: Print Version 🔤
run: |
echo '### Build passed :rocket:' >> $GITHUB_STEP_SUMMARY
echo "Version: $(grep 'static let version' Sources/Agora-Video-UIKit/AgoraUIKit.swift | sed -e 's,.*\"\(.*\)\",\1,')" >> $GITHUB_STEP_SUMMARY
2 changes: 1 addition & 1 deletion AgoraRtmControl_iOS.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Pod::Spec.new do |s|
s.name = 'AgoraRtmControl_iOS'
s.module_name = 'AgoraRtmControl'
s.version = ENV['LIB_VERSION'] || '4.0.0'
s.version = ENV['LIB_VERSION'] || '4.0.1'
s.summary = 'Agora Real-time Messaging Wrapper.'

s.description = <<-DESC
Expand Down
4 changes: 2 additions & 2 deletions AgoraUIKit_iOS.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Pod::Spec.new do |s|
s.name = 'AgoraUIKit_iOS'
s.module_name = 'AgoraUIKit'
s.version = ENV['LIB_VERSION'] || '4.0.0'
s.version = ENV['LIB_VERSION'] || '4.0.1'
s.summary = 'Agora video session UIKit template.'

s.description = <<-DESC
Expand All @@ -26,7 +26,7 @@ Use this Pod to create a video UIKit view that can be easily added to your iOS a

s.static_framework = true
s.source_files = 'Sources/Agora-Video-UIKit/*'
s.dependency 'AgoraRtcEngine_iOS', '4.0.0.4'
s.dependency 'AgoraRtcEngine_iOS', '~> 4.0.1'
s.dependency 'AgoraRtmControl_iOS', "#{s.version.to_s}"

end
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let package = Package(
.package(
name: "AgoraRtcKit",
url: "https://github.com/AgoraIO/AgoraRtcEngine_iOS",
revision: "4.0.0-r.4"
.upToNextMinor(from: Version(4, 0, 1))
),
.package(
name: "AgoraRtmKit",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Agora UIKit for iOS
# Agora Video UI Kit for iOS

<p align="center">
<img src="https://github.com/AgoraIO-Community/VideoUIKit-iOS/actions/workflows/swift-build-lint.yml/badge.svg"/>
Expand Down
8 changes: 5 additions & 3 deletions Sources/Agora-Video-UIKit/AgoraCollectionViewer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import UIKit
import AppKit
#endif

/// Collection View to display all connected users camera feeds
public class AgoraCollectionViewer: MPCollectionView {
/// Collection View to display all connected users camera feeds. Used in the streamerCollectionView.
internal class AgoraCollectionViewer: MPCollectionView {

static let cellSpacing: CGFloat = 5
public static var flowLayout: MPCollectionViewFlowLayout {

/// Details for the collection list of participants camera feeds.
static var flowLayout: MPCollectionViewFlowLayout {
let flowLayout = MPCollectionViewFlowLayout()
flowLayout.itemSize = CGSize(width: 100, height: 100)
flowLayout.scrollDirection = .horizontal
Expand Down
11 changes: 11 additions & 0 deletions Sources/Agora-Video-UIKit/AgoraSingleVideoView+RtmDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,21 @@ public protocol SingleVideoViewDelegate: AnyObject {
#if canImport(AgoraRtmControl)
/// RTM Controller class for managing RTM messages
var rtmController: AgoraRtmController? { get set }
/// Create and send request to user to mute/unmute a device
/// - Parameters:
/// - uid: RTM User ID to send the request to
/// - str: String from the action label to
/// - Returns: Boolean stating if the request was valid or not
func createRequest(
to uid: UInt,
fromString str: String
) -> Bool
/// Create and send request to mute/unmute a device
/// - Parameters:
/// - rtcId: RTC User ID to send the request to
/// - mute: Whether the device should be muted or unmuted
/// - device: Type of device (camera/microphone)
/// - isForceful: Whether the request should force its way through, otherwise a request is made. Cannot forcefully unmute.
func sendMuteRequest(to rtcId: UInt, mute: Bool, device: AgoraVideoViewer.MutingDevices, isForceful: Bool)

#endif
Expand Down
36 changes: 26 additions & 10 deletions Sources/Agora-Video-UIKit/AgoraUIKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,64 @@
import Foundation
import AgoraRtcKit

/// Agora UIKit data structure. Access `AgoraUIKit.current` for information
/// about your UIKit version.
/// Agora UIKit data structure. Access ``AgoraUIKit/AgoraUIKit/current`` for information
/// about your Video UI Kit version.
public struct AgoraUIKit: Codable {
/// Instance of the current AgoraUIKit instance.
public static var current: AgoraUIKit {
AgoraUIKit(version: AgoraUIKit.version, platform: AgoraUIKit.platform, framework: AgoraUIKit.framework)
}
/// Platform that is being used: ios, macos, android, unknown
fileprivate(set) var platform: String
public fileprivate(set) var platform: String
/// Version of UIKit being used
fileprivate(set) var version: String
public fileprivate(set) var version: String
/// Framework type of UIKit. "native", "flutter", "reactnative"
fileprivate(set) var framework: String
public fileprivate(set) var framework: String
/// Version of UIKit being used
static let version = "4.0.0"
public static let version = "4.0.1"
/// Framework type of UIKit. "native", "flutter", "reactnative"
static let framework = "native"
public static let framework = "native"
#if os(iOS)
/// Platform that is being used: ios, macos, android, unknown
static let platform = "ios"
public static let platform = "ios"
#elseif os(macOS)
/// Platform that is being used: ios, macos, android, unknown
static let platform = "macos"
public static let platform = "macos"
#else
/// Platform that is being used: ios, macos, android, unknown
static let platform = "unknown"
public static let platform = "unknown"
#endif
fileprivate init(version: String, platform: String, framework: String) {
self.version = version
self.platform = platform
self.framework = framework
}
/// Get the Video UI Kit details in a pretty printed string format. Used for print statements.
/// - Returns: String of the version, platform and framework.
func prettyPrint() -> String {
"""
version: \(version)
platform: \(platform)
framework: \(framework)
"""
}
/// Initialiser from a decoder. Used for internal purposes only
/// - Parameter decoder: Decoder object that is used to set all the properties.
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.platform = try container.decode(String.self, forKey: .platform)
self.version = try container.decode(String.self, forKey: .version)
self.framework = try container.decode(String.self, forKey: .framework)
}
/// Converts an unsigned UInt32 to a regular signed Int. This is to handle User Id's across multiple platforms.
/// - Parameter uint: Unigned integer userId
/// - Returns: Signed integer userId
public static func uintToInt(_ uint: UInt) -> Int {
Int(Int32(bitPattern: UInt32(uint)))
}
/// Converts a regular Int to an unsigned UInt32. This is to handle User Id's across multiple platforms.
/// - Parameter userInt: Signed integer userId
/// - Returns: Unsigned integer userId
public static func intToUInt(_ userInt: Int) -> UInt {
UInt(UInt32(bitPattern: Int32(userInt)))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// AgoraVideoViewer.swift
// AgoraVideoViewer+AgoraExtensions.swift
// Agora-Video-UIKit
//
// Created by Max Cobb on 09/09/2021.
Expand Down
7 changes: 7 additions & 0 deletions Sources/Agora-Video-UIKit/AgoraVideoViewer+Token.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ extension AgoraVideoViewer {
case invalidURL
}

/// Update the token currently in use by the Agora SDK. Used to not interrupt an active video session.
/// - Parameter newToken: new token to be applied to the current connection.
@objc open func updateToken(_ newToken: String) {
self.currentRtcToken = newToken
self.agkit.renewToken(newToken)
}

/// Requests the token from our backend token service
/// - Parameter urlBase: base URL specifying where the token server is located
/// - Parameter channelName: Name of the channel we're requesting for
Expand Down
58 changes: 23 additions & 35 deletions Sources/Agora-Video-UIKit/AgoraVideoViewer+VideoControl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ extension AgoraVideoViewer {
self.agkit.setExternalVideoSource(
agoraSettings.externalVideoSettings.enabled,
useTexture: agoraSettings.externalVideoSettings.texture,
// encodedFrame: agoraSettings.externalVideoSettings.encoded
sourceType: agoraSettings.externalVideoSettings.encoded ? .encodedVideoFrame : .videoFrame
)
if self.agoraSettings.externalAudioSettings.enabled {
Expand Down Expand Up @@ -52,17 +51,12 @@ extension AgoraVideoViewer {
!self.checkPermissions(
mediaType: .video,
callback: { err in
if err == nil {
if err == nil { // if permissions are now granted
DispatchQueue.main.async {
// if permissions are now granted
self.setCam(to: enabled, completion: completion)
}
} else {
completion?(false)
}
}) {
return
}
} else { completion?(false) }
}) { return }
self.agoraSettings.cameraEnabled = enabled
self.agkit.enableLocalVideo(enabled)

Expand Down Expand Up @@ -100,14 +94,11 @@ extension AgoraVideoViewer {
completion?(true)
return
}
if enabled,
self.connectionData.channel != nil,
!self.checkPermissions(
if enabled, self.connectionData.channel != nil, !self.checkPermissions(
mediaType: .audio,
callback: { err in
if err == nil {
if err == nil { // if permissions are now granted
DispatchQueue.main.async {
// if permissions are now granted
self.setMic(to: enabled, completion: completion)
}
} else { completion?(false) }
Expand Down Expand Up @@ -154,7 +145,6 @@ extension AgoraVideoViewer {
ssButton.backgroundColor = ssButton.isSelected ? .systemGreen : .systemGray
#elseif os(macOS)
ssButton.layer?.backgroundColor = (ssButton.isOn ? NSColor.systemGreen : NSColor.systemGray).cgColor

if ssButton.isOn { self.startSharingScreen()
} else { self.agkit.stopScreenCapture() }
#endif
Expand All @@ -174,7 +164,6 @@ extension AgoraVideoViewer {
parameters.bitrate = 1000
parameters.captureMouseCursor = true
self.agkit.startScreenCapture(byDisplayId: UInt32(displayId), regionRect: rectangle, captureParams: parameters)
// self.agkit.setScreenCaptureContentHint(contentHint)
#endif
}

Expand Down Expand Up @@ -250,13 +239,15 @@ extension AgoraVideoViewer {
/// A token will only be fetched if a token URL is provided in AgoraSettings.
/// Default: `false`
/// - uid: UID to be set when user joins the channel, default will be 0.
/// - mediaOptions: Media options such as custom audio/video tracks, subscribing options etc.
public func join(
channel: String, as role: AgoraClientRole = .broadcaster,
fetchToken: Bool = false, uid: UInt? = nil
fetchToken: Bool = false, uid: UInt? = nil,
mediaOptions: AgoraRtcChannelMediaOptions? = nil
) {
if self.connectionData == nil { fatalError("No app ID is provided") }
guard fetchToken else {
self.join(channel: channel, with: self.currentRtcToken, as: role, uid: uid)
self.join(channel: channel, with: self.currentRtcToken, as: role, uid: uid, mediaOptions: mediaOptions)
return
}
if let tokenURL = self.agoraSettings.tokenURL {
Expand All @@ -266,7 +257,7 @@ extension AgoraVideoViewer {
switch result {
case .success(let token):
DispatchQueue.main.async {
self.join(channel: channel, with: token, as: role, uid: uid)
self.join(channel: channel, with: token, as: role, uid: uid, mediaOptions: mediaOptions)
}
case .failure(let err):
AgoraVideoViewer.agoraPrint(.error, message: "Could not fetch token from server: \(err)")
Expand All @@ -283,24 +274,28 @@ extension AgoraVideoViewer {
/// - token: Valid token to join the channel
/// - role: [AgoraClientRole](https://docs.agora.io/en/Video/API%20Reference/oc/Constants/AgoraClientRole.html) to join the channel as. Default: `.broadcaster`
/// - uid: UID to be set when user joins the channel, default will be 0.
/// - mediaOptions: Media options such as custom audio/video tracks, subscribing options etc.
/// - Returns: `Int32?` representing Agora's joinChannelByToken response. If response is `nil`,
/// that means it has continued on another thread, or you area already in the channel.
@discardableResult
public func join(
channel: String, with token: String?,
as role: AgoraClientRole = .broadcaster, uid: UInt? = nil
as role: AgoraClientRole = .broadcaster, uid: UInt? = nil,
mediaOptions: AgoraRtcChannelMediaOptions? = nil
) -> Int32? {
if self.connectionData == nil { fatalError("No app ID is provided") }
if role == .broadcaster {
if !self.checkForPermissions(self.activePermissions, callback: { error in
if error != nil { return }
DispatchQueue.main.async {
self.join(channel: channel, with: token, as: role, uid: uid)
self.join(channel: channel, with: token, as: role, uid: uid, mediaOptions: mediaOptions)
}
}) { return nil }
}
if self.connectionData.channel != nil {
self.handleAlreadyInChannel(channel: channel, with: token, as: role, uid: uid)
self.handleAlreadyInChannel(
channel: channel, with: token, as: role, uid: uid, mediaOptions: mediaOptions
)
return nil
}
self.userRole = role
Expand All @@ -315,9 +310,8 @@ extension AgoraVideoViewer {
byToken: token,
channelId: channel,
uid: self.userID,
mediaOptions: AgoraRtcChannelMediaOptions()
)
// Delegate method is called upon success
mediaOptions: mediaOptions ?? AgoraRtcChannelMediaOptions()
) // Delegate method is called upon success
}

#if canImport(AgoraRtmControl)
Expand Down Expand Up @@ -346,15 +340,16 @@ extension AgoraVideoViewer {

internal func handleAlreadyInChannel(
channel: String, with token: String?,
as role: AgoraClientRole = .broadcaster, uid: UInt? = nil
as role: AgoraClientRole = .broadcaster, uid: UInt? = nil,
mediaOptions: AgoraRtcChannelMediaOptions? = nil
) {
if self.connectionData.channel == channel {
AgoraVideoViewer.agoraPrint(.verbose, message: "We are already in a channel")
}
if self.leaveChannel() < 0 {
AgoraVideoViewer.agoraPrint(.error, message: "Could not leave current channel")
} else {
self.join(channel: channel, with: token, as: role, uid: uid)
self.join(channel: channel, with: token, as: role, uid: uid, mediaOptions: mediaOptions)
}
}

Expand Down Expand Up @@ -385,15 +380,8 @@ extension AgoraVideoViewer {
return leaveChannelRtn
}

/// Update the token currently in use by the Agora SDK. Used to not interrupt an active video session.
/// - Parameter newToken: new token to be applied to the current connection.
@objc open func updateToken(_ newToken: String) {
self.currentRtcToken = newToken
self.agkit.renewToken(newToken)
}

/// Leave any open channels and kills the Agora Engine instance.
@objc open func exit() {
@objc open func exit(stopPreview: Bool = true) {
self.leaveChannel(stopPreview: true)
AgoraRtcEngineKit.destroy()
}
Expand Down
Loading

0 comments on commit d549f82

Please sign in to comment.