Skip to content
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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// ViewController.swift
// PIPDemo
//
// Created by qinhui on 2024/8/7.
//

import UIKit

class ChannelViewController<T:PIPBaseViewController>: UIViewController {
lazy var textField: UITextField = {
let t = UITextField()
t.placeholder = "输入房间号"
t.borderStyle = .line
t.backgroundColor = .orange
return t
}()

var pipCls: T.Type?

lazy var button: UIButton = {
let b = UIButton(type: .custom)
b.setTitle("加入房间", for: .normal)
b.setTitleColor(.blue, for: .normal)
b.addTarget(self, action: #selector(joinAction), for: .touchUpInside)
return b
}()

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white

view.addSubview(textField)
view.addSubview(button)

button.snp.makeConstraints { make in
make.center.equalTo(view)
}

textField.snp.makeConstraints { make in
make.bottom.equalTo(button.snp.top).offset(-50)
make.centerX.equalTo(button)
make.width.equalTo(150)
make.height.equalTo(30)
}
}

@objc func joinAction() {
guard let channelId = textField.text, let cls = pipCls else { return }

let vc = cls.init()
vc.channelId = channelId
self.navigationController?.pushViewController(vc, animated: true)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// RtcManager.swift
// PIPDemo
//
// Created by qinhui on 2024/8/7.
//

import Foundation
import AgoraRtcKit

class CustomViewPIPService: NSObject {
var rtcEngineDelegate: AgoraRtcEngineDelegate?
var videoFrameDelegte: AgoraVideoFrameDelegate?

weak var localView: UIView?
weak var remoteView: UIView?
var channelId: String

private lazy var rtcConfig: AgoraRtcEngineConfig = {
let config = AgoraRtcEngineConfig()
config.appId = KeyCenter.AppId
config.areaCode = .global
config.channelProfile = .liveBroadcasting
return config
}()

private lazy var rtcEngine: AgoraRtcEngineKit = {
let engine = AgoraRtcEngineKit.sharedEngine(with: rtcConfig, delegate: self)
engine.setClientRole(.broadcaster)
engine.enableAudio()
engine.enableVideo()
engine.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: CGSize(width: 960, height: 540),
frameRate: .fps15,
bitrate: AgoraVideoBitrateStandard,
orientationMode: .adaptative,
mirrorMode: .auto))
engine.setVideoFrameDelegate(self)
return engine
}()

init(localView: UIView, remoteView: UIView, channelId: String) {
self.localView = localView
self.remoteView = remoteView
self.channelId = channelId

super.init()

setupRtcEngin()
}

private func setupRtcEngin() {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = 0
videoCanvas.view = localView
videoCanvas.renderMode = .hidden

rtcEngine.setupLocalVideo(videoCanvas)
rtcEngine.startPreview()
rtcEngine.setDefaultAudioRouteToSpeakerphone(true)
rtcEngine.setVideoFrameDelegate(self)

let option = AgoraRtcChannelMediaOptions()
option.publishCameraTrack = true
option.publishMicrophoneTrack = true
option.clientRoleType = .broadcaster

NetworkManager.shared.generateToken(channelName: channelId, success: { [weak self] token in
guard let self = self else { return }

let result = self.rtcEngine.joinChannel(byToken: token, channelId: self.channelId, uid: 0, mediaOptions: option)
if result != 0 {
ToastView.showWait(text: "joinChannel call failed: \(result), please check your params", view: nil)
}
})
}

func disable() {
rtcEngine.disableAudio()
rtcEngine.disableVideo()
}

func leave() {
rtcEngine.stopPreview()
rtcEngine.leaveChannel(nil)
}

}

extension CustomViewPIPService: AgoraRtcEngineDelegate {
func rtcEngine(_ engine: AgoraRtcEngineKit, didOccur errorType: AgoraEncryptionErrorType) {
rtcEngineDelegate?.rtcEngine?(engine, didOccur: errorType)
}

func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
rtcEngineDelegate?.rtcEngine?(engine, didJoinChannel: channel, withUid: uid, elapsed: elapsed)
}

/// callback when a remote user is joinning the channel, note audience in live broadcast mode will NOT trigger this event
/// @param uid uid of remote joined user
/// @param elapsed time elapse since current sdk instance join the channel in ms
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
// Only one remote video view is available for this
// tutorial. Here we check if there exists a surface
// view tagged as this uid.
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
// the view to be binded
videoCanvas.view = remoteView
videoCanvas.renderMode = .hidden
rtcEngine.setupRemoteVideo(videoCanvas)

rtcEngineDelegate?.rtcEngine?(engine, didJoinedOfUid: uid, elapsed: elapsed)
}

/// callback when a remote user is leaving the channel, note audience in live broadcast mode will NOT trigger this event
/// @param uid uid of remote joined user
/// @param reason reason why this user left, note this event may be triggered when the remote user
/// become an audience in live broadcasting profile
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
// the view to be binded
videoCanvas.view = nil
videoCanvas.renderMode = .hidden
rtcEngine.setupRemoteVideo(videoCanvas)

rtcEngineDelegate?.rtcEngine?(engine, didOfflineOfUid: uid, reason: reason)
}

func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) {
rtcEngineDelegate?.rtcEngine?(engine, connectionChangedTo: state, reason: reason)
}

/// Reports the statistics of the current call. The SDK triggers this callback once every two seconds after the user joins the channel.
/// @param stats stats struct
func rtcEngine(_ engine: AgoraRtcEngineKit, reportRtcStats stats: AgoraChannelStats) {
rtcEngineDelegate?.rtcEngine?(engine, reportRtcStats: stats)
}

/// Reports the statistics of the uploading local audio streams once every two seconds.
/// @param stats stats struct
func rtcEngine(_ engine: AgoraRtcEngineKit, localAudioStats stats: AgoraRtcLocalAudioStats) {
rtcEngineDelegate?.rtcEngine?(engine, localAudioStats: stats)
}

/// Reports the statistics of the video stream from each remote user/host.
/// @param stats stats struct
func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) {
rtcEngineDelegate?.rtcEngine?(engine, remoteVideoStats: stats)
}

/// Reports the statistics of the audio stream from each remote user/host.
/// @param stats stats struct for current call statistics
func rtcEngine(_ engine: AgoraRtcEngineKit, remoteAudioStats stats: AgoraRtcRemoteAudioStats) {
rtcEngineDelegate?.rtcEngine?(engine, remoteAudioStats: stats)
}
}

extension CustomViewPIPService: AgoraVideoFrameDelegate {
func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool {
print("")
return true
}

func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool {
print("")
return true
}
}
Loading