Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
maxxfrazer committed Mar 24, 2023
0 parents commit 620969a
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 0 deletions.
50 changes: 50 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# OS X
.DS_Store

# Xcode
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
*.xccheckout
profile
*.moved-aside
DerivedData
*.hmap
*.ipa

# Bundler
.bundle

# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Note: if you ignore the Pods directory, make sure to uncomment
# `pod install` in .travis.yml
#
Pods/
Podfile.lock
*.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
.build/
xcshareddata/
Package.resolved

docs/
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 AgoraIO Community

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
24 changes: 24 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "AgoraVideoSwiftUI",
platforms: [.iOS(.v13)],
products: [
.library(name: "AgoraVideoSwiftUI", targets: ["AgoraVideoSwiftUI"]),
],
dependencies: [
.package(url: "https://github.com/AgoraIO/AgoraRtcEngine_iOS", from: "4.1.1"),
],
targets: [
.target(
name: "AgoraVideoSwiftUI",
dependencies: [.product(name: "RtcBasic", package: "AgoraRtcEngine_iOS")]
),
.testTarget(
name: "AgoraVideoSwiftUITests",
dependencies: ["AgoraVideoSwiftUI"]),
]
)
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# AgoraVideoSwiftUI

AgoraVideoSwiftUI is a package for building video call apps using the Agora RTC SDK and SwiftUI. It provides a set of SwiftUI views and classes that simplify setting up and managing Agora RTC sessions for video calls.

## Installation

AgoraVideoSwiftUI can be installed using Swift Package Manager in Xcode. Simply add the package to your project by navigating to File > Swift Packages > Add Package Dependency and entering the repository URL:

```
```


## Usage

To use AgoraVideoSwiftUI in your SwiftUI project, simply import the package and use the provided views and classes. For example, you can use `AgoraVideoCanvasView` and `AgoraManager` view to render all the video streams in an Agora RTC session:

```swift
import AgoraVideoSwiftUI
import AgoraRtcKit

struct AgoraGettingStartedView: View {
@ObservedObject var agoraManager = GettingStartedManager(appId: <#AppId#>, role: .broadcaster)
var channelId: String = "test"
var body: some View {
ScrollView {
VStack {
ForEach(Array(agoraManager.allUsers), id: \.self) { uid in
AgoraVideoCanvasView(agoraKit: agoraManager.engine, uid: uid)
.aspectRatio(contentMode: .fit).cornerRadius(10)
}
}.padding(20)
}.onAppear {
agoraManager.engine.joinChannel(
byToken: <#Agora Temp Token#>, channelId: channelId, info: nil, uid: 0
)
}.onDisappear {
agoraManager.engine.leaveChannel()
}
}
}

// To show and hide all the users in the channel, we need to make a small subclass of AgoraManager.
class GettingStartedManager: AgoraManager {
@Published var allUsers: Set<UInt> = []
override func leaveChannel(leaveChannelBlock: ((AgoraChannelStats) -> Void)? = nil) {
allUsers.removeAll()
super.leaveChannel(leaveChannelBlock: leaveChannelBlock)
}
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
if self.role == .broadcaster {
self.allUsers.insert(0)
}
}
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
self.allUsers.insert(uid)
}
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
self.allUsers.remove(uid)
}
}

```

## Contributing

Contributions to AgoraVideoSwiftUI are welcome! If you encounter any issues or have feature requests, please submit an issue on the GitHub repository. Pull requests are also welcome.

## License

AgoraVideoSwiftUI is available under the MIT license. See the [LICENSE](LICENSE) file for more information.
54 changes: 54 additions & 0 deletions Sources/AgoraVideoSwiftUI/AgoraManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// AgoraManager.swift
//
//
// Created by Max Cobb on 24/03/2023.
//

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.
*/
open class AgoraManager: NSObject, ObservableObject, AgoraRtcEngineDelegate {
/// The Agora App ID for the session.
var appId: String
/// The client's role in the session.
var role: AgoraClientRole = .audience {
didSet { engine.setClientRole(role) }
}
/// The Agora RTC Engine Kit for the session.
var engine: AgoraRtcEngineKit {
let eng = AgoraRtcEngineKit.sharedEngine(withAppId: appId, delegate: self)
eng.enableVideo()
eng.setClientRole(role)
return eng
}

/**
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`.
*/
init(appId: String, role: AgoraClientRole = .audience) {
self.appId = appId
self.role = role
}

/**
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.
*/
func leaveChannel(leaveChannelBlock: ((AgoraChannelStats) -> Void)? = nil) {
self.engine.leaveChannel(leaveChannelBlock)
self.engine.stopPreview()
AgoraRtcEngineKit.destroy()
}
}

94 changes: 94 additions & 0 deletions Sources/AgoraVideoSwiftUI/AgoraVideoCanvasView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// SwiftUIView.swift
//
//
// Created by Max Cobb on 24/03/2023.
//

import SwiftUI
import AgoraRtcKit

extension AgoraRtcVideoCanvas: ObservableObject {
/// This could be used instead of UIView directly, if the canvas view also needs to retain its state in SwiftUI
// class CanvasView: UIView, ObservableObject {}
}

/**
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: UIViewRepresentable {
/// The `AgoraRtcVideoCanvas` object that represents the video canvas for the view.
@StateObject var canvas = AgoraRtcVideoCanvas()

/// A weak reference to the `AgoraRtcEngineKit` object for the session.
weak var agoraKit: AgoraRtcEngineKit?

/// The user ID of the remote user whose video to display, or `0` to display the local user's video.
let uid: UInt

/// The render mode for the view.
var renderMode: AgoraVideoRenderMode = .hidden

/// The crop area for the view.
var cropArea: CGRect = .zero

/// The setup mode for the view.
var setupMode: AgoraVideoViewSetupMode = .replace

/**
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) -> UIView {
// Create and return the remote video view
let canvasView = UIView()
canvas.view = canvasView
canvas.renderMode = renderMode
canvas.cropArea = cropArea
canvas.setupMode = setupMode
canvas.uid = uid
canvasView.isHidden = false
if self.uid == 0 {
// Start the local video preview
agoraKit?.startPreview()
agoraKit?.setupLocalVideo(canvas)
} else {
agoraKit?.setupRemoteVideo(canvas)
}
return canvasView
}

/**
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
}
// Update the canvas properties if needed
if canvas.renderMode != renderMode { canvas.renderMode = renderMode }
if canvas.cropArea != cropArea { canvas.cropArea = cropArea }
if canvas.setupMode != setupMode { canvas.setupMode = setupMode }

if self.uid == 0 { agoraKit?.setupLocalVideo(canvas)
} else { agoraKit?.setupRemoteVideo(canvas) }
}

/**
Updates the `UIView` for the view.
*/
public func updateUIView(_ uiView: UIView, context: Context) {
self.updateCanvasValues()
}
}

struct AgoraVideoCanvasView_Previews: PreviewProvider {
static var previews: some View {
AgoraVideoCanvasView(uid: 0)
}
}
4 changes: 4 additions & 0 deletions Tests/AgoraVideoSwiftUITests/AgoraVideoSwiftUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import XCTest
@testable import AgoraVideoSwiftUI

final class AgoraVideoSwiftUITests: XCTestCase {}

0 comments on commit 620969a

Please sign in to comment.