From 6f1ad6af19d0fda512b30c184a8d675c2c91b374 Mon Sep 17 00:00:00 2001 From: qinhui <> Date: Fri, 9 Aug 2024 22:14:34 +0800 Subject: [PATCH 001/166] feat: add pip example --- .../Base.lproj/PictureInPicture.storyboard | 95 ----- .../ChannelViewController.swift | 59 +++ .../CustomViewPIPService.swift | 169 +++++++++ .../CustomViewPIPViewController.swift | 234 ++++++++++++ .../PIPBaseViewController.swift | 12 + .../PictureInPicture.storyboard | 45 +++ .../PictureInPicture/PictureInPicture.swift | 347 ++---------------- .../PixelBufferPIPService.swift | 114 ++++++ .../PixelBufferPIPViewController.swift | 264 +++++++++++++ .../PixelBufferRenderView.swift | 179 +++++++++ .../zh-Hans.lproj/PictureInPicture.strings | 12 - iOS/APIExample/Podfile | 2 + 12 files changed, 1114 insertions(+), 418 deletions(-) delete mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/Base.lproj/PictureInPicture.storyboard create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/ChannelViewController.swift create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPService.swift create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPViewController.swift create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PIPBaseViewController.swift create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.storyboard create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPService.swift create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPViewController.swift create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferRenderView.swift delete mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/zh-Hans.lproj/PictureInPicture.strings diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/Base.lproj/PictureInPicture.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/Base.lproj/PictureInPicture.storyboard deleted file mode 100644 index 84b72944c..000000000 --- a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/Base.lproj/PictureInPicture.storyboard +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/ChannelViewController.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/ChannelViewController.swift new file mode 100644 index 000000000..49e931b0c --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/ChannelViewController.swift @@ -0,0 +1,59 @@ +// +// ViewController.swift +// PIPDemo +// +// Created by qinhui on 2024/8/7. +// + +import UIKit + +class ChannelViewController: 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, with event: UIEvent?) { + view.endEditing(true) + } +} diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPService.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPService.swift new file mode 100644 index 000000000..4e99795c7 --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPService.swift @@ -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 + } +} diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPViewController.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPViewController.swift new file mode 100644 index 000000000..ebe0ac770 --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/CustomViewPIPViewController/CustomViewPIPViewController.swift @@ -0,0 +1,234 @@ +// +// VideoViewController.swift +// PIPDemo +// +// Created by qinhui on 2024/8/7. +// + +import UIKit +import SnapKit +import AgoraRtcKit +import AVKit + +@available(iOS 15.0, *) +class CustomViewPIPViewController: PIPBaseViewController { + private let containerH = 250.0 + private var isJoined: Bool = false + private var pipController: AVPictureInPictureController? + private var videoCallbackController: AVPictureInPictureVideoCallViewController? + private var backgroundTask: UIBackgroundTaskIdentifier = .invalid + + private var pipSizes = [ + CGSize(width: 150, height: 300), + CGSize(width: 300, height: 150) + ] + + private lazy var pipButton: UIButton = { + let button = UIButton(type: .custom) + button.setTitle("画中画", for: .normal) + button.addTarget(self, action: #selector(pipAction), for: .touchUpInside) + button.backgroundColor = .purple + return button + }() + + private lazy var sizeButton: UIButton = { + let button = UIButton(type: .custom) + button.setTitle("切换尺寸", for: .normal) + button.addTarget(self, action: #selector(sizeAction), for: .touchUpInside) + button.backgroundColor = .red + + return button + }() + + private lazy var localVideoView: UIView = { + let view = UIView() + view.backgroundColor = .green + return view + }() + + private lazy var remoteVideoView: UIView = { + let view = UIView() + view.backgroundColor = .orange + return view + }() + + private lazy var videoContainerView: UIView = { + let view = UIView() + view.backgroundColor = .purple + return view + }() + + private var rtcService: CustomViewPIPService! + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + initRtc() + configViews() + if AVPictureInPictureController.isPictureInPictureSupported() { + configPIPViewController() + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + guard let pipController = pipController else { return } + pipController.stopPictureInPicture() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + rtcService.disable() + + if isJoined { + rtcService.leave() + } + } +} + +@available(iOS 15.0, *) +extension CustomViewPIPViewController { + @objc func pipAction() { + guard let pipController = pipController else { return } + + if pipController.isPictureInPictureActive { + pipController.stopPictureInPicture() + } else { + pipController.startPictureInPicture() + } + } + + @objc func sizeAction() { + guard let videoCallbackController = videoCallbackController else { return } + + let i = Int.random(in: 0.. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.swift index 01c87c5ea..f686853bb 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.swift @@ -1,334 +1,59 @@ // -// PictureInPicture.swift -// APIExample +// HomeViewController.swift +// PIPDemo // -// Created by 胡润辰 on 2022/4/6. -// Copyright © 2022 Agora Corp. All rights reserved. +// Created by qinhui on 2024/8/8. // import UIKit -import AGEVideoLayout -import AgoraRtcKit -import MediaPlayer -class PictureInPictureEntry: UIViewController { - @IBOutlet weak var joinButton: AGButton! - @IBOutlet weak var channelTextField: AGTextField! - let identifier = "PictureInPicture" - - override func viewDidLoad() { - super.viewDidLoad() - } - - @IBAction func doJoinPressed(sender: AGButton) { - guard let channelName = channelTextField.text else {return} - // resign channel text field - channelTextField.resignFirstResponder() - - let storyBoard: UIStoryboard = UIStoryboard(name: identifier, bundle: nil) - // create new view controller every time to ensure we get a clean vc - guard let newViewController = storyBoard.instantiateViewController(withIdentifier: identifier) as? BaseViewController else { - return - } - newViewController.title = channelName - newViewController.configs = ["channelName": channelName] - navigationController?.pushViewController(newViewController, animated: true) +class Model { + var title: String + var cls: T.Type + init(title: String, cls: T.Type) { + self.title = title + self.cls = cls } } -@available(iOS 15.0, *) -class PictureInPictureMain: BaseViewController { - var localVideo = Bundle.loadVideoView(type: .local, audioOnly: false) - var remoteVideo = Bundle.loadView(fromNib: "VideoViewSampleBufferDisplayView", withType: SampleBufferDisplayView.self) - var agoraKit: AgoraRtcEngineKit! - private lazy var callViewController: AVPictureInPictureVideoCallViewController = { - let callViewController = AVPictureInPictureVideoCallViewController() - callViewController.preferredContentSize = view.bounds.size - callViewController.view.backgroundColor = .clear - callViewController.modalPresentationStyle = .overFullScreen - return callViewController - }() - var pipController: AVPictureInPictureController? - var remoteUid: UInt? - // indicate if current instance has joined channel - var isJoined: Bool = false - private lazy var containerView: UIView = { - let view = UIView() - view.backgroundColor = .red - return view +class PictureInPicture: UITableViewController { + lazy var dataArray: [Model] = { + if #available(iOS 15.0, *) { + return [ + Model(title: "SDK 渲染", cls: CustomViewPIPViewController.self), + Model(title: "多人视频自渲染", cls: PixelBufferPIPViewController.self) + ] + } else { + // Fallback on earlier versions + return [] + } }() - // swiftlint: disable function_body_length override func viewDidLoad() { super.viewDidLoad() - // layout render view - localVideo.setPlaceholder(text: "Local Host".localized) - remoteVideo.setPlaceholder(text: "Remote Host".localized) - view.addSubview(containerView) - containerView.frame = CGRect(x: 0, y: 0, width: SCREENSIZE.width, height: 280) - containerView.addSubview(localVideo) - containerView.addSubview(remoteVideo) - localVideo.translatesAutoresizingMaskIntoConstraints = false - remoteVideo.translatesAutoresizingMaskIntoConstraints = false - localVideo.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true - localVideo.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true - localVideo.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true - localVideo.widthAnchor.constraint(equalTo: containerView.widthAnchor, multiplier: 0.5).isActive = true - remoteVideo.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true - remoteVideo.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true - remoteVideo.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true - remoteVideo.widthAnchor.constraint(equalTo: containerView.widthAnchor, multiplier: 0.5).isActive = true - - pipController = AVPictureInPictureController(contentSource: .init(activeVideoCallSourceView: containerView, - contentViewController: callViewController)) - pipController?.canStartPictureInPictureAutomaticallyFromInline = true - pipController?.delegate = self - //iOS 15 workaround - pipController?.setValue(1, forKey: "controlsStyle") - - // set up agora instance when view loadedlet config = AgoraRtcEngineConfig() - let config = AgoraRtcEngineConfig() - config.appId = KeyCenter.AppId - config.channelProfile = .liveBroadcasting - config.areaCode = GlobalSettings.shared.area - // setup log file path - let logConfig = AgoraLogConfig() - logConfig.level = .info - config.logConfig = logConfig - agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) - // Configuring Privatization Parameters - Util.configPrivatization(agoraKit: agoraKit) - // get channel name from configs - guard let channelName = configs["channelName"] as? String, - let resolution = GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize, - let fps = GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate, - let orientation = GlobalSettings.shared.getSetting(key: "orientation")? - .selectedOption().value as? AgoraVideoOutputOrientationMode else { - return - } - // To enable MPNowPlayingInfoCenter, you need to add the following two private parameters - agoraKit.setParameters("{\"adm_mix_with_others\":false}") - agoraKit.setParameters("{\"che.audio.nonmixable.option\":true}") - - // make myself a broadcaster - agoraKit.setChannelProfile(.liveBroadcasting) - agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) - - // enable video module and set up video encoding configs - agoraKit.enableVideo() - agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, - frameRate: fps, - bitrate: AgoraVideoBitrateStandard, - orientationMode: orientation, - mirrorMode: AgoraVideoMirrorMode.auto)) - // set up local video to render your local camera preview - let videoCanvas = AgoraRtcVideoCanvas() - videoCanvas.uid = 0 - // the view to be binded - videoCanvas.view = localVideo.videoView - videoCanvas.renderMode = .hidden - agoraKit.setupLocalVideo(videoCanvas) - - // Set audio route to speaker - agoraKit.setDefaultAudioRouteToSpeakerphone(true) - - // Setup raw video data frame observer - agoraKit.setVideoFrameDelegate(self) - - // start joining channel - // 1. Users can only see each other after they join the - // same channel successfully using the same app id. - // 2. If app certificate is turned on at dashboard, token is needed - // when joining channel. The channel name and uid used to calculate - // the token has to match the ones used for channel join - let option = AgoraRtcChannelMediaOptions() - NetworkManager.shared.generateToken(channelName: channelName, success: { token in - let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option, joinSuccess: nil) - if result != 0 { - // Usually happens with invalid parameters - // Error code description can be found at: - // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode - // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code - self.showAlert(title: "Error", message: "joinChannel call failed: \(result), please check your params") - } - }) - - NotificationCenter.default.addObserver(self, - selector: #selector(didEnterBackgroundNotification), - name: UIApplication.willResignActiveNotification, - object: nil) + title = "Picture In Picture" + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") } - // swiftlint: enable function_body_length - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - setupPlayintInfoCenter() - } - - private func setupPlayintInfoCenter() { - UIApplication.shared.beginReceivingRemoteControlEvents() - var nowPlayingInfo = [String: Any]() - let path = Bundle.main.path(forResource: "agora-logo", ofType: "png") ?? "" - guard let image = UIImage(contentsOfFile: path) else { return } - let artWork = MPMediaItemArtwork(boundsSize: image.size) { _ in - return image - } - nowPlayingInfo[MPMediaItemPropertyArtwork] = artWork - nowPlayingInfo[MPMediaItemPropertyTitle] = "Song Title" - nowPlayingInfo[MPMediaItemPropertyArtist] = "Artist Name" - nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = "Album Name" - nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = true - MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo - MPNowPlayingInfoCenter.default().playbackState = .playing + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 50 } - override var canBecomeFirstResponder: Bool { - true + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + dataArray.count } - deinit { - NotificationCenter.default.removeObserver(self) + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let model = dataArray[indexPath.row] + let vc = ChannelViewController() + vc.pipCls = model.cls + self.navigationController?.pushViewController(vc, animated: true) } - @objc - private func didEnterBackgroundNotification() { - onPIP(_btn: UIButton()) - } - - @IBAction func onPIP(_btn: UIButton) { - if let currentPipController = pipController { - currentPipController.startPictureInPicture() - } else { - showAlert(message: "PIP Support iOS 15+".localized) - } - } - - override func willMove(toParent parent: UIViewController?) { - if parent == nil { - // leave channel when exiting the view - if isJoined { - if let pipController = pipController, pipController.isPictureInPictureActive { - pipController.stopPictureInPicture() - } - agoraKit.leaveChannel { (stats) -> Void in - LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) - } - } - } - } -} - -/// agora rtc engine delegate events -@available(iOS 15.0, *) -extension PictureInPictureMain: AgoraRtcEngineDelegate { - /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out - /// what is happening - /// Warning code description can be found at: - /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html - /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html - /// @param warningCode warning code of the problem - func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { - LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) - } - - /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand - /// to let user know something wrong is happening - /// Error code description can be found at: - /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode - /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code - /// @param errorCode error code of the problem - func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { - LogUtils.log(message: "error: \(errorCode)", level: .error) - self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") - } - - /// callback when the local user joins a specified channel. - /// @param channel - /// @param uid uid of local user - /// @param elapsed time elapse since current sdk instance join the channel in ms - func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { - isJoined = true - LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) - } - - /// 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) { - LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) - - remoteVideo.videoView.reset() - } - - /// 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) { - LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) - - // to unlink your view from sdk, so that your view reference will be released - // note the video will stay at its last frame, to completely remove it - // you will need to remove the EAGL sublayer from your binded view -// remoteVideo.videoView.reset() - } - func rtcEngine(_ engine: AgoraRtcEngineKit, - remoteVideoStateChangedOfUid uid: UInt, - state: AgoraVideoRemoteState, reason: AgoraVideoRemoteReason, - elapsed: Int) { - if reason == .remoteMuted { - let pixelBuffer = MediaUtils.cvPixelBufferRef(from: UIImage(named: "agora-logo") ?? UIImage()).takeRetainedValue() - let videoFrame = AgoraOutputVideoFrame() - videoFrame.pixelBuffer = pixelBuffer - videoFrame.width = Int32(remoteVideo.videoView.frame.width) - videoFrame.height = Int32(remoteVideo.videoView.frame.height) - remoteVideo.videoView.renderVideoPixelBuffer(videoFrame) - } - } -} - -// MARK: - AgoraVideoDataFrameProtocol -@available(iOS 15.0, *) -extension PictureInPictureMain: AgoraVideoFrameDelegate { - func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { - true - } - - func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { - remoteVideo.videoView.renderVideoPixelBuffer(videoFrame) - return true - } - - func getVideoFormatPreference() -> AgoraVideoFormat { - .cvPixelBGRA - } - func getRotationApplied() -> Bool { - true - } -} - -@available(iOS 15.0, *) -extension PictureInPictureMain: AVPictureInPictureControllerDelegate { - func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { - } - - func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { - containerView.removeFromSuperview() - let vc = pictureInPictureController.contentSource?.activeVideoCallContentViewController - containerView.frame.size = vc?.view.bounds.size ?? .zero - vc?.view.addSubview(containerView) - } - - func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, - failedToStartPictureInPictureWithError error: Error) { - } - - func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { - containerView.removeFromSuperview() - containerView.frame.size = CGSize(width: SCREENSIZE.width, height: 280) - view.addSubview(containerView) - } - - func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) + let model = dataArray[indexPath.row] + cell.textLabel?.text = model.title + return cell } } diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPService.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPService.swift new file mode 100644 index 000000000..d34047993 --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPService.swift @@ -0,0 +1,114 @@ +// +// PixelBufferPIPService.swift +// PIPDemo +// +// Created by qinhui on 2024/8/8. +// + +import Foundation +import AgoraRtcKit + +class PixelBufferPIPService: NSObject { + var videoFrameDelegte: AgoraVideoFrameDelegate? + var rtcEngineDelegate: AgoraRtcEngineDelegate? + weak var localView: PixelBufferRenderView? + + var uid: UInt = 0 + 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: .fixedPortrait, + mirrorMode: .auto)) + engine.setVideoFrameDelegate(self) + + return engine + }() + + init(channelId: String, uid: UInt, localView: PixelBufferRenderView) { + self.channelId = channelId + self.uid = uid + self.localView = localView + 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: self.uid, mediaOptions: option) + if result != 0 { + ToastView.showWait(text: "joinChannel call failed: \(result), please check your params", view: nil) + } else { + self.localView?.uid = self.uid + } + }) + } + + func disable() { + rtcEngine.disableAudio() + rtcEngine.disableVideo() + } + + func leave() { + rtcEngine.stopPreview() + rtcEngine.leaveChannel(nil) + } + +} + +extension PixelBufferPIPService: AgoraVideoFrameDelegate { + func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { + return ((self.videoFrameDelegte?.onCapture?(videoFrame, sourceType: sourceType)) != nil) + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { + return ((self.videoFrameDelegte?.onRenderVideoFrame?(videoFrame, uid: uid, channelId: channelId)) != nil) + } +} + +extension PixelBufferPIPService: AgoraRtcEngineDelegate { + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + rtcEngineDelegate?.rtcEngine?(engine, didJoinChannel: channel, withUid: uid, elapsed: elapsed) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + rtcEngineDelegate?.rtcEngine?(engine, didJoinedOfUid: uid, elapsed: elapsed) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + rtcEngineDelegate?.rtcEngine?(engine, didOfflineOfUid: uid, reason: reason) + } + +} diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPViewController.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPViewController.swift new file mode 100644 index 000000000..9378fb7bc --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferPIPViewController.swift @@ -0,0 +1,264 @@ +// +// PixelBufferPIPViewController.swift +// PIPDemo +// +// Created by qinhui on 2024/8/8. +// +import UIKit +import AVKit +import AgoraRtcKit + +@available(iOS 15.0, *) +class PixelBufferPIPViewController: PIPBaseViewController { + private let mockUid: UInt = UInt.random(in: 0...100000) + private var pipController: AVPictureInPictureController? + private var videoCallbackController: AVPictureInPictureVideoCallViewController? + var isJoined = false + private var pipSizes = [ + CGSize(width: 150, height: 300), + CGSize(width: 300, height: 150) + ] + + private lazy var pipButton: UIButton = { + let button = UIButton(type: .custom) + button.setTitle("画中画", for: .normal) + button.setTitleColor(.black, for: .normal) + button.addTarget(self, action: #selector(pipAction), for: .touchUpInside) + + return button + }() + + private lazy var sizeButton: UIButton = { + let button = UIButton(type: .custom) + button.setTitle("切换尺寸", for: .normal) + button.setTitleColor(.black, for: .normal) + button.addTarget(self, action: #selector(sizeAction), for: .touchUpInside) + + return button + }() + + private lazy var topLeftView: PixelBufferRenderView = { + let view = PixelBufferRenderView() + view.backgroundColor = .blue + return view + }() + + private lazy var topRightView: PixelBufferRenderView = { + let view = PixelBufferRenderView() + view.backgroundColor = .red + return view + }() + + private lazy var bottomLeftView: PixelBufferRenderView = { + let view = PixelBufferRenderView() + view.backgroundColor = .green + return view + }() + + private lazy var bottomRightView: PixelBufferRenderView = { + let view = PixelBufferRenderView() + view.backgroundColor = .purple + return view + }() + + private lazy var videoContainerView: UIView = { + let view = UIView() + view.backgroundColor = .purple + return view + }() + + private lazy var displayViews: NSHashTable = { + let table = NSHashTable(options: .weakMemory, capacity: 4) + table.add(self.topLeftView) + table.add(self.topRightView) + table.add(bottomLeftView) + table.add(bottomRightView) + return table + }() + + private var rtcService: PixelBufferPIPService! + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + initRtc() + configViews() + if AVPictureInPictureController.isPictureInPictureSupported() { + configPIPViewController() + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + guard let pipController = pipController else { return } + pipController.stopPictureInPicture() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + rtcService.disable() + + if isJoined { + rtcService.leave() + } + } +} + +@available(iOS 15.0, *) +extension PixelBufferPIPViewController { + private func configPIPViewController() { + let videoCallViewController = AVPictureInPictureVideoCallViewController() + videoCallViewController.preferredContentSize = view.bounds.size + videoCallViewController.view.backgroundColor = .clear + videoCallViewController.modalPresentationStyle = .overFullScreen + + self.videoCallbackController = videoCallViewController + pipController = AVPictureInPictureController(contentSource: .init(activeVideoCallSourceView: videoContainerView, + contentViewController: videoCallViewController)) + pipController?.canStartPictureInPictureAutomaticallyFromInline = true + pipController?.delegate = self + pipController?.setValue(1, forKey: "controlsStyle") + } + + private func configViews() { + self.view.addSubview(videoContainerView) + videoContainerView.addSubview(topLeftView) + videoContainerView.addSubview(topRightView) + videoContainerView.addSubview(bottomLeftView) + videoContainerView.addSubview(bottomRightView) + + self.view.addSubview(pipButton) + self.view.addSubview(sizeButton) + + videoContainerView.snp.makeConstraints { make in + make.left.top.right.bottom.equalTo(0) + } + + topLeftView.snp.makeConstraints { make in + make.top.left.equalToSuperview() + make.width.equalToSuperview().dividedBy(2) + make.height.equalToSuperview().dividedBy(2) + } + + topRightView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.right.equalToSuperview() + make.width.equalToSuperview().dividedBy(2) + make.height.equalToSuperview().dividedBy(2) + } + + bottomLeftView.snp.makeConstraints { make in + make.bottom.equalToSuperview() + make.left.equalToSuperview() + make.width.equalToSuperview().dividedBy(2) + make.height.equalToSuperview().dividedBy(2) + } + + bottomRightView.snp.makeConstraints { make in + make.bottom.equalToSuperview() + make.right.equalToSuperview() + make.width.equalToSuperview().dividedBy(2) + make.height.equalToSuperview().dividedBy(2) + } + + pipButton.snp.makeConstraints { make in + make.center.equalTo(view) + } + + sizeButton.snp.makeConstraints { make in + make.top.equalTo(self.pipButton.snp.bottom).offset(10) + make.centerX.equalTo(self.pipButton.snp.centerX) + } + } + + private func initRtc() { + guard let channelId = channelId else { return } + rtcService = PixelBufferPIPService(channelId: channelId, uid: mockUid, localView: topLeftView) + rtcService.videoFrameDelegte = self + rtcService.rtcEngineDelegate = self + } + + @objc func pipAction() { + guard let pipController = pipController else { return } + + if pipController.isPictureInPictureActive { + pipController.stopPictureInPicture() + } else { + pipController.startPictureInPicture() + } + } + + @objc func sizeAction() { + guard let videoCallbackController = videoCallbackController else { return } + + let i = Int.random(in: 0.. Bool { + if let view = displayViews.allObjects.first(where: { $0.uid == mockUid }), let pixelBuffer = videoFrame.pixelBuffer { + view.renderVideoPixelBuffer(pixelBuffer: pixelBuffer, width: videoFrame.width, height: videoFrame.height) + } + + return true + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { + if let view = displayViews.allObjects.first(where: { $0.uid == uid }) { + view.renderFromVideoFrameData(videoData: videoFrame, uid: Int(uid)) + } + + return true + } +} diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferRenderView.swift b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferRenderView.swift new file mode 100644 index 000000000..330b3f9cb --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PixelBufferPIPViewController/PixelBufferRenderView.swift @@ -0,0 +1,179 @@ +// +// PixelBufferRenderView.swift +// PIPDemo +// +// Created by qinhui on 2024/8/8. +// + +import UIKit +import AVFoundation +import AgoraRtcKit + +enum VideoPosition { + case topLeft + case topRight + case bottomLeft + case bottomRight +} + +class PixelBufferRenderView: UIView { + var uid: UInt = 0 + private var videoWidth: Int32 = 0 + private var videoHeight: Int32 = 0 + + lazy var displayLayer: AVSampleBufferDisplayLayer = { + let layer = AVSampleBufferDisplayLayer() + return layer + }() + + override init(frame: CGRect) { + super.init(frame: frame) + configLayers() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configLayers() { + self.layer.addSublayer(displayLayer) + displayLayer.frame = self.bounds + } + + func createLayer() -> AVSampleBufferDisplayLayer { + let layer = AVSampleBufferDisplayLayer() + return layer + } + + func clean() { + uid = 0 + self.displayLayer.removeFromSuperlayer() + self.displayLayer = createLayer() + self.layer.addSublayer(displayLayer) + } + + func renderFromVideoFrameData(videoData: AgoraOutputVideoFrame, uid: Int) { + let width = videoData.width + let height = videoData.height + let yStride = videoData.yStride + let uStride = videoData.uStride + let vStride = videoData.vStride + + let yBuffer = videoData.yBuffer + let uBuffer = videoData.uBuffer + let vBuffer = videoData.vBuffer + + autoreleasepool { + var pixelBuffer: CVPixelBuffer? + let pixelAttributes: [String: Any] = [kCVPixelBufferIOSurfacePropertiesKey as String: [:]] + + let result = CVPixelBufferCreate(kCFAllocatorDefault, + Int(width), + Int(height), + kCVPixelFormatType_420YpCbCr8Planar, + pixelAttributes as CFDictionary, + &pixelBuffer) + + guard result == kCVReturnSuccess, let pixelBuffer = pixelBuffer else { + print("Unable to create CVPixelBuffer: \(result)") + return + } + + CVPixelBufferLockBaseAddress(pixelBuffer, .init(rawValue: 0)) + let yPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0) + let pixelBufferYBytes = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0) + + for i in 0.. 0, videoHeight > 0, !CGSizeEqualToSize(self.frame.size, CGSize.zero) else { + return + } + + let viewWidth = self.frame.size.width + let viewHeight = self.frame.size.height + + let videoRatio = CGFloat(videoWidth) / CGFloat(videoHeight) + let viewRatio = viewWidth / viewHeight + + var videoSize = CGSize.zero + if videoRatio >= viewRatio { + videoSize.height = viewHeight + videoSize.width = videoSize.height * videoRatio + } else { + videoSize.width = viewWidth + videoSize.height = videoSize.width / videoRatio + } + + let xOffset = max(0, (viewWidth - videoSize.width) / 2) + let yOffset = max(0, (viewHeight - videoSize.height) / 2) + let renderRect = CGRect(x: xOffset, y: yOffset, width: videoSize.width, height: videoSize.height) + + if !renderRect.equalTo(displayLayer.frame) { + displayLayer.frame = renderRect + } + } + +} diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/zh-Hans.lproj/PictureInPicture.strings b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/zh-Hans.lproj/PictureInPicture.strings deleted file mode 100644 index c50d8f1d5..000000000 --- a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/zh-Hans.lproj/PictureInPicture.strings +++ /dev/null @@ -1,12 +0,0 @@ - -/* Class = "UINavigationItem"; title = "Join Channel"; ObjectID = "AmK-zc-ByT"; */ -"AmK-zc-ByT.title" = "加入频道"; - -/* Class = "UITextField"; placeholder = "Enter channel name"; ObjectID = "GWc-L5-fZV"; */ -"GWc-L5-fZV.placeholder" = "输入频道名"; - -/* Class = "UIViewController"; title = "Join Channel Video"; ObjectID = "cAG-6V-STC"; */ -"cAG-6V-STC.title" = "画中画"; - -/* Class = "UIButton"; normalTitle = "Join"; ObjectID = "kbN-ZR-nNn"; */ -"kbN-ZR-nNn.normalTitle" = "加入频道"; diff --git a/iOS/APIExample/Podfile b/iOS/APIExample/Podfile index 1a98a1409..4e2cea8d0 100644 --- a/iOS/APIExample/Podfile +++ b/iOS/APIExample/Podfile @@ -13,6 +13,8 @@ target 'APIExample' do # pod 'MobileVLCKit', '3.5.1' pod 'SwiftLint', '~> 0.53.0' pod 'AgoraRtcEngine_iOS', '4.4.0' + pod 'SnapKit', '~> 5.7.0' + # pod 'sdk', :path => 'sdk.podspec' # pod 'senseLib', :path => 'sense.podspec' # pod 'bytedEffect', :path => 'bytedEffect.podspec' From 3306b949d31b43d1ae3a66f87ff6d5660c8218bc Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 11 Sep 2024 14:53:40 +0800 Subject: [PATCH 002/166] fix: media relay bug fixed --- .../MediaChannelRelay/MediaChannelRelay.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift b/iOS/APIExample/APIExample/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift index 539a2cf57..cddf2a31b 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift @@ -45,6 +45,8 @@ class MediaChannelRelayMain: BaseViewController { @IBOutlet weak var resumeButton: UIButton! @IBOutlet weak var relayChannelField: UITextField! var agoraKit: AgoraRtcEngineKit! + // configure source info, channel name defaults to current, and uid defaults to local + let mediaRelayconfig = AgoraChannelMediaRelayConfiguration() // indicate if current instance has joined channel var isJoined: Bool = false @@ -128,6 +130,7 @@ class MediaChannelRelayMain: BaseViewController { // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code self.showAlert(title: "Error", message: "joinChannel call failed: \(result), please check your params") } + self.mediaRelayconfig.sourceInfo = AgoraChannelMediaRelayInfo(token: token) }) } @@ -140,15 +143,12 @@ class MediaChannelRelayMain: BaseViewController { self.showAlert(message: "Destination channel name is empty") return } + NetworkManager.shared.generateToken(channelName: destinationChannelName) { token in - // configure source info, channel name defaults to current, and uid defaults to local - let config = AgoraChannelMediaRelayConfiguration() - config.sourceInfo = AgoraChannelMediaRelayInfo(token: token) - // configure target channel info let destinationInfo = AgoraChannelMediaRelayInfo(token: token) - config.setDestinationInfo(destinationInfo, forChannelName: destinationChannelName) - self.agoraKit.startOrUpdateChannelMediaRelay(config) + self.mediaRelayconfig.setDestinationInfo(destinationInfo, forChannelName: destinationChannelName) + self.agoraKit.startOrUpdateChannelMediaRelay(self.mediaRelayconfig) } } From c31801f0c68a9c9c5fa2adb224dc0c716defe4c8 Mon Sep 17 00:00:00 2001 From: "1138289316@qq.com" <1138289316@qq.com> Date: Wed, 11 Sep 2024 14:53:44 +0800 Subject: [PATCH 003/166] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E9=80=8F=E6=98=8E=E8=83=8C=E6=99=AF=E4=BA=A4=E4=BA=92=E5=85=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../APIExample/APIExample/APIExampleDlg.cpp | 6 ++++++ windows/APIExample/APIExample/Language.h | 3 +++ windows/APIExample/APIExample/en.ini | 4 +++- .../yuvj_full_range_alpha_1280_540_left.mp4 | Bin 0 -> 504596 bytes windows/APIExample/APIExample/stdafx.cpp | 10 ++++++++++ windows/APIExample/APIExample/zh-cn.ini | 4 +++- 6 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 windows/APIExample/APIExample/res/yuvj_full_range_alpha_1280_540_left.mp4 diff --git a/windows/APIExample/APIExample/APIExampleDlg.cpp b/windows/APIExample/APIExample/APIExampleDlg.cpp index 7281c0795..d3f4d71b2 100755 --- a/windows/APIExample/APIExample/APIExampleDlg.cpp +++ b/windows/APIExample/APIExample/APIExampleDlg.cpp @@ -255,6 +255,9 @@ void CAPIExampleDlg::InitSceneDialog() m_pMultiChannelDlg->Create(CAgoraMultiChannelDlg::IDD); m_pMultiChannelDlg->MoveWindow(&rcWnd); + //transparent bg + m_vecAdvanced.push_back(TransparentBackground); + //inject m_pRtmpInjectDlg = new CAgoraRtmpInjectionDlg(&m_staMainArea); m_pRtmpInjectDlg->Create(CAgoraRtmpInjectionDlg::IDD); @@ -604,6 +607,9 @@ void CAPIExampleDlg::CreateScene(CTreeCtrl& treeScene, CString selectedText) m_pmediaRecorderDlg->InitAgora(); m_pmediaRecorderDlg->ShowWindow(SW_SHOW); } + else if (selectedText.Compare(TransparentBackground) == 0) { + MessageBox(_T("TransparentBackground")); + } //Sleep(500); } diff --git a/windows/APIExample/APIExample/Language.h b/windows/APIExample/APIExample/Language.h index 7d53ff4c2..9a18d37b6 100755 --- a/windows/APIExample/APIExample/Language.h +++ b/windows/APIExample/APIExample/Language.h @@ -348,3 +348,6 @@ extern wchar_t localVideoTranscodingVirtualBg[INFO_LEN]; extern wchar_t advancedMetadataVideo[INFO_LEN]; extern wchar_t advancedMetadataAudio[INFO_LEN]; extern wchar_t advancedMetadataSend[INFO_LEN]; + +//transparent background +extern wchar_t TransparentBackground[INFO_LEN]; diff --git a/windows/APIExample/APIExample/en.ini b/windows/APIExample/APIExample/en.ini index 985283928..0fad41a7c 100755 --- a/windows/APIExample/APIExample/en.ini +++ b/windows/APIExample/APIExample/en.ini @@ -304,4 +304,6 @@ LocalVideoTranscoding.VirtualBg=TranslusionBackground Metadata.Video=Video Metadata Metadata.Audio=Audio Metadata -Metadata.Send=Send \ No newline at end of file +Metadata.Send=Send + +TransparentBackground=TransparentBackground \ No newline at end of file diff --git a/windows/APIExample/APIExample/res/yuvj_full_range_alpha_1280_540_left.mp4 b/windows/APIExample/APIExample/res/yuvj_full_range_alpha_1280_540_left.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..2e9dfbd99eeab36def64249af60bb9468f653826 GIT binary patch literal 504596 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∈+nZ#*=xjS-dBK|0!Z#fVqbMM-hYNXevL;Iyq;MuTtF%AX=a4 zpm2K9y23}{zioKcBX`pt*FEJ_-d`<7cA6?Dt|Pu-0IJP(p5+OE>6Hskry^2de}1k| zK#CL9#f_*XvzPe3BfHXuEPdN|inmfeqi6@4IH6XikcL>l!D8?V)twHfTNrP#%nf;-?ET8+sbATs0~ zEzzfmt{8NfbtMBnZ}Swkd+!gzS70EgKO4lfpNFqzx5CFEce-|`e+pam`Vl z0SRi8Hn_b(Zd8`Sj`4a9os%gbX-UPVcoS;P7bT3=hHC@R!j5S&0#0VL7FB*2hk3&=MjWI?DCH{-wFO|MByg zHE8nq+dFHmvv&?!mH&0--0I@q)=IyZGhWakxoe=F&~ z$D3;@(n?lLFZ`}-x8jPC7d{X)No0}bQ{5Fj9m2wL%%S~E(lE+mVID5drnD&(i=Vze zT3lp0IcYjlX;1!nTZ>%G7dEakNOixrzX$eiDRtxki_VzbO5G>3-jSeO0a(YywZD^j zS>0kp3;QXF*GMmPG{;Ab#-hvn@> z(G*qMmzr`Pfp(etc{i6NDPipwMT=FXS#HVA*DPvL4gf(eD_lqXGBJcC({ajA;?FJY zx%|QFXCw~g7YpiHy9X+#ni?;@t}LaI_asyB982FIPWLyBaBc8BANDSGw0TyeMZ@I_ z$22te7bJ90ilLOIC=^FZX5z(lnkJ3`et)mNL zS^tW&wfQ*e(0A>!Xo}rt6m=zb%ZM;@H_WFoW7n6A0gdQljL`pFlPVmDS#t_)zYsL@ zS2zWv)bJVh6`_B`Jk#{B2Q~AnFCF5?cNk?F_WsYVE7}VIwo=FzPWO&W#uDbc=#2&q z=9MkRlj1y;%V0!H2gvu0w%JS-%_U<56!0~NzhxZ_1u@6M?}@9z-+?-)gqM)sWf+{X zW@XsRG7VWua9@SkyDAcvr2eZc7HBKk`4r&IdJ|E}%s;#EjNTIXA517McuI(|8aS+2 zJDDubpiv!i%>HpNYQhEHmg~Av$B|-YdZ$mx##by+C!JF93o5)fLy@+O1g(Mp^JzB5 zRDk)f#b!YBrYALS9RU!YE4C-$k6y?y7rfy@dIu@buOwlgF3*g*XD&H3`ox<&ol41} zr*cY3X3n#AFHSJ?MEySrN}8v8#uz5(BPhLpvD(afp@vJ6Z*alw&oP&T@r_LS`E~se zWQE_#rqKlFr6^iQZKz^Qwx_&|*KZ&G0Fx@t?&4TD$Cpa8EJW>&Kxq-M<*?&elzBPR zhftd83OdXnt6GWbL3>SsMts;P<_?cx<8O+Dgt&{1J490RYe?mK!t`Qcb@2{gBSaS7 zz#c`kN#%CRy6zI7JarKJiu&2x<|#`Q7aMmkoH$Eep+^O-Q!XzvqQ138kYG4Lgtag| zVp@#kTb)f2i3a4IaO-9lFVe4JFZo)9AToK4)txh0=t1`gb26 zmljq6nY+rst6*S5;jHi*aJ44+xDVRh>&Y<6$uY?uVl{Qqn;06rXcXsOboecI0CYVj zjUK53WOZ)YWR96wFz|3JAH;i4Cx&aBiyloHXR;Nc`v13rmVFQ1Gk)P?+QT zqd>F>eCQ8Dl<&*Tl|3Qp;Z3)PDro+`CNqT{_oyO|eyY#O2@0-zC>Q_*63t!-Q?EZ^ zdUK{o*Z;MP=wx%5$UkrdE_6`glpUSC=%B{pZ;#&{UAVY}dq{=jGea zb5aesL@&GxRR@!4H4SE>hhvpiqE%T>S_*}InGzYW&cSfIA+RC-mm05jHvIS)2mg4X z>cs%4fUKm)LDwj05|-$FVu#StnFIUK&QYivF<4-I-CH=HZ)PDBO>#;+%xk-*W!z() zRf_JZ{1X}>r^=By`1e|Ssw$F_jS9n~60oYABM_$pLAFlK9lcK)7lXUH%4{&Ca}U4iL}*;q@P%&Xppp@O-d;8l6#Vi6ea_oUcQ~RxRcD( z=n+EcZXdLjJ2cbtG+-2tT9=0nJ4we~T9hvC{!2d6-U88u%q7xMiuGZD(y2-|8m{`~ zon`sE`}9;O_@7ZhinCz&zutH%R$T$~PgNwUP>$FG!k95G#yE)~EbiRg8 zTb443XuUfVelP}3t-y1h0dV0sz4a~y0Xh80d~UdO4%t0kc2Eg1P|l~c@1#9LJ*r1G zza>ifEmzb$<(8d%Uv8O8*(wV6YM3|95#r{8vP5IPZ5+V}Y;RdJ`1ZKnh9_@q;|msfnfun+-f2`i6}_Nz9?09m`*lx) zFcYW_Oi5e5+%@%^R@Zdmc=ps<_<1$$oSHn$Z%(d&JU2GCCiu8FAP{`if_=*xfPnp# zoWq-V!9*jLL90?S?sG-DPs@>MZT%vcFa#JeqJVn-4sa>Waw{km+MW9rLX*E~qu&93 z$nCoe$aG-7CC!QUVLy{rE(~-xd!}-BG=ICd2>yv!@I=AZTe2tBK;Zhs zkH)=11k)dM z{A9)P+S^3NV+{W7+<#NumDGfRb&-YFo1w`N<>wjtj&EY2M&WP8Z3y3%n)-sCjqi=F zdL+6eeF-huVp66YfHT>T&fVw`{D3GajwzaY{6o91ehL7#JtuXx0Wg^X;j78Wy9z3C zMsedi0xL8E8H!-He@}tJn`}%72I1p)`%gQUY?haqwD+b^$nZd%C#HQuP{WckyB1h? z$)rKgvajU2A!lDL=7fODDV!=|p&g9$-|O(rPN)J;D)feDRLPov+QhCuuie>QS8`^% zh=gk{H2;VyGDn-oC69L!i{JT-a=Vwwe|b16*`^dflD^QDAof*PdQvk(M?IVWeJLjT z1&9#lJcndhbByX);Q)!CObkz`Lo}Yvu`3g_8oJ)dU31^--nDtUPcZygn~bsI&13*< z5@(Rl+f|705HOOnE+y|L4gY3DsC?tvsoxd`x;lH6&^*8m_+MdJ0Jv+Av%tEUa%Ke% znJJRGkr-_Oqt8kjEw=C?G&JaXMBrR)Jwogz!uSpx{88m3dF(u=Mr->0gEk2ZDFB8# zzq0z-%e%$hjt9$2ILu65WAbF8{G35;LjB9m)7yJ^NEQ<{L-)~Jt^nimVp z+8Z7Fza*H+VT`TBusJWkjUSB%hl@29-E@Q+!q$LDu5U?-#bZ5rLY%^{a$e*CMAYO+ zDXOtMOIg5oG5hnpQNEX$lh-(f^klG4+crMBT)G)1H{TBn!r1C`Cvnh$eJ^R4baepK zNy>pRlvcNNo`OuKvLMVaM5cCzY}mO4oDPl}PrR8H>~I;!FC`(x^@kgcdf)YkA)FOg zF_>!Rg&w2RV95P;;3;4JyQRGSgUl~v5SAReUqZ#;tWwG*oC#YZWI2aO>=NTX8{$t~ z6*ebXbI11t>z)E#j`c|I$oGx?FlS{QgDA8S5P_E7dUSI6K=$&U`hbz`zPZ!jj#q96 zT}|3vQXVS1BI&YAhPbl0PdPv*!6ZPGEnq|jrs)fZ0@2bQhWxL=Oa0l`ew#FzVk^2v z)vQ$%7>;8)w#qCcZNjkGLmHv?ghxJ2ljiU~kj}t+EU4u`L>J4G(h9FJl5(kyXr8qq z6jAGUzgMXW(n6%v`kGpIQTkT@>3kZ0=XKKhyL({Mc4NJlnp!{j8kRAaWLhTOOKFLQDjW0eH#plI=_`+8C5d56+lmR>}K`8^hfdLuD z$=vJ`6&*k|MNXyHLM|_idNo_r2Kmy^@nD*=ICA}O4W;dZwm|50EA8(FZeK$@NQN)u z##=i#`#NsD`TO5y{NKWn>gDNDsaw;z)`nx2%$*1t3)Dw&rc|V^@p|}M`~AvSG_<>~ z{95{z!>T4{W%5SZ!MIb%H%mPm6vPZ8r1J(dr4MSwON=`?(rWUwQE@WEDZ7LvbVg6j zcGSh5t>Gq4na(dtY6u?~qqXbAZsoe%50I1CVrcU$`u^R@p{|*}*?_G23o+pbA<6zo zka})wz%?eIzCc>eBKQk~SmwY|T+h8F240dJo#LJiGQfsKVO|w{Ar4BBHXc1_6@Nl! zgL1xPDGH8sv7+(c9O6HJ>v(KwzT&W+zWdt8!sq@8*RMe$e-Xps6*<6bO=%`NAn&x2Gu|3I zBP8les8QcZADtj_fX9%u$CH)n_>5RsDOFT|^Fjw~k<jICDWqji zOkxO#0(D}GcdDT`e36SFX1AoqJRNLCPJoy2%>@$^6<$rp$`>&?RmrD2ilquK@i^zk zA{@Y6iHasAtTuxVr0FfbC#SsG+V8k%D+}PM;~jD3s+GQB4oOiEX3S9n%juBx##MO{ zI>Re*PXc|%-AmpHQ-1*I-!Y9iL0Zuom6ku%-fV_=$y${~0^b_ID+52)T?|qRMEAzY zW+2(OB!ibs``;SIYYPt~@jmsi3Jlb00)O|Z8h~T$2zdYiK=y*UVgF0Wx!@V<%NW>S zR%(OF68{Rsb=ekXg911+RssIX&g#>*M7j8VcI3Dkz?IcAmcRt85r4g~0+i;GQTz~y zaX~?MU|VcRx{G348PU(!{F-u1J+6BREu?hXJb6(l-x^41H4UU|FMjPGVairW0#JM6 zQ!5~r#JKMrxDx~cCU-JZ*WbQ`JIPP!@30qJ4lp>L|5eB*bnESipP#0r<1%m)QDFpU-OFi`_r!+Z`z9S6IJGfKOR`xo8+5g}1q%mP~2 z`kT0k+@O@Xkkxb}QOJ297BT6$9oU837wxzEQ~afJ@8T+$Vls!X_X1j7Y@EDAq0Q<0 zAOnDyKAsPVeqElcI}qtx*pE*) z%iyCx0IM$o`2qu?VTkk|U8a8xiWVVK+{i-4#iEB_frs-fV~HO|sjcotpmjlxpjBmQ zap9;5o_vy}MuNo4y7Cnd{jcx|?3`lIU8-g8)6XNr@@$YVz(a@kFtaLF+kg)`Qjr#T z$5YhVYY$K88T)&EJG9A#+K1tD-is=_f_^IE$AneM zNF^)Ip9wrQiDEnYp&Eg3*E}>HCxIcj+U|g>rq53LXiZBt4wV7@Q80ebyKS@_R6_O^ zf-1X|6OeZ661y6^=xfpNrF`lZ?xyy7#1yjGqPuVY?@w&86^5$inmzrg?ry$eLe-A#KOF#5 zNe-`!Kqx}<1* zm=LZYZ??ztXNCD+xu|H!@FTaFtW|O2pFxS8AA;00d&B=c4O@V@W&el1<_1hj=cTUa zklODRAKx$~L{JHLE;bTC;doY3%gVNA9m=(;nAQRJd5q3+m!<(($3WfObJO(J$(-RI zI!YQNnXHKB6uI3x_|{W~pp(7qD$bd2)W^&n-@<^usT~O}KTd9edV@DN73njWKY`|I zD!@@gdS^*E!QUJ{?d7uD)_XCOr_B zPNU`s0@yX8#jU~ndPmv9`itH7JB8ZaG^Q8I3nZOCF8O2}2ekik6XZjQ6rlC83|27j zadhT1$PByT)w3Q9l+xv5^G6>-xR^yZv@;`6gS60@ve$!fYjfc?w47D|Ok{sS(Znp> z0_~eax)g$(MwipN5y1HAJ$ zccfoR=8nG6tj43SmsoPZpGTb;Kc$+%0`_0%B?j#@f-j1YD5BG7LEfp!J#)OVD72=# zpRrSovcZZQDVF|Q_I;B(GtdzBrDN9fOZzq)!J>B? zyG1#rqEF{hI)~QqBo&IMYQY{Z%D~{;?s(tTCkcbzu_^-(7NZ^&0GQf_2C`|5SFvWN z+6R8%6U=t?}3~Ef( ze1#Fs6wu`rVv7a$bh%dNH6CUlAo*+d{XV_DjrF=v(IEdi|9os4&{I^!U`>KCWMUTD$2I0I| zi2!`wj(-jEb2_rVNxd0Q8zaH|H;G2*(D*SyXq?}(l=P%Z(YGj%e7C!^ho(ya4~MQ} z8=I6Nxo?5C;Y!RLL-AT{ho%J2`={$FN=|Hbqc9_8%sbil1_DnGWHFBOn?N35{_a3a ziwetjq=+V<<6c;SRuodMP}ln9Q0E=J_)*-51$w?ZhVxmNS(Bw@nm26-BzGW@i}I16 zV;^xqu8jo|)(SGuq+)?Q1prVNX;>Ju4GMx(T(W%x8CsCo42u-Y*_A2tRh+q7=Bz4@ z$d_)C27d=q1Km&q?0)*;#=-VOMI9V)JWGeE9QE&r(Se*tD~H*|KSN48dJTsICwK#u zPaOncmO>_rgO-Zpu2T|ih5oppi0-u9w|qQDaAut>qbJv5&~h_FM|0B7S^cHAs@GPc z5Lvh9BQ*1KiAqiB01cHD=>SqbqUW7*Goi$1z$B1DJCs-bf*0-`r7~Kv7>@YU)rMqu>`^DJ`P3X9@ zC!{Wz;N>|KvDPkl%T@{N`}T?JPwyU}Y`L06w~-o$eu-aj0TwP6HkR2?2P`_pqY))_ z8BhfyG%K1fV~Dj8dztbxPwkl8yMjKXE{&4_c3!xBf^!L)qBX)*8Ec#5-5+-AO4XYV zJ_w9y=U010mC?T(TOiT68U_0tno-_RD|=lx8EUlZS_0&fU_Z!o=@?3WoECpb+n(v0 zFqtC&Ttj8|kLnO_b>?ey3I7q(By76H?yqo5)9y0p++S>lE9366hzcv#S;r442%2=@ zjD1{y1NjLDQ56VcjGrMR{F9R=^URASGFIa?ozoW}^CVx?s;WaC&dG_>1DmCfYg`2L zOckX^y>=sH0`H3-Z)x=Cgl)h9Jo-#uI6#sxX&XFyg>)e5Lsni4DEOm-Qitx9{yw5i(PEF8J5efDT6!hN49JZ`YQ zDk+&h*f$llA5Ysej;>omjroSVpWs9_{!s=pjsC zKR>M~NJSdNtiV{{v6WqK{@JQDbe7}yYd(O-sGy|RsR0Q6k_Xw9sXB2T?*abU*TJH>R za}LZgJsoerH6kE1gUwuR(^GMWoEH&wRdiS)vIN6mG;ARW&Tco|oaM4sofLhs`is4c z54y0zZf9^d%pO@r182(E9rJ9S6fp>*(Wd*R3@`1)Tgc+av+;H90k z!(GZ;!gtzCPQPf9`BxB(p|!EfFN{dlAB0u-{puax2Dvm}?M~kH`H6IEK{|o5Uq`gA zN7TteD}gA>aW)|w^5}Dno|>2lzQMFD?1s#YLEh~h=E-=fre|-bA=qex9uHxwmP&RW9rxXB#}!hh^WPg{XU+w zIJAPEF04@qHn19k9B=O`rMqkP=T2&YU-z~Gj^m*l&7C`yNdU`=OFadh=!-n4KFyp4 zM{2#oP#d}4aT$9gL;Jx+!HIc~>oZ`aViTUWS|?4|!mASc-QLdCdI(O#T00HDMwhvU zhGipm9|nUv{OYuvHXG5-`CWHqgl!uFO!Juy^#*O6^;9E2`HOTQk+VwAHsL?Bo z<3;Q{B1BKT!<>dwH9KQiTXHxRp!o5+N+C*j?#x(lGG@t<^q9lawS=7dyqZ}s)g~$^_4J&>58f&@4-t1~v zR27jv%AJ@kPB1i$N!aI@B&r*<+A+wxC|aya_%pcSVw_+Ao`n;N0EN(1p*(NS z%0^KRkwxG{OnobviDJig^Er56H#smR6!jl2SK7S7DJf$Imkz6-cPm{t@5!+MTje)o zVtT%S3SVO8%q1n@XH69(8hvFS2^rzr@vw6sB1?K++dRuGZqLGw{~H|g5V++>oXLu{ zY1_4psv8Oa2l;eEn}ProJaWs*L{wFX97%^%k{Ze{I!O4&)Cd z4T3*bO&vLNNz;C>*&Nip$93lCQ$H_H?n!*ee5dvRzty`ln|7;xh)}2loILk2?Pb;u(f_0B9Gf!%wyvE!ww+Au zOgyn|+qP}nwr$(S#I|jl&%9M{)j8)UbbskyYp=C0j$%X-{{pm)=- z=S6;B2TH{32q`hG5jC{G1EUqQslgllW1HBw%RR6~WF0cuI1J|zWgLD+`>-gxHW0LmmTP53`pX#wV}LH7opu_$vb9H+j0XBf z{$t+eJ>3m71t+zJLP(v=lb~Fy3G~@#$msF>e}c^gkaPCmI`*wo$yj>N5(AZt!bGk1Pt9+Y@>@s> z$6(sxbh-L%Ozar?16vq9YeXRXDQps_LM@u)F1{&Xlh}A#Y8c>?Jt=7e+)CAEkMr2f287Il-APBlaf?m>R^{J zJ1>*qlZ{46k-{LFvHFiJs2mW>+4uHinRZV9zDLlsm73UR2g|=CNX||9h_mOq=Ihv( z;bT&Y4spe+|CK0gg8v_BU6U#(q`!$zpWtY&fWd-t%|t;^`5`~{KC(W4dpTqnWPAvC z({d}Yv&Q=exe8TlSl)vu7jRsgE=KwSG%A#->jOskJ8W{gJyD>27Fr!bYO3WLxq;B4 zrN;AF-vFzQkH9byS=DmCW0KFF%wNw|W{yAH#A01!+qoPLj+XR5KnT118MpsmEZY8j zmj?Zdass&f$C9z32Z5J3{E$X^Rw3L9LUY>gUU{Ml%(P%Fg_KogG49ax(2)?kr`;^otd|ar=V$W=l{Hal)Fq78k^#;il)_ zm4t6!#fL$C2BaO0Z4>>u9w`H$HVoZ_w6d#@8nz;Q8qUSYy@BLNpUO1Iy8|IQjS0OM zqyIe5zQfe} z3bU$TvufZ0sFkTD;>T*NSS4fG(Do#ar6>{yYg!e$h!O;0Cv(mdQJvwZLhas2+DYB?kIb+rV zdOp2{Y)M8!grW1G87VL%8aJZ?Sz<5H{7nV~iHCo-b*o{fT4iG%HoJh7AxdHTxmUSCCjz<($*w0+4h!XS@L;mS zsw8OPKo4>l)0t7aA2XISXA4M)t4gnzTDu1coxg#@{0G{>@V26ip~By3^!fW@OeTJn z(QuXQ=K%ztYnC;9s#P!Tr8oWuzMVq<{}Rpwf&e00(|RM z>ad(P_jgSphbWD`YP{?uIXzqsXztzXOCgym2hbA(=UnF+0j!&gl=%OQytP3I0(n<6 z4}q2vO~SmL+77mHJ1%2~m_LPIoADH>lj#tgc%(7gMD10kD>>Lv8F9oA*ngFu$~DDCBXC56MtGWm2Ksa=`<89L6GhK&Nt6;sOh zqs|dDDg9|dLyK#D+z>gD>82-i@Qd}AmIrJ97j`yaXsS_dGkw3~Rt@W|E!O=GF z*K=v@;2=LM-pV6|08WYdY7wJ6-TQNXT~5(F7>Ha2606`)OkkNDq)SD&c;ugAG~ycDj9U5!|6^sSR8R$rF{ z+lF~S+u(SY6QZoxrIQ$K(#_T5_)-zg_9BbyJ^gtT;a&N|H) zB(T=DT0^Scg9E9|uq6wLOlT2;f)+f0<3p+YS2g+{RKNyGa*M*-u_dc%I)%Ifops=&ot>C|z@tIh#sUf@}O$|MJ*N;w0Kwa57{Op5Ob9*Y2wZ8yoWH zqovHEM!i98q_QYwg5W6ZUV~i@Ex$}-6$)fgf{oX`iCHg|#ayNwt$Z+;QOX{W<1ktl zEY55*?DSQLlScOq*V1xId1TqPw!D1;k@RWf{xP-cb)XU3kpOr3AjE#3)a+*Cu3f9W z2~2zq5FPaBqx`j2D4635y{6b((>nwgMoCFS!4woa@9rb|aML%UGr$u^Uny57CNKfy{5kCOEE`6nNm~7f6G2LT2!rDX5yDOMy}S(8vOn3vCbKw+r+I4 z#Mz@8ufCI(=@Q;kZi_7JU3PNUUZ)%1=K&u5BPW|E2g`sS&P}AmZG{iz5FAlTI3aC0 zs}?FenjOq%Um(}lb9bHhGX45O#Q2oI{SWhs=lKN+P?=;IcRRJX5Q`)*j4ATuPN?7e z%`Hc19=RFfm>HVN%X?kDfd@CF!-y$xaeBABc*qPo zaiJ=!808yue>zsk*K`6bcMGg$(b_Ui{DY}D=B7@{IpA?l1#yG964MzOa65}%@iX~%IF@94&A=h>z~)Xawf{A0=#MT(bhSJ3`=*KMeT}iw2bQ(J zSfF;bpt#olvHE~rbN}_S{2frFTG^eW7ZWTnitpEJGM?3)XY@^7%MwZAfwJqROXs8^ z<$=cP1PL2!C9xgITjsfW83t2pWs@O-GSBP#m|j#}Zj8K{L@7flz3HtY0;7xF|AaZ&UE5#{$t2)0=AB zy(TaAU!o_u8iY|xwf@$^-teEgWpC0()0Q#3-E=qY;rLm!$e`0;ThqylqGm7me?#G#}XbOKJrp zc?$Nue35uJ;LuWu;ry^gTdt#l8p7ES@T9 z15cVPugv6@#t?L(0nz8Ne3O(%@iiy^gT8lJDj_3 zLJ+!vsrE~nGEGA59?;0Y-%i~us3#XmKK6_5mOcns7(-|Q7Na{%3UCiwl!t~4-&fvCnf9I z@BEDoFYjrU#qEqvB~f1reLqh*Tj+T(u1+mHLWDZk;JvkAEej9nl`Jb%HqXFjdNwW9 zW!`kkdY|eySwXOvG2$rn(3db;OqSv8-`}vd43ksg-M0`LrtMu7j0k&lkG%fo&?n1v zT%KE8(`wgc7;v5$^LZlCBtSSU*t;VxUK2TnsDiL1X2F9H8m~&>@eowsx*znkS;v`d zE*mKW+G0s4Ew_UpgLDO9{Pg(hk9LQ^n+KJ^ z>^KEaHzwmmr<-8hFO^s>*!#UoyDrfns#rb0H*M4%-lg6I&ylDd`WL=$9sT<_zzHNS zK_awJ&G@L+qhk{fX?x`A-*T~SxNCavP{a2DNMgm*wj_F;3usuebRJ{xd)9;sPfAj{ z4M^C%z=DkMGt_DAdMWS@w;VEBL{}D4s8%P?_(UINm3Uzzh3mBaoppkc3MsD*bNWf? zcrB7t@p7DGR2`-vIzJeBe8V#tWJO!fH!k<;7AGQPUzAvGIOB zrn_Kc>k{mBs~Q>KpiuschaeH0-0}i3jUt4CJ5TW^X z*q#q*-yJxw_47LGiTLxi!xTT*v!d6A@1#%>eXt^R&Xe(0i>51DQU@R|C@9056-i?wZ@3vT2xvz_7>!OfdRzE9SOouWJx-x}bT@|jq%PosB zSF_*m1Qt^!ZuIj{>9|j}4mY&hZ9_Al-Is4f0~FH@r=gJ)6F~^#_;RudIOEip(?_xs zQ{Pu&aP4M>N^CXa9UrdRA&A!Su;YGRwAWdw`=WPvIJR(YpZ+;DUf09{av&tQ1gC<^ zU-@(HH-~kWpCnaQp%K-KmHRaW_zXZk`Q-yFF)`>Oj`1(@uQp6VuT8p1b9!f`R6rED z(jA9EAW>bMmzv<&FvB#!t8+&z?Ur|F^7>AH3WU+oGRonm-d_y3Qb6H(N`(5{krd~D zc9zL~bViYvzeZgHnYRXw6Y%F&zQE3KYNc<)@^3`=4b#nNAAeprU+;cV?6%1JcYiO* zx(bC+%?v2tHRlu_E_mFm)=-G3(|r_3`IhwQkUii}Cw#}H)t)Lcr?Tj^6zK(eZZ!T1 zzo9$Q$?fb(3dV`Mj>#tj>*;uCXIAw^6i&2jhzWAJ&g>(e9mmN@zcWDIO7OEl8QN0| z^~<%!(Q8fmJ3&_?2GW4%#pRbdog;Y*1}aY_7|Z*M9cO?dk8=<*shwsWkpzU4sdR{K z9jmkKoE%mL%Xfe2yH5Y0Dl2kJ35@2RDs(^vuOCrZ@u}S^rAbYPggdEAIx*V+xZJ%Jh@#Qg&-tl~L5Z2zc0(?^Hru zGqW51g!mz2T5*t>ynww4l5WMYX96vNt7nS(YlV?gWOQKQE;*YOoaASgOppEva6q0)VV^y+_)f0brX9^CnW!R zGr;fsx$ysEJh6(Qly~M>O?evKW95MeufeWn_6k2%${KkJR)Y{Ktqth6!&)Wg@St;{ zoq{Tiehl6pux5AO4qjG`dqMo@ZE!od-5K5w**{MaEti)tErA`Hsb}mpwNcr-?a?Q% z=t~k$$8O=`xE+#$>YH0LB^|@vS6iNxY{VF$T|VP|X5O+~PU6NYxWfnpOtr&1Yq`wx z>h@`pYXCo=0;cMiCliL+-KW0njtn+~0bxPE+n-U4Yg*M(OTw7i|FK~C|E-b5l8_9m z7DCRE*5G|fWL>~mYdj|S_=o6;^~3e*3hzLoT2{v6n%%|k_2R?OHqYrprv)u3n~b+>Ts_7(dm!tUs+5L(8Sboy<#Q=&7y7 z6Zbq|4VlMoIjG(;_x8)6=IqSI7N0dy1NB`VN2<)A$kotfl=fa91tN=kducGWtvL1% z{t-an$i0GHg0^iBnF44kP-9PG&W_ayyP zo{=uY?`Mz3Or^9W28c{@$fs<8Z^2y6mN1TWld z##TC~lipo1B6WK9c+o0Nka^Om z)`|c<`UfNGd>A?f02b8HJ(6yFw;gLB1IH$?A=6dxD&jJN9EeW_?vmI?Z6W8&ewv-4 z{=(mUV>azRmIPglUuH;a$YeAFThXk6aHLFJYim67(*)r^23GRFUpSwUe!Js46$x%~ zIWkOxJvezn?({-BxIUJHGbxI!GNc!THwH30IBEJ&rV0%Eo^-P)h9xHeUkUVcIUb$q znC7A_=6Sm(4MJ~+T97z>sInGUg=0DuzsMaIFocq zqXfx3LC-H3i;`tmazc<8q$$@`qXf%}y4Dge$d>Q@Gc;!axpe%-0D z?xyKyj2Q5yz&(2KaMaoF7T>mcLGYyQY5!^=OPRUse?3=ZD4; zTo?~!K%S?y=+CpDC2sHhc#M(qe<7rZ&r1-(6cR$sJ3FsxMXA> zvyWTlYJE#n(^jV8UFl0p>|!Z0NuTK_h7-hXcgSxUmf2X4=Tj{=b6e?^7hSvS$&?lNQ%qh`=?~UBj2&XO{ zThIgXJLD~gwK>yeW+!g7T1!A+YQs)!BD?NJY{x=&YaPVuF*VLzI}(!8xERbE+Je7! z{ttrh8REpit)ppy`0^~t0;jJNF?RocJ{S|?9@yO}Q?=nlJ9~1+cqr|)E>$p%@5TT><&SM(je;Gz09nNCHs7-( z|6>5djfFC;0|p^vzkP1y$H_3#zI|I|?D|dano|P?Te6KOYmO{p*U?D9h5oNT6TY0k zmlw;hXZ)gz{Kj;e7*PWovRR;d&f?3#Q6y~zL5M4ndJM#2^+afp3gQM$w-b)_m}ee1 zjG}BBEqcY&%b{+gMch_mW?=&LICea;f8R(so}wG_|M7+p5lk6?PEW;g{ebgSC(oKTwlMQbv}Bn{()l-nfr~5#5w>9#e@OEw zA0)9xm%4P>b=Zf>H1Y$>ns^dREWc+_NjQ}`4_#3^j~^2aqUtPD5+sx|aD$-;>4&K+ zz=t!Xpq|C}JJ_l6X!EVl;$MKw1omNExPjN$#eD00Ms(hOUHTHt+1+1Z zE@U%_HJiEHm)D9sE(P$Gg<7l;e5;cwrVW#F+PM^zu`Tw>dMO4?#MRu*rWtSZsFfVD zow%0}5YzyCP3&@YU)RuYUQ}Jh=sa79WCH24mUqG}GkzD@JFpyB8Dfx!`zw&?ii{K; zF>~~FyN~3M6Gt4;VN*RHl3j)&f1(nw+>sje5Oa@(3OKk79dIpP{?x-C`<>&6X1!-p z&0tM-`oL1O%k z8Juy_q&;wA6|zX+lR1O@evtF;4YfOMqp%FR)SRvrTXSFe8P!k#T~$b6>v>z`JYg^$ zg3b_^H&(HBPqoCho0f&Sw~`l??YN=6k<1lN@SHwq^%YB?urGe2Epi}or+Iceuln}j za+PYhtG-iRyjGBtq15Ot6byX(b>}N%47K-Tk4_HYAhHyJCTlcUiQO~r@?>@jb9jd= z+7w(bp+&ju#h?SH@6i$BqYCWmq`?*WkHfSzH;O>eid8@o3e(=HY1_s;xsr%t=6IGY z?L!k7QJ7CvW}}BGOOfZ;;^+Gm3QxUc03M~ZxTnjy-d}mPG!2onvInIv^7NeK=qF{h zl_hX(DK_-Wq=iEncA>mr-DUpGNAll)s8~H~LKz~UGoaJB^JOT^Wm(MBihtx-CF?O4 z$osbuLdEh3&Gq$cq4yuTnwQkOq#sey?AG0+N51o5gCNjv%u_L&`@lwQ@@|<~&!M5R zhP7qa*36W zo0)ShtBFOeFqz_i!aPug;}3F6B|^Fj?Z*+B&0N+KnNwL~esmQRKq0o=FE9ygEvD|v z;eBOr^v#%<+S5FQy(SN&-tO$F(`6~BoZY)Bk6!Tv$G^q~7Vajdu%trUTBn1rk!sPv ztD1euiZk^%kxQ!QM9ezX{}t=UR)}PrIl)cdWy#8kJ$xM9rRHTHmuY}eBqjn-QR1C< zL#pvQe=G8Z^Y>kBPWI7`ZgaWsiQE#Wc4Y7lV@)?;zjL}()+QhyVuIv+C6U}3N=#Lu z-q-+;2Fdi12<@!b137W!c-(I=2Hs+Af_y0&o@)$Ii&nNEkOJ++}-MjN+PPD0 zl}kX>jdrC>nKM%P2Q$Q7x?lig5@o}D(`ZW#-J4oh=3hg_dTaVmr_$@-t$~B{ECdhk zhj>6DEjnkzDDJ9<@`mj(`qg;pS-8VFN%Pl)a}yA{fN0OWiEe+QqMSL;|A@LlpSWcN z;wad)tVvc)*8NohX~HbybEI~ERR0|thl_9YyhqC!Dqv!SN7O9hJ@|Nbw!)-Ag%Af{l zKWj^aHQ*)8$J-fpMDhBb+Tp^Z$+8{U9fJ~R6g;jLe4nSE0$WoIenkw$2b(a!-iw42IbIFN(hq{hcY*MrCmx35 zg%~c=VejZ7&$nbWUnmz%Y=XjniB5i7kx!L6j9jVQ=es2&-mVsO;@U=Rw~GA7$v zno}qqgd#=NQn@BK`}d1~;m=k0A4QK==mi82DQTg+_#q=fb(6)gxJPo;jo=H9wgQib z<>piZ(uTk|63^w}X9$eX6Re%3^cnLDN3XoKWv7Aemu`p^#a?u|46U*0;zA7@T{8UH zF?7>21^Na;t^(rG{XzXMI_b>5?6)=dIF}s3?#<#IK34$?+KDY-c-%dFi{bb+^%kwh zX6N?DNTwi-_q+XdE{gUanMdf%Zxn4@L zbC?DJ+75h9)IDx0V^`8IAF3`{6tp@OG22sH^bVCJbShPA>tbC@&`y*SUuT9CL{ID|EoOwJn73;@xU$Gu#!dF`oNj(D*3XD3vY#B zfi$WmdW{tz(uzb$4o2%EhVwjewRU~DA+EUg@~F(G8Ky}X+$!`ST6yPKZQ|ZYELU;@R#kH`*mW$B zX1V&0C!nLrivOX3Sar?L8!-4exv9G^YuzRv{EKu|_C=r?lIWr$C}a3~cp1iy5V7~f z^ZsK4CsACg%URktB4 z&|ZMT*lv=Dpf4r!ER)96*cwZkWN7>&7 zVb=XOLlg!XPafj{U^^1=8W}4QqOe4@ozS?kw3$s6rdi}FS=2Ic{Vzrj0DD0D_5%ij zTME^pqLPqPf@Xm5ZiSu$cK)}D`u&_qC0^_Oz7JWG_$*Ydi@Uh(4QOHbf}UG-FAwLy8B4x6X*VE#{qVd-!q034ehv(`G9 zqDcr)aLNOa3DKQ(llfH%7buOm>v1pvKecxt-z^DKs%MGh=k04>Ncu_eI;1qRken&MEmy*&6L%5p|lhojItdy z>rIf3yx^-G+=Ni;@xIGCq1V$Uz^mhA=~+46OK#*8$Z;-Ue(nG!^cNA$#4jYF=-Zm2 zMBK7Vq?B7$zv0Q98E6;2+jpVD3ngo6B_xA0y^yByddR}G?6zztf@*WkH3e#&mfBxpztC%W zp}NfBA`JMxyctZj?9g5Mr)A+rN zRds{EQ>@Rms;M}Bs#0Jqvk+UE;b@|_xNR~9H6BEM^8+cs>=Z&17zyESJG;d`+DvPs z=CmZQj2Ju6AZy=s_Xl%1_UV#3SOKH3r}M6KxOc=7fV6@26`We#K%r8eyW40hlD9S6 z_UQh#KDjb`h6YzpYKpwO(Rt~VEW=TWQN;&|i`30$P(KjB%PNPMyLpCkb%aUAO&Opv zSFIa81ipn`p+7ZAj0l~fq{d0E9cNLvXwl>%W@7tJC(a1WQ!$HhHbcNM4vao9Pf1N3 z&EBBTn^%WQ(_#n5z;)j>;cWOgS&(+ILmOpQXm<*~FcA*vs2JO#FuXVzry6@M=KFql z$?h>k)&$#a=Xwcpx7aCr-6;b^CpnMl8#7e}Y(;;h z*IAP7cA6in=8X7#>||D?og54Wv^{;l$%-q44X9d%Daa+=BJv<*c;KH?2od6}43oh6 zfkc%MSj^C-bsT5XGgr^=0Ty=XL`Jgc%0lZQ0pCW*iSAG!@mMo)A7{E^4bFax%61|s zSvd|4raJyo>EQA{ld4p#^mdUgcSiSl^T7Qlb_WzVvu%c9r0+Zg8CuK=u;&Lt z=ES4QY-ouTc@>UBe{_}#MtVtf&-GU;gK>KL8uCpB{#rD}(LUO|?=%@9oe5S#{?Km9 z$O}}9R|%UUi~dkYv=bZS)&L}2GK%XUDwIYrqy$!;{?eiK7&M7BPgfh;(vuj2PuPF} zJ(SepKh)dII^f;gd)tW2P2_45JGdp3$vuN&CS%-Tg2s_7mmP|W;{F*3Epg@r-G@sJ zz95?Eu4*0Wh-sbI#9`3n!}FyD>5Nc`$XariArub?TXP0OO|_ z(e!04H~_9)+MKudM*^3G$*Nnn98IB@?Izc7MXnOeiP8F$HdCdhDt2vOtf6w3ur6er zHIO55z(PaTsUQpb2v*VN{o~1B8w?zk#q#VMt0-jVzRpzY?j|$1spxilf3nvz1kljI zsBeml?H_yc5Qq=`P=(S@x$)yl*kH(ZV zMu)7%PXrTEX!rlVaW^g) zYL{?zzu#5_xlD5ucFd#MyuJHcQn(Ox@|zZK$bb3#Nv<|<{rb~ z-|^MmzAJc$n#bfICrR>+l2y?So52qI*xpVj-R~`H(#2~g?l2Bs%kfae=il@ zT~&Q(v!)w6Z0g-No-F8pKstVbD<9Kwc)w|`_}httfd<>mi9>d_!TOzK?ws zCNNzYiWo-o!?p60DkBtXwxI%&0HZ)^ZmSo7nAGO6&jrwG%!#Fu*GrO3~cyE&nj zF=i-eKj&X(e(4^nZoV8sO`-@Rb8OnL5&XZclqmDPe=o1BG$VJOb+p^Z-rY@oUaI|; zzv4d}xDbgwHI@OSbM2pT$f_4TQxGWDn8653lziz7{)GH=R;L^ww|NAcu{{u;g(YzR zg_Nx;M+u)j^pTZ9ICX~xsj{cJ=zBCj@Qh0fp4nbfSSi;8@nGObrzEY+`6CK!ML$L< zB;lb+t|JGFq1YDKb&&1p`m$qi*F+~} zSFUOF-DEM>Icj4qrnjW>MfJ~hg{m^ec`>g8Gn(7P_T-IMR`|lz7c=DQN-iU{$Vb84 z8``6T;@$~PN)1h^798T6bNzfKGM4B68CZ7A1hDrZam42KV?4|f>sZ4E)%&`hONb#md|Qo25X=d=RzjU<8Z^SfGH_NVtCHZP z;`6p;6DK|q&9li4*y+^#<7P15CYbo9mzOoL-l+^TLwfP-(qz~vn1&#huFdVy<(*=_ zWWFBYWHdsjz$j{`b2{KUjEk3v!#{sIj%)FzP|p`U7C1(XI4&m0NVpOA;7yv{T^*Ij zf|3~MrX%ga#9+hbeU9Yezg;ldKs7YXXqKW4?&$n2Qe2m{_PNMoYgi-^sDa$d+WYb_ zn9y}S&8WYZoVN5sBJ?!$#D%TMohpXAOZy>i0=s&S)YqRNzMP6dsCs1eRQaRe%gK=> zOgW=U*j-=|_;x$U<>l7Ia5oGOH(}-<-ZOU zBP*$^$gpo!M=X$~dgN2OYsS;dh_?q6heK*$V@6ft6uip_SuMi97KcrI^@UHxN3|Y# z*cPncfLwX3IWe#zv%h?Wd=S*dqyKf_(G`WKg_t0_^l0X&IpW$l0ggo&+>zbH z|90Ni$Q9(va+;)PoF(ewF=n%cv%Bsnl6S&^R!(j8Y8&W!2%rpRPGtRSuT2PZ#i6| z6Gn<*qg{SMMuVD?__D=gxsvD$zphy+v!{a@2-c*S1{j*=+JW~V$e#WCoCBsjuOryn zYaNiz+lXT~gXTYzKgOeL^iHTDI4j{$Rb`Jj&3YK7kNLiFNTf_73-DIK!{MRKB8rBM zH&g{^M6u>l(Zx+H9{E<;20s0xd{Z+{js&hhzqcNQwNi=Lf8=dJIUxMD0i>B?Oqt6> z!Hq!?F>^=033>vkUCUK$(6F}R3yVh{GM(Vl4gSm{NQmR=9JCP--$pAdM7SCg7Oo?u+yqE{2($1dWe~<4={O*ozkJxN>iZu>S zi#5HF$*OtOI4$q-Pl(TiW=8^)&6O`Gd5zFF)>2JTxAfFhsuU7uQ;Y!A#wJ+QhZ*E>to_awk{FKcALxQ=Ki zk%yJ|)Do%Fdzrs-fUg%8S3ROK@ZK`rmWklXyqB+8>`~KB4H^|q-*qIP@}r1SP(jy& zcY~6{)DF}Y7gSo=73JF|8Uu?tJ<6{R%Y^pj-cY1=CDHQNgR3kt^T}dq;UdCA5%>eI z9lj);20T9x?XFaa@z+TIDYwwRM}UD!FC&muFP0jWE_bDtS3-3|(FOhWnEI_`V8~V(!t{@pDCIY7 z1_37*flxE1GqcdfthO zV-5F|iRwaKCBkne}gmj>YDstU)_Yl z#(rqP_imQa^pHz9W;ku0))>bX?!_>ICzz+Lm-^5yjkxHT0-9DSq!j8yv)o%rn68mLKQ1J?f zgt7}2@qzwn-9Zie+_Gmoq`!A4_dErLO&T3H<{@I!o-rndgKvfPF4%EfZg?IGy=l&z zVPS8-VSd9$5_Nga$xEKItd*}GtI?iX)4Z%XBtOSmYH~ePx-tHU%!+SsW-{0>JGBuR zZ1e@j53}OQteG#TRbC&g=(rYa5?`(GxaJe6k?KO+niMLBs73BF(>i#}Gic>2x-wD~ zk6rsprS+Xa4&i3}FUs<1T$t^f@$ba|@rB=ny-s#k;PZ}Lm{f8FndQ>m7-VCXwD#fk z5mmZw?xT4(e|`H>T+sDg4t!Zl4MNUjrTKY-fyh0K%BEs`_L!nkWVwuslz#VM&U-5v z4EmFiVp=PvA%H+B}jkw{#8=S^k zqirHKJyO$wd_5l=GMfd#oa9dS@KvekWTO}Fch&rC80a6q$N9rwFwwY$BXWeu8wLzS zQM**<9Se;oYpX?ygS|oIrl~*37}Rf;eBT{cCQ>E>ulg)fA{271h0``*?~V`kE74M6 zG`Q%{*ol27Rj=sKl{e%di&C!I@1A{CgK{>z*d_Jg%21X-s&WW#hf9iMaM=G+(BE}o z)d=83*~dVDHGyO&vS3)}k5% zS!q4%3P?%)JaamT5C9(T%3X4rB|=c;7E4}1B2pUj<{9x!m+ z5!5c_+&j2x-}8HEBa3^QbLAuWj&OtWxp^oPkeeGUsO+(PV_eOALtrMJ_(P zZnx3ZxPMA`p`kMC{?wI6|H{GyCD~6(kN<-Ds%Tf@Olc$sp5Q`%LR4k5B@!Cb2`v5$ zxwwLH<$)D?dDn8gki)KfYi6_J_E@_KkL;R6(LU`Bw60Oz#JZxJE+NlAX&x}KC2BcA zK5*T5l>6L3y}>_7FDwYE)OoAvc+FK*8h!rPm`CtoB`&oXZq8O`N&v3T!SxTgOj+A_ zVz&6s<@Ft&u8nF2B%Zt2t{P_$c*UVAMJU^aX9eHARYif3J;QUemtgBbAHyb>oh_MQ zS)6Gf;h=9bu&TmsS#z+wqMmUHb- zhIZRop(DXtI|OXBO*GbU=%Mc`4o)u72tuyp{zv>pRO*%S@;QO7bnSo6lvZ-k?i8Y! zz|FCM>9C+l%GtTTj_dSzpaWshB<(D?s`dOyDPu|Xv=fx5qE;kH=ws^p;zBv8%sOPw zMr*knE3Dgu6&9(KKQEKtn-*IFA2gPP-(|PCY&5WI2eE!}5rvP$$N_i)>UKt39Fhl1 zH*BZxA^bZxZoLTn7bDynq0MAVHLueYFPAS$x0M$3UVRNL|#%|LYOH z^5>@f&ya#poQ4Bl34;lLuEgw&!7F7UNE0(DX=ddn^N>R(X&2p$;Lz3K%wo3ej0=)l zm}i8)wP7fLSD6vS-05E@$Ieo>R(=S;cvjM22C>vKDqttXEcYct5HaIy9^QE&k61wV z@{k++TBY#=krBNGyxGMU8ZNQV!6NE|<23B!J_(djh0+7_Y!|Cy?dR*P#w;p=$jT@_nrV>Nqba>uPqI?wboSgGRZ8i2>UqU_>{D|<^kDmH6@5KlwXdnd zU*)LBv$uxl-+F#Dsy zgm-~w1NuA;q)@j0j{eS=8cY3NV(WFw+~gKl-?7b5wa~uuunbj_v$9*%jq|cx+L8Rx zptrJ100znS1|sPL4j{r5mlHN1KclTy0Uya}&uxh)-phur*iQ7Fp)@^>UG>=JbE8%r z(B2xXmOE-!YYCaTzvpyEOC6QiN5qvZ;;lZlwJI8w?JbnxlcJ`Rx4?&#W0c}$p2-jN zRtm`leC#C)s9oe|g{2i^FjIkROG)few#un)XZT&DQ}L~8gnqf3T+?p`c3T+;<7-pZ zTHcjAgM_1+^FnpQJ}jCW&(&nFegD^W%10=iAbYiQTisfvpM3yPg`HMb9C6q6Ud$%AkQ2@F&!>%jO+%bT^MNUKbhzi5 zFEW%>zD!7Z)%H`aY+x_JV%(b{+HWMpj$Vc!=p&`c)eUIAJo9x)O;<*1xDu6DRhjnp0{k? zNC7Il*!rf6VA-BbLx`QAU+F32Q$gY}){-u;Y9->>o-&KCz46lA7GuE8C#}-GlV)cq z(@H)H9~6e$if}#0!Z7`iHW}t4mZSPJ$wYzMpxhR%h#oZb0-~;=0PUG(48-!XD^T#m7L!+lKu73a3lz5CdV{ z5`iH=8U0Kw)0m9@5;}CK@}@F?!Fi%K8Mrqk zn=>ozDcoo2A0E3cm1mj2TPI^e;Sil}cCF{52B!f;WymyO71fuUv(S$KyoQVS+?%rs zRv8ZbQL9ChY1oIZFYV+0vz0qIt~Jsd{#&c@=oB3h;J!n%vuA|ZaC85 zbtcg0q~6Ya=B?izUj4zx61o8Z`Zj53o4Hl>N3c^2%(>>?T#Sk5xqqzkq%g6wek&0A zf7Nk6UiO?>&W9OnhKjL;Z*TNIic57j%RP6TX}9xO)jYBjo$52*mrQb@3UZ;GC7zhl zDBlg;!Y@`gyb4ew)Aa*r6?~B7yJV;G@F~!2^|!tXhrd|7xb7#%888OjD;7Th=5O4A z2`4S9InjNqo3qwjfrhMz80hmv7>k1+6ycT)Vd)U0Bd0@eEl$3aoDNSM#Xt!E?74l? z0o9Iuk_m&n*35Ba{lj4fTW3a2YW;uLE)2+R{qLb+^ctQPF&JZNnsDF=fq-2U4gT^N za3HdHH~&6=1K7cA3Ch1!pai!Uwx^^)zq>WN-?VkkJnuGtW{iGi)7{4Gxq3DT;EDbp zSLd`PSd=Z%v~AnA%}U$0?aWHswr$(CZQHhPy>;LIg){az4>4EF03DBDC1Gk1r6YrC z9EYfvW!`99K20v1+^e8Kk+!fg@QIc9iQMiYdqMXc2#}ZoHt>${S*h@o@m8U(%@LA& zNVCVwlyZm2$9+2#yXFiGVW9GPk?97sk~G>%1MU})n0mH;e=caNk%8*1Vu-d&lCMdd ztnk_A2Cvv1HOBy|z2=DZIb!+&TSo1P+LO-G1axRj;#zl>ok3M}xt@If?k@D>fQs9PX9$HJ6>mj<0+f`TjQk&c50ZDY{#W zEaMRqT&QI8$$7^)APih5Zj?usfUqLl)5jF{ec?Q!FLn$gn=NK}HVeD(67TXly}6I- zlXNqNps;0hvisszA39_x@!!%#^E;!CKbTeLNtlx_1hy-kmJlm z%GDhfBIK~_ou-tXH2ERnGy66jcJbU_7-p-0;aFCKe>aZu^-`>}e5)FZ>1vsUCBtzILzGsU2ipnoM%s%ndlmHw@y=i#|nRdS0+=^dl=1&#+6 zO%EBa^!MgifcP}CDoOMzJKqa|7@AoknXX5kR8{&@AG#8&x1C}@FtxI>Ta}Kcfa_e0 zQM`;;lmKzLf8?8eur`lzOV0Q{qqLKL%f%qXJi_!l=!fi?rrGAn@$13WrXfNZ%pT-c z&aM|9xj|d^ix4(QFGt8aVX!Uq>DCYbtMl%BP|%GfJE`?lKtX9WNN0XA^$JLEs&8wU zln8NLauav8aAS5#-8bTFHj7$YK##vBE2Xwk^uqD+=L-4{x)rF1^poWuT$fDgrrN_!{{2@)3ju_bR>0* z(Ca!ug}Il1k4V?`;iOgtQNlV7_RogSYS1X~R3sN=w7w5&O^@m*-gG?@>hbM);zEg& zyy7%1_Pz7v3W%$;;VK`wUY~Y>U*raE;K|`I^Y&v6R^;j^U;1_y1!6S-(~QZ9FtU%_GDGW2Ij)%m4?^}K zC*kVBSnfb)5>^K_D)o<)Gdrl^E$W`~JX!S*UgxXO?Icd;pMKC@eJ|Ml7Ba_kRfQg7 z6v-49;ALRA(9|3`M_e17MNb78V<-O%IN!~ARMpDBr+MMN`n0eurDY<5L?gMXA* za})2$+s>Xke3rd6`~*wBuTwEaHdugfZ$5tEIcqlC=!;P|;X3*(_QW5G$(Yto47bC% z-t!f_&(mgCXn>sn(ASlRAqOQyL`KBJDPmHU;PB~aoH?)CU;gM8YcWX)8ro;3n~R&h z6}n4I8LV&9Yewtjf<%J9-hKq=OusdB6(VSS*9e@8dpfRZjr+Uo!cfJPtBkJC^x91{ zN%R1msX@hr2BGxpcv?LUazdA(Acrt3dj3^6v=FRzU<@R4{5cSRGX&&$!>1-Q(+Iy>5NjPk`XtJ^)8I%4g z*RwFJ9QZZ~!u^J|m(UlS&>g3G^YYeo(s#WU0raZh>S93A9|M9Of~-#0MzeF2v|%vM zO;ovU$>Z2;=hSJ^99x(MPp6w(aSkVqj#!!7^M@%n~-HRw`j2R1j&h9g1J56Dp-2gaBM;iR=?5hIch4@WFAOH5llUAgJm&O*F zO-Q(dYUtz>#)C>1QJ-pvrdMIRy`V4dy6JQWWA%1+Mbt6z2qULI)%&O6T;SgHVT+tY zfjVPkICB+qiofQWN(Kgc2N?lal>I|=0g;&;vv=c2gy)t~`v#rdz*cv1?QiPhUW>!Z zNSSc?0EooVOJaFDLRX$x9X{d{4;lWIiIe6}RLUZ44A8t%t;~$Cxq03t(9aUf0)w&m zhuX6WqOj033LEuahE{8qpCMa_sjjF-acgY5%LfH%Dj=&vQ{4;$aCrQ1RHR0ZjusoU{-IiZu=bTI%??Xj5{)fZc+}Z+&omSrKzs*x~CBU1XZoU+^Wpd=B@?Kh0u0x!Kv6t7 z97emSDq_NzFoE>`%ZRnj^u~KSs5@d+1E2gcwH}T)R(>|uIY8&h!9plfx0hI zdX0D^aT&Us(t>2_h&@FS^kFp)zn8AYw|E*)&VBZ2>SGy|s}zS*vz)#(7YN36LDHIpgHcO{yON z-VwIit;)3jQz5e#p1wlgN{@vRq<0)?cZ+#SD~k%z)N+&u z7A0?Pd;SDT*|~mJly3@84A`d-$M0jkJl`W%?sL z;yAf=I1>X|RbB7qEb-bm=egZW{rR?nB1h@TY03bwRtCt@3CT(lXN_DN{Okn{o!~a3 zSOCvpd#w}6$<&m~m1vUr>k}solhV7*cKuSI<2{(T3$2Kx?^nw@xvOt=wi7^mu*FGR z=i2S6yzTsD+FhA~LR~_fW^imWCs-Eljz-T<-lu;S1*{VsJ8<^+^u&$!j_K;J+6E9k zkrJZrUl5>dtP|#+7D;6)z-}4SdnA{E;zMW)CvE2bu2~NAMRhfUPERDU7 zwsV6h6m@hNS^C`{5ZcY*czn=i_B$Y==)Hw$krMU3p|=7fSkLa1FN4>h@Ai2!Ucs$c zt&}}Gw3ovBhIG`tA!AQi*2q}b_)mis8s3r4g=2_YO>Wc`-Kf5bRXirs08=v~i4{i} z%Z$aTz7kTE)qnEWz|ADYM#eLqXyB zfvj-~Z>MJpiwy4uhQx$@zmL;*#-ae70yWH@_kl1iQh%v_SgYpz{))GZY*0?gd4v=C zwjNX9%Kj^DT$lVrVE0*7^PZ#}#Fw9yp^+D$H?BL|RDc_6-$J)pi$K}lfMA3sjh{!o zOKj!LkNOJBN2m;|iVr6wrC#S#H{--WU7A|r^w=r?BT}ucRO~i6q3-#QU4^A6HDg~w zfrl~4i} zY7wDHz&OA*ZovYxXX?yCN@Q3RMyE*EW?wP5Z~hg!mFQe{YFtPh?#1`-TXj~aW@+^R znRrLlca)iR{d29Rfo9h=FSySgbpA-O#%#C8I`}nc5%3Ra@P>2a zv)YDehU71{ezyG1kCKxBt6Rqay>C@Bc0z$G!ff)4q7K%lZw4#!fb~l8sP;i#(OhMNSi-6AU5Tg4KUHz_ zv_(BBVkAko=g>(Rn9w$s3p7lu=|NXJ!bII&LB98;H09Hm{#HyiECdw8qF5Z#gPScS zgt6hH4e2?|m_OOMlAAqmWD-&Fj1Im|FJi8*H7wB(1Ld-&JVWLlV|gx)YMj}0%co?i z$%&Jw8*B$*$z^0vqPgjpLw}k&(@2b?bukJ_nE-2X&ARH<(wSTGfsfHOd#?KG*X$ES*Wq?nERT|b_?*b`ze5QWU)0ZL`lgBWKviV9C zY^vng3k1h?856d%F7BcMV)8#AJ*c5L3Z$@9XXpZGqz?F>O(Y*Ud1Zc0of$nA034Ei zXvxa%Uhnpgzb>`fiby?~dRaVRc+hVxKxFUG3rj`5=iz9vn73=FcZCZPYzIMtYKi}W zkbqIk!EXey4yC#0eXOsr?XF7C;6uMr8-D2J986Sd$vV#q_en?1+%c|jhcvz-tu-fNak{ur-&Zh zQDeh#@7B8m6hqi*fS`x?Z*dd;k~8gMsBEsE{y%JIBH9F6;SGNL9!pa&eNad~-gINS z9pXPX0airNun~HI{Q~PeveO)=R&uG2z*#0nLg`088GLt?5V7D;3Wq{6#j5^E=o)$n z-Q-Q5u)&0{heZM4g2Eg)wp4VIl#SkWqKC>4LwBrka$b7Ta*N&7gxw=^b*DNO-+OsJ zp_w!tieql`g;o)6y%8$=8x__n+>bG3WDvf2Zz^Z<5NqNE6LuLBVFV25C0hJ+dZ#%jE&a(Qq4P~vZ0&E#PO9M21O$Lyv~Q-%|n)5LVYrvMOJq=g_I zvF0&N-tz}nJA>XW*u?>e_fpPS;8+a4ZT!x?cc)%e4;1(|h=pR;7awy!*Wxb8;F3i7 zae&d(H&izyi3^~`AOF{3XCzs_GuAw1a$spttY-0)CKC9y0O;{)KxA4x3Do&)eqZMv zqu!jhuy@VPFv{$abS?=Ot#7dsd2~S`$rB(|M}M1CL)1akV#xxBZJbum$<-vm$}t!7 zOebQsh$wL)n!F|Uy)U@^YsM0vKKFd9>OIJOb>0;#m72sQFCvT*c*7;wlM|-Kka*WZ zUJ+FTtC<2DQ)J2{K3%Y#Jwg}Zg0hR_LLI!1n&*>U37 zi-Tc%pFy}`2ixbMF_BvMW4%x<6aE&?7m zc$G}`F%h}tawFcQt@F5!pWrDD>S8TXhtsNh+Q)1k�IKWUttg;h=pPYIl3?6@WBZ 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 z⁢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%0A8Ne!d`fXc1ZlQ-F-J10Z0-FjR*6< z2{)wMLw(ROY*H`fx`-V*L@d(kc{7CzgsHTD4`XX21s2GNTN}GTOc&<5uzi0_OB2`U*%ei{<~YHIMw{9gjY2rbH1dC1Brk^MYbg$ykf8GJ~n_ zBk0L*b-mBlGF!o{sg){Q9A^+-3=N(GS<|-Z_1&~R#*b77bKK@cOPW8QeiyLQINDQf zmMA4dMb5E>f|~gD86k{vL~M9XcA^>5w5CNW81u%R!F>cYtKN6<)~p!{^>xrjD6^FX zsFj60jJ@mNB^yM@OuK{oG0isjDkAp~Ei0U<8n1Qtb`lNN)O5^64>(xRxlbASc-`Z# znE{E#dKJ42U&EJy-$Ir$r6f;K5{u}W¾gksx*(4=W^3A0YZY6~w_rp%dEo)ysp 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

nfHML-7KVx=gr6ip6=rjB^vpu{(ofuHYmr=b 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

ZqtXD zp@DwBVX|p5j6wG?nr#iXxP`Q@7_s_r>qmHv>W7B~@52n1=NSp)5vLZRm^na23xS1j z;2pku{Wn09np>{dt^ZTr{IO^M_~u8>%_WK&DK8IEta?OIBlWZxQSV_Y zcoM~UkOFHsgDE79FxCKW=wmep+lLWA!v+HjbLK>2lly^_$MydJV8MMEuQ^pX5>JSR z4*y~ddJtum^KxFo%k5RClo`9EqbIoR~vhL|(xJFqnoBEid0u z2XF=YtNs9RjN4jIU`&3c3?y}FO>+@=aFV#FhaT3fIN6-^P1y+fif*KHYvQ|>NBsjH zEs9(GN-BQJH~?|tD8x{=aYkE+0UpR;7I$sic=*^^?Wjg5ERk}Ss5A^=F51K$X-{L? zU*@x;lE(sgrm-)Mi1a!NR@Oa397m^y0l+p4f(C}T27XA*V=mK#@Q9a!`{WV7z+|od zvN5!g%e(FvzvyXq>+TlFK;8QPv&}!6-}+M#o_yCzs)Sx8Rm>S7Z1BmL>#~wJ_#wP0 zR;-l@|9imG_8kAfi?;ojSKafhr`{^1`0K|sQ|(J9JUt1?uAOCj<(!d})fzqTzAO3( zRcv2{USHyR;5CQ--3u2_-g~0VQxbanECrcayLzflx_YX3y3BH}B}*waD~c2hWDY)s zH`yWy0YAL4=S9D;{%Jt1!!32lWsWkT)y7jv=-((r2}W&+%;uzoQd>hgBml^~yS8mA_AGET!%L~gdbrgiiJBR5#K;kq=;*O?x)F*r zUQNej`lKPWg;OVM;?Kcj7}0==KL-;AoSNW(T})UJ54_zEEg9M3B^(1Md~1bME1Y=R zs?!oR_X%$>mcFAN!^TocUN=Zj9hE#<3c?CB5 zp|1)ZmfJ`e@@q>z3rCc(W0<V8j;a>kG=R;6i?fc18|H+D zZ798ae_Ap^CTIT0K>AkUp4#dbRD8B>o8H-k7Y}%4)D5M|6PCLrb1)ihAY$C9?-W)L z2>fyYQ37VZzz{NKL4fTpk_uRugX{kUz`43by5IQ7>CgOuk3KuM{;3|?Ix{ySh6ArN_!#J>-}JV{=k9;xgMV|!@4f2q=iPS;{TNDrU-kS2|KISO zpw!emjk65Rb606Zs<%~^i~sHUcUt$x==4*a554N14}82B#W*em^fOtipiqx=Wwvo#9ZHTliGR!8Vlvf#yxE*O!rmR^sR$F3U z@gUa0#mfC+O(8Z=PJ$9{gai%c&ht+=kwzfjfo&0K7=ZhXic{to(S~}j5dJE3O9yNa z0*qHI*a3!l)3d5gi&5c(6L46Dm$k*QOJ*pL$KGH42LQeTlomq$NMcKJek7rtju3rs zxRRy;!(Q;oo#|%Sbi1yjWcIGUI0ImjoVu{lo$QFpAYcV4qVBcrWuR*d7;hNXqN_gY zCLqHXC1QE|;v76zlo){e_Ik10mJJyN(D7pr$&h+pwlHi9R@TM0md4`bRYvUIa;8;| zOe8>YLg3f9QkR_(h6r;7(9v(833cc*BfX;4Jutf{W5dm2v3IZUMX;L&b zcHx7k_SZR)QseDnN@;i$p2_Z7Itp3>U{qo?4ZFxDjwtwfp#Wxi;R|j*u3P`#dilMd zacKTu;g;UbeR$n_PSzQCB#*>+f6ix~q=f_RGm(e4Z##Y8!5i;C@6%)6@4oV|*8TJL zANTJDc>b9?y_)72%9EWJo6cwjP$~)yV^VBBMY!5XojK}TmB)Zz+`0b^554`DkFKKE zqnj`Txy+?BveVR4C@vN{uH&5LR3PR-=5kNDQ8t!J=G%ZU;EFwT{GDB_+K%*7wpJ3G zhGJi!1&_J`jsW98)UX=Mwg$(N@CBpCe{ECWVFoZjw(&Wa2KTc z0Bl4(*w}<}+dSr5#U5Vn@#;SSOyQC_nvPvbzA*QEBdw%N6YhkDz`!>&; zWdzzF^m24;M)BBwGHKg}7$NP{TPA8ceuR+-#RO~sa{ViP2d1HM;Qdc<7`@|&k5INY z8G#=c?m;B(R%kznk>Clf^du}(6vIyNY?c7Kcdh>yu&p`2$;SGV^ZL~P^M7pfgQpKH z^w-TO5z4Km$0AEdTLW%{qt^WcfBW!uD--vcYMT-tTeJDp3I>oh2$VRNN@hdELflL}jlA0&Xr&Z0vs7FYVg@{p-ho zr0=Hfb(vGCscw9Rqg?7_<^tjLmd#bg!C_00xvaQ+qC6{GMmalTN@jFz_2re$U;K#* zy)Vq@V}W3zsbL$H;hbyD@kv^N61vq8n>1mIbl7tYn9aCsGEKIWUD<@XrEY}ca_V7Q zNAB^L79x7>lE4Knw}mwXPc$a#85$W&)uY)l842Iu7>WhdgDkZ&2v6!GJPqSQ0=LAN z9)rxh%nMR_LnT_R8;_{Sl)eH~=(2oyhpYYoaH9T4_C)VAk;+a1)#F@1xFR$kCg|*V z!c5SW;yk#@Qi(_f>~svU+0`k_S-Chx(fH`b5k>^l!KErfQuUDr4<^3gdhxQ}ff}3& zP(L-#8jiKp73tw%E*5(>cuvw@u$&G=qcp&_Ia41wSf_v)#5Y#-0%?crcMUQ{32ipE z#mxx&;H;v9Ud^$w7*by?1~FzGJmA7U;PA8(W9r4lBnP#&M~K#;cjlvG_Kxk_cWl4v z#hDP-{k6})?;kn)jJJLC89%b|!PENGU)7Tmr5-AnaB2^%2H164;L=dtP-QU7j4Npi zSeC$B$AzaKus!>Z<40b;`~83G-un*Tx<7RK$L~A3!S{chJ@U;qu0)OFNL>VK`{+E`nT3SjZ;bOzO5(xF5s zGcMx#CnSYs8ayXaNnz?btpitUjd@3mq?N2|v@hd*_LN+f`d-8!>*F)#X9fi|J62Kc zy9itoAYe>85*@KT?hYj5h5#;6Ep;QL`^C~S$4NomY)i0-Q6JTDN6{)eipE+iL^lk@ z0Z_V8j!X<((;`*xRF;jBwHBh`qFqaK_{EgXVLq0vi}6_i3=IGVHT(ceJTUFfP`bsU z@2E4n-2STHWAV3bG8rW(Y06Ojm^r!dJP}!JER)mx>8WNb7zRD*Pbz^#rLEhZ6p~-} z_AnJqwA9CS2#nySYNZ0OX4#iK!(r22m}YBCRq}X8G%!}Xqy2JnC(??F%7`2xtXsaUqdQ;b8|wyDz#y2*Rwm3!a&lEZi1cB}um=^wmL z-z^6rWECbCCpPsMu-jh>T0aJ?ru4=isR};*Df>BH zb-h%XP#tbn4z3oi_Ej~i9V;=UZa7VfqO{aig`(^0J0etV44MmZylNnjZp3wE#!x|# zqKpiidYKf%Ml1_cEHxow9XG~ejyHM{;ei_fAl?KmkN#r!hX2#<5h-@8sje&uiFVi} z#f2Nr6q8Kr<=}#}4MdjvHYj-PI$9kQQ26cv$C{`zfgq%f*=DF1cVGe}a*z%qvt_QS(m*U}Xr` zFLz1KPyu6P6^#ejR>r-G@XK3eoD{bfge#zoXy~N^F<%vl6};CB(gYY=CM3JdLWZB7 z6*Yd&lw~Hqxl<3mc$2=Ovn_Rt`=n)d-lS?7KSxW z3fR+&O)BnUa2Ts+@oG=iF=w+_ioA&TqQ+ z%>Dab^l8U;)MJ3=+STRUI0aqCq)Sp~kn`Ip#h@}YpIqCHtm*uiQ>68fps1IQ?ybRN z!2hMk0R1#z{ks7-Ri!=Y3H!bBzJ6xkWqy=ZF5;;v#x9T4ph`zIM5B_pqGrV9*EN_D zaupes$`U-DY)Yz=StK!8%zg@pCowBfA8={+a65Q0QnWfs+CazC;SzBezDtP>+u}wj z)}m>{$YZCN8EE6I@-r=rV;?Pg6L{l>$h~;ZOdADBGbZE;9ib=K8E%vf)}Rk|SXqq= zX~lL3&$Q7wW~F+)gid-!*z!XIaANvWeVCWkU-gUM$%M-UJUuVYEM%vKlzECIDC^|K z6F)DcQ8zN#RCZVoE6&Z9igm>oCJ^eeS0eeXDv9@~1uU3-px6-(u$Yo21`dMQL70pU z7>Y5B!Mr4n{lMtAZ;bEG3S(>ZqTSF zU-*L`ec}(D{f$!xTsvNMbyO$?=(i3j!VFDQ)fvu`Q{T@Drq*K_Tw7MOG)Q7A5<)QWU{b6QpAVV_E| z(^Z5Ee52| zg;=pEyQf?6sG+?Z9$Xo>J{G{+j=H=G;h9De*yhRlQvJ-pWsq0@0U+U$BfT_t&quU4 znH3U?YW@R|L>QDrOMM3PtX+mctR<;vFdCM8Rwx4dWeJ@V+98G8it!Z7u_c<9toxM} z#bW}FIxAGup;q+r(h`!I4_HXp#g$;&`SHu|8c9n~`itA7gUt35j|Yif*6kzO#Ak|t zs=>-=*qaX}4BtHxy``>U_ze9T!w^P-PZK3Ry)7n^a0I}@7+4_@qJPg_H~)XSlpNjM zy>I;=c;Y`k_v(7ewN_AB|vfR}MSpdV4xlB?%5@}S-CSq8lB69E^>YCcV-1yoj z9oMJ1Kl7q{^~r8D*L^bZwhuU`q`8voW$N^ZNg935AahBq2%l+?E}ppKGc*K9hJpd#nPDdsWLsQLc2Wig47A0J=<8+|arle~j_G$?s-IBW=#S1Am2cHdy zVtTPxN{X=+(nVRSjt`Zdj>rhJ%+M@SbE9J80!Tf8sjAA!lAi!btGe0IWP4lXYZQj# zSqZpiWs3tg8HYlqXms!dYWhPX#25}E;aCOU7;ZrtKh-qSM$9HNF^#WCK;CuNb^V`- zCfs%ZC>eP0R#M4xzp~IqYXFY-{HKf6mU;k4!2Cl@aZO4?bJwcHRErj1t&8Ae^S zO<`GneG(>^;V*erZ1kMJ z0u(#Z+48S>M9a(Qpe#0;W=`2-P0mfL4-p0}XuZ|ItG~c;k;S6%iVoCwsKpY!H0 zY*CF;XLe!3JGY>bmD z(|>O?B^|u_)W5S`bgX#$$Wqy?jc|Ig>viwnv-b@TecyZ5j{zh3HxhBz!TH6GRqpln zVtYW>1pBhbeY8}CLs1xKJe5?V(&?cDD^18&+sf~;UkV1wLxyCg1gsI_{N zW+E-Q$nzUz6Rg-R(NK2dP6vpd5mvTvBsNs%tGcxVRA)0xN;-_&1@QP%-`3!m#VamnQ#OI#vnqN4!5JjnC4D7%QZB`k~Zxs*gA_g5V_CLJr-+$}= zK}M(fhV1gGzi<8hYrbQ5v#!0~FkNS z&pCPaHMhU*udHwVN!z2efBK&!RN^|rBBq7woL9m@c`c03nl2Yl+kL`v@huE&5bMdz#%MY_W0JlW;ih#WZyCv`rMRdakq1Y4ZGn;EM!0rZ`uJ^dK4 z{@s8i^M>i`V#g}?X;K&EaqX?Ys8M@V814+IDfS@0?~B?@%6)<>!+R8yhFGV3_~4qN zuKdE347r6Ub!=5!WycKeP8CAwL=tG9giEn>vEg^l9P|~Ys6lS(MyUMiAce9YjQbKp zue9)c50Q**fbzqV(;1`=lAw@4va>yu zUEOl~EMQUcClLv*1N!miFvYDVOX48LNOSA22=$J3vIt3Xza5prutJnAF+PA8=ieRBx_^`m zJbZfN$mTu(BZnC{uf^w()?B9=mh=C2pLI*`*5^O-z(?;t^zQ$5^T|8)9|`xlu`<>N z)h8!7Cy?yv-4)&tj+VOz)Z-jI1du%ifD1C(G2pcF(1#2B=5SYL=OsE=5J=t{>wt+o|ZGfW|Czn4w zVI|ICR$#U-Q90h+w|D&$0P=MGx7_;Q{%ZvK>DL_8x3p(2*W{yR;QpU|kQ8!h(W@IPGFs?J z2Y-M!w=d7X_*r)h^esy~=d<>G=#}?;;OniwL-7WS&Ln#M6i4u2v-o>;_{4gF)WEJ_QJ4FU+zK10oQJ8$sYf(A|XC9 zfb<0(l%bLn6Oq@mg-JAQGfxkK*nm~&)NBgtCEPf#8zDS)Unn2aMe2xP;Gp6NS;GO) zID##`0BMt&?F_z&Bm>Btud#-CwV4U9#jIdiF=@?wVQ+4Mu>m2}$4g+w!dRZ(m>IFo z<#f{t>2j<*itd^I?baD4GZZ5;^l)WTvjIX6xx);Ss&q}xOo|*x2oQ+f8JsnMM@uQr z{1h@$BW$DehoMPMR3jv_6CoO_zGga2wqnN1&GYB@kHGX|6SMI$M;YRuBJr-ov;}6j z4e!M$AZKPg^#ioB3=)}!Q0z2D5LnRAXn8gr`;rQdTOkDWhPOG4g0VH(0fJLCM-Iz= zz~M+uGF;W}N8dthBQ?e*2`X*(?px(|3TwhQ;6cAU`rLo|QQ!LC?puGaWtOuRRkJds zb)7h_lY*s?GziRiiY|&>W>Jrd>rb7V0C4whJM-2rIdkeYcmADQ?3?Jx!sYb;;tzM! z(kPLYdD%!DA@2SfP;3m`ky!-b2-Yf3;;NRH(%)Q4h@zVg(=F};x zInP)2lWOk+Qi%3N*k6oW6+t|+=H zEyaXqBGM7Pz_F)y{QB;J2u5Aoz>wRR3<`&e3^6lnyWB<6HqQFH(2!w-Fs+WG6#?|H ztTe$4!)e7 z^ulIqZ*Fo&edXFUcmT-yj;YQjoN15;G4pEH$O~|0?>BT~Qnet~V~C*>|a%z1rmTl9Qlm=ECj-pes#Rr*V-jjU zQ6qOG*3f|1%(Y{lARIyrl{Kk}@4zHQ!9C{(5S$a&?Rw3CZvDUdM?SjeEhm2A!F=kU zK(%gaEMzs;0*mZ-Iz$1c558!LT3wu?DJC0q&99i+Jh(jlgMaSK@%!(1`IoLggm#i1 zOZULB^A9h_FCZrKIj_o!2@-GqSRjV1jn@Ip>;IeeU+mqQ^v^i7>o>mr@P}W#^UoYO zHf7Rj%Ly2Tl=qa_nUNrqk$gnWC8LU<+|7Evca z@MeW?h;5jPE@Z?QXM~bmnT|w58lfBF;Ou6K5=>wrY#|IGv7>j?Jx?Nxb%_G@(5RZF z09Y_`N{3-(*}82zK#k(-273TFoA0&|y(Z^0Fv(2ReWk|9ibTbbwUHc15F*l?DFIg4 zJ&0jLjGn0S*}#e+cx=g!2kJt^TlHDv3~C24py;hj%$8y!3!LRQbKV7}XmAwu&5iRL zb>~Z1)MJdgGEMvD+Dek}l6Is`!bUI)UO6I^`p3b+iOH)nU>331B3KmrS6cQ$tvM1`LlF$O;9aG~GYy7XtJWV`+_60MqkrMt(fjXw>7QNS`gd|3#;U$NUe*5m{-0_IM-aJ+Q zNO&h3Mriux_R)%C3-rY$Mz-|B$Xs`^;4$F0^cb-IQqY!sT^GY$x!7gNSm$0m?K>`u zb>$SdPo^P|cx!^=Tq&TGg~I@sZsXa%5@_5t#MN0exiY0@$V`cs7#2jMNaYW!4C{1D3$} z#bS0xU69K;^yTz&Y&@#&S$(vf#?dp&8ffNe@I3j*2TVg~Ww!HC8PLJH%@$~uWk&Ji zV(x*QuGB|k5=AQ1s?K;X`EXG_Js$BWj4Y}YMbI=6S?uYEEPfj_$UtNj#B!;xzG2C% zKw@r%lf0EOa!Kh8#g;e1a4t!5Cpl7s-2wE=OzGQoLI+?w1Mhu7{L{P*z-o|);(RPB zMk;te3naV|0(#bUV8d0S(~LH6`u|jDq~b;)HZE*_-H-d$U!VFfecl-BCL;9cCy^<2 zT4}Wqqml!2g(1ptAV+Fac?~$U?c_V3cmARK@6z938IU#cDP-VX5BQgNJF&F{Sp}IJ zgs6cTd~e+^+Q0t(&!3R^gL}5W`^ER3e${PXb?DgkMgG{sOeKj`?|dQ{oI!_M{5n~~ zQxh|7PRvcUT*otu-F^&M|1@Bhl+hackI>*MRVh6lPjrTZk4+ zJ6bUwEB2C3VDJKqkU<-d2=)jD`MI;CsltsHYsLl)s0cWO!VKDuz3BqM1{px%ds+y) zxdQXwBaxQi^($!*$rH-uyOqomGe_e_B@ZJKmfXaM1ZKC;@+0-a+wJ!4SN+knLs%dG zgbd`?fA?EX{Nx|^t^d&2vX(XUVJv6BV+fJLx|EdxlQ6XU(2K>r%M(BU)f*pw^&$P; z6?50!r=Ee|{rK6F%iZ3h7a19wFUcRE8X9l<2cEZHh>Nm!DTY4L_}AZb_{^*JeZ!NE z?^v848J)26+)ms}Q9-J|mWI(@?+-b_^B7$`%SfH7dAHO^g5 zAq@y#urNzRYz`0a(|y=k-QL;?_e+?zdG5F}8_=}2QUHds*S9a@UMt8Ll#Y#|PFu~3 zFtM55a^kXQk{Eu5k`j_ZLy-W?3qK^YG_~SdzM^KcrKNa=zR<&ynRFF!{k@pjzwCZG zH(a)aFBZeP&r|)|4_}EtM$bSi%|_9w|1n zPLgd2rtRoxR0Rt|`7s>FC?(=)uGBtnHxb*`-vFv)Jf4T?*8hP68~Vb}XuVRd6%WGE(n9zUj(UhO zhzSpi*QKCgw$<>0rIJ2r`|)4+nhSsY>bsx&+3PQy%oFsf(=Yqkqby5SA!Y{ceO*#8 z85=ZH*}Zx8Sx?>jsYh_@Y3e_s{;{t+eD3}OFaOLFI~V>hJ(JIo`4A(?V>r)Mq!Eb^ z;X(L4LL;2ol^W+94fyP~U2pxp{kz`u$oesWL_MzUk{3I#C}E8?9Cri`mfME0Ee#$T z(`2l>a!H?SrE210=nN|m9^hqg2M&TOwocF^41gNv9!j#Q@WixjV9vB})dyon%UFHkG*h~nEu%8mqcqW2x3@{tFd}Bjj zePfSILYM9A3;p)0j;UG4Sn$^IkMJx>y$BWalA;k%#qOavu~|ZaQ0j%ULKGqOc1fFU zJ$NqfnCZy~Yf0%B+rU(A2om0(1xQNz9RUOTE}z=9Es-RHhUQ4vz(h!EQvKw5N{izjb8{=OG3{^*tWeEHM; z=jtO}_m`c4e}8m$+2~X=tOe@)2cad>N(ELraQ^&VXU1qvJf;l1^#ymIz5n*_ddA5; zo1Md?*Sn!i8}8dzj2wM9d5a=xMr@SoJgXN-PMLP&de8?+=vgh zlQxWOAs7ypNsL(wd!Cxj!|X&yQa$UUSMGq|_2RT^>=TM%9H7-tZso-TxzO)Pk1y35 zcbVN){|SKq+cKvq6VepM#Kx>N<;)ssGNrzu!84pSjifS|s5{F(B1$R51yWe0FRjVg zM3q#q=wf`Rv~Xya6f-M6lv6vC*{AI|{(--?(BD>Hf6P2`bft)2`OqnS6=bqDmMO#-g7AuDdk((0 z{XcsC`q!_g6n+Yn{=_uugk|Ep8`^!@zgSs5nDPIS>4YNzPM=@c*YCKz-JL#NNJ z5^0T%Hj|0WmRv5@j{%*;$LFYvT`ijzic4!PHK$Wwdli@#%*#jT&k6x&AWAm?23WTQ zI#{dM-%bETliLYDH_YHFGkcV=a+X6151_B}ZLw|&90lGa9sxjP8g0ysvS1kj(4vaE z{~rJy{Zb-wn-QmV3QDSc3x|CnnNGsBq3*E~B<6rK0ce|zQ}D62>T6gn zUE43kc}T{otGgyBr%rhLw!AnNg2axU;*-Tn&aUWx1iW%tcJx=e^PR0Hz#4cyxNsgd zEAh6h4T-i?d}_K|V6BHDEr;$S4PP|Fh+3eLNcABm3nMUC)e>-2F_XszuLL6p--b~E z^NE`#1^8kRb}sn8zd&ZI$_d9ZE_S=|ZXrG5<%L6G^J1VOfk#P{bEr|P#FT@9WI8rj zeU+U=Qj8-GE_aArW0y~Vk6}uwrox+nZn?$iEEXCm;B3* z?R>Lt{r8_=>OW%hy3bvUp_XD&pVtIH5OImb$oi&QQY0&QTZ~@u;e76{WB>UZx9jhz z>#wR$@HKViGVt=B)1Rm8r3{tTtR-eA*B%(CNYe8duiThW0|F=Ez7OFt~NFDa7V)UdWvgU@1CU3+=Sy z!Gh=r1Pp%+P53S%RJj&DDoo^2o8(cCqf(2OZ-M68ART;|8f~?YxzbSBO?iqMdLofW z2<^FpnB}K+`;NLTUEXp2x!mPh`UKki%5qPCS_$TMsRrBAjt;|7aK=x1rqoTwrRqU2 z>O;T_H7s})tB&XTc4t)EO`QePHJ6nbUJ9RskO6NoD`~3_;7sv6UjZV@0;#Ilh4vv! z95pQ4+BfYbcsq?lYq)Aed4Os@Mld+lDL0WP}*B}GB>hF5zm6?+f_LJ>WMwheAY`V z(iipKoL)7pmwjhrY8@f6oXfv_@7b#m*R5;voBzzgqxawS&gY)LdvT)9pJR879i(Ma zs~wl6@Se&74N;a2nDy~ACah;%F1=gCL)#XZmuS89{{W~9bSMa87|LeS4Nmb8hF97-h!x`zYnVue zx_jvtZHZnHWj{&?}H_9Z1r-ftA=yg(;ybbAkDCYv*+rWoxD z*sRhSa?|G%iujPWo8uIoZ}(9g&04bMm69aNXuvU_69AGxZNC6)oJf!Niiu%sOu*f~1n>pBANlaN z?D+p)dU*Z0a*}xU`k(uc$Iorkm%Bz|4ZILqrd|>AdL0M9aDu)41$PboHF2dfpg(W* zu~*;y3tzSIq~!^0Y8A9u`nx){94t+itoI|(EL>EyUTU?3rdt|*_Ak5A$N)LXt1&pY zedpW%%YOYZ@Wuap{TSe^T+OalLzyS{Ua8pv>AEO3Z=`Bad_oV4A=g~BtR!SzYbCcN zOCK}F*?`UT?LhP~$SntjU`+>PYj8#oH83V0E~3K~Ji0hGK4vk7a))Sjcm6p;TovAb z1QfMy@ug9c(`+2fn}>A5&)Xa(Ixhi4G!h8!iIZV?7OYB*tj#isXVlDiJDEvC&Qr9- zy8&K{nbs7|75x=}tN#_Cm2jEGEIYILnH-||Vh?67(^xr7>D8)5%?~Yw7x4T%_=%9> zf5LT}bmq3hEsk{mB=y=4Rm^%C%m^^zXNs5* z)1SZVs77z9hF#Oe^M)p0`sYUz^9hBG9?dr6QABa*@BlJY-?DbeI9b4|M*cRScv7?< zEU(+u&A@lR>xh2h|JFY^!0n*2&Vr~x)#5P9YI|9z5LS*J+IT$}X3;bX4+93+QX!4C zZn`$Lx%uqd9y#)DyMOJahwr<6epfofuE{H!f$x0J$y&Qw6t8J5R<9F7y}gAY@~U;e zWAoHK`}HNUb-OAV(C@qd(JSwM{|h&tw(WQ}S@&M446-1#<+6fexv?Kbdy5rJd@;wa z97I;R`>2$a#rbVJ-tpo6JKwT?4Cstp)uY#kg<~2YHm-u37JB#jIz7h--U(i0bX3r1Z6JgMC*c3e8N`0E&SoPIP>I36Kdj$MMPQ&%IBamPPL zCX97|MKhpV|2=PcYTHh&WA#iRsHXa$mg&fWGpL>Y^jwG5JB2RDe;v>;rYMX^A- zVm#--BS-(%?)QG%;k#~|{f*H!wmx2^4E)yF+gR(Y1FKw=-DR1wzk`ufL|&qW-+bXy z^`rWAySf?pq9^bDy_etf!Ef01jGg+04XudV*m{h{vv)6It)#*8l?^`@hN<}`WsiHm zqZLPm)~^Gt9|I~ESMxyDJM-KckKrI%3ZqxaBn;NiYv{EX$8FWjj7JgJ#tK|q840Te z@mfp`;Oj6c1E{x{sZSdTiO2vc4$CuU?tKhe=)cRJyA3KL(H;)X46C>8IlSzB;sfCL zidxQfgBhZ;Jhwcj%lq&$H@Jcuh)WYaY1_*{y}eg-1EIU7iN3V8$HKk(4**0n&tuaS z<(A=WZq9&FTQEsU=eLeSvH9^k>Z#oI0r(slemLDURQ-Sh5mxmW*BY6R>4+GOCz-v98%w(;S8pA7Uzx3XBQ zUTB5G#-2r`A{a4(xo(as7#~SX}p4Faud0uMkV>i!3Xmw_ng{ z!9e?>EWvbAE);8-^$cTDu{95Cy;Bf2W~^*B3nPBTuX-t_#q1V(fRWDL@ji5;)l7xq zXxq`;GRWz&62#W06N19@tbivI^XpFB&J5}{x^fUv-{LrQ&((=Y+=MH<2V3vIgJ>h| zXX|l_$`Xe2@S4V$p;UmUHaCwdadW&v?W#WjRGgW{)X%0hBWvJ6Rm1(-xaOC3A41j^$7@m0-jWu?64g=-?=r)`p(~YQ+5L4c`zf^AWmKw^a@?JS%)0MkSUhZ-cN$bG<>+^u1TbbJG;y|@$#yB0 zB(cPTu>3@$oZAw^VPX*Ndwsm@41C{v9^CuphrjoC_MPGT-+da%DzZeZAx=VzUyG2H zR__-mBPVI7=-LJVV*g0p_b*l_~&wKrc=UGj0 z^wuJ&8z<7hEY&)4x$#m882oa1&xMnFcdpkiiMmF;z8&}fe%rlA{^suI?0;mbzm$^Y zpw|LrDYHPeo(y`uyn?-m@V(*$?maGbgiVVbgW&`tfGcGBX~6n1;0mvNR;yNpfg6cu zea4c(&48_0G#AcsVGWNjG#wdRdc!VBNDd3elAhip}b_A-dMsmr6U`gz=eXOgoN znCp2qb8wP{%qq-5XIL6KxM)d}5n{~ob34c*ZbTWeVvt)nTJP{FS6db!7!5<0v23N8 zsgMI7I}Ed;u97g-i@((Ww3NSlZ;RRPEO{KL3j93aZ{Jj0n6jIcNCzmcP;oHagiwje zm8W1Gj50Uf%fpv7oim`+pd=hV0wvNmT6REm?GjRg7LhPz3OZIDuU*)!zcXlW@tRr7 z_hix1b$8hr@U8#R*Zs!c)7y8m&}#I0k5@SA#nBogZWhb#p}Jmv7^16O3J_+XEOCRy zSuVD3ZhY-M$IiZD-@ks*;a%H@!JyauwadWoZsh+{^Rnvn&q|H{qA(EoRT5VG+y2y8 z_lxjr#?{P#zA5+a7vFpO<+pv+9mlru2NTo0(b%(EO0On_*GN3h)LCK?y>P{E1GU5k zAQ~$kfvsWLb{32C+jqX>!v}V}<@neA_(%D#Ti5NfGr$Fxv~$w*6rqJs3QapK;CCdmhfx_KlseqsA;p#sC;9;boS8hx@qC}rW zh@KYsqG<)Ap0w&PsTlmo*beXf?L5#%prPkJ%}E2k^wg%CgTKQ4On)fv26KF*c#DW_n&G8 z-uO!o?R|@H{defr-^tgSCA%StmIF~OiaW0^Y+e$vI2b9Z4|5}^3lLbOXzaLf{#%}S z?EEYD{lwQF-oF0--70;L&*4qK^pMUqGv8j;THI!j70=pdV>SBwiS=VZCFwE_+Jas~UAMWE(v$MO`ucX7<&Z3AS@~jd(9=Jbq^{(w zD*}r#qLvFa_u5(F7DpOO@Nf&-_9S#L9$?W|X25pQHz-vi=wPlqau=ZBzzQt_=N*zQ zYlwh3LfM&meIYdC=AwkyEzazparl#TPz??qBvY>@=G>gVPwyV83Hg{&PS{fTyj$2idKjiki1eXch)f9H}aU3 zU2z>92cM0^659f+Lv=GhL;HpwpJH~9VmM@W6) zfAL)jt<)C5NN?7ojzEl2AKL5N>!tNIpJg>M`U;c^F_|7~J1?C7wkI7w_p1Fr{K9(* zwLUzq8F=HbpJ#E^vdTTEHO;z9TASC0f%l3(d2w?66z2>+&Yf1_$N$=4ZLXI-<@nCc zv$ddgo=o{nEBT@`e8AuIFWX0H=%(jWa7bDV^lzN8h^O{A`iGU0HDY+)p>|x@|oetf@j+J!4=_EmxaNLwK^Z!T#0gM{M>2L zT?!gfbRAw?XDD_e%usZ!hB^Ac=19y*Hya@X4@JfT(ipc|n41eq$ zI5J8wda<(!uPsEDEFeb!jHo@v-z-_;uG?eFKyLkC_N%*3sx;^bv-nFTjP%w`u>krO1o{m z#v+=SR#}vh1!h?_i`RVN`j@t^hsB&?_`$z&_t{t8{#{Q$v3okpU*T3!{2+mR9JiJ6r z$V5csKtww=%)yAsfg=a*_vT{94nx&}@th5|emX}UydjgQyhPV*Zlg>{lvmI}&gnTI z(k+S_&b6YeejXmQW7d($&Oot0@Wa&L4^EWEa85Xe8|(pK`ns>9A1Rq-r!%XmPAL=6 zQ>WA0G-Th1l%c^ND1%-5L#fO*cE&d=PSxkto(mS~(3Mo2EyG|cq)Q!ykBaNREDR(1 zhIG|EJ490L8VFY}L4jn<_ETe5Ig9}^8x{zI*mv2=4B4nw3IL&<*qAk})Ve`=?-FZI z*Glb*0kcu(=_fV^X2s~0S+5&xE1={F$?zNy)BKsM=9aVd;giaM{=kbq^?%v>cc0j? zC#69mDV(V5(20fgvaukumw+==!E4bvhPKgTsn`Xu&D|Hye%I4ao_W>5A9%s~55-Iw zx*n+i>E9k%)c1clH}uOZuK2R7E()RzAsB?$SErB*8~6YDJCUy2b(Vp@|GYz|Uv=>H z&pfejOfW+>$shTqq)YPY>KL&x^SYKjFxVOzB1_A1|1m3Kb{zq>fk5 z&%R4&IkZ}PDEn`tANn2dPnN8gxZ>ywYAtaux`qLUzgT?McK`RZk4yAxr=LUy{?2m_9e>pw|KwSx z4{n^=y5DoLkdfR8X=SMd8x7H`>>Do+21lrY(di|8YD1I_!72WD4ETnh_^7R~yFVcV zEC{#sTxvOaC%s#gny+Ku$_7U-T@I`Wn>&KRD1n8AfsUhrEmoE{MkyIDufdKowsI3& zUQ03d9D*!!|35DA<)dW5JIHp9#Ps%UegX)8j>lXn7IchS7e*T_;iPhrOvpJ{G~srW z;%wAh9|s?m6-f;SAY)+$470UO5cWcv4%&VPUc9*%Tb@2rZ;i`2UiAln9W1B=SLY+? zAQ3$jkqHm!B_}lSlFkz}z=Ju67;OIlhmnZpy`)kcx}e>Lk!H+}mZ^)@Tz6Rh|Ji#N zI8D>4KJfeM)>U2AT|M1%fdP$y#TAf^$O>o@l}OAk2HX{iAweT1%8Uaf?$7*W<6eIL z*8K%H$+|{hhMW8ZF`8LP1i5Skfz3t*gQCbq7;eLGneMK>R9~vQs;j^KU(Px2^LZ|HjNzcjMX}0N^C`9>XcA97qZ7vJf3KZ4?HH+T76AC!`m0`!}-bucqkQ29rvQ9-kdkPBwhg@n1b@ZS5Z) z_?c%MOkIDzwlc7`aq-Aht&payQRo~ku0yPHtOb4QqwD_Mcg!cQKVQ2U__3!RIPs6K zd+T>!xPDV_*!-b^y480Z99IUtu%oN!Rr)R4oD*&@CV|9h{E&WgYWg=1*LoWV^u6&6 zbT_*;m%h;IT1$A-?e6!smY0RRhr=l?b-UH~<)JOw$&r+auK8t9kXgyrPt4uu2@8+} z-YazQ41>mxFNkX8QI9g3B8|DOA zwsitCk--UT8>^*i^(}en?}KLozwM|dFhQ%`xdlJ7&D*;1q}8a3C$c)iuMdww1zgf6bY{NK}!l1knPfibN}MohPQnCfo=f3bWLX9 zpS*o#Ftv|Eb4^`$Un^A7ZkbfAL$9rjKUIA3!t+qg?6qN-?9H;VM>^mR;s?Yoa4&72f$i^< z6Zb@CdyIhB!NouLUN6>l`A^P=JE z33{Dq+;Ys|11{SdfDE?AXDf26rh#9Qxy4|Nn3pe%)>D%R3!KOJc(%b*uF5&Dz2Pg8 zkXwK08>hf!XgyJWjtkq3VP>`pAv3R@Ty0<2?lcJkbLUrOV08AlAimN(D6;;&A<;3@ql z!n^!k%hH{9PY-;Jag`@(-FCOix*a}o?(AUDJV##3v+c*08Tg*ZEq?KFiyypu?fGvz z{h6WO0m9Ul*vQh9FrlCDnt*lIGL&GVzP)4yc(d~jF`t~>MFx3ajB4q&>YneGG73=4 zZO?LY2*Qu_^L}5ju<|iLj{ zfG@>xDgAv=U9Ra8)R$0$btazwfxwE!{^2cG+YaXxAwZ0u8(HrGc@y{@H!=RT9oYCL zg58$HF4F1y{Ok*(aAEaHt;xm3OAro^%X&Q;P)`%j`Vvf0O-ds%I%xhbUiX5hEC-}NUE3Kr za{9t?d_t^h-Hvu*NmRE4fFTbD|MD6BAH-VcUfvxUc#+}ne) zy+lK1QSdcU8#sXnj!`>C-~ncu7+hUB@)0CxbOYcML*D3thRM!;*ry*3j~U45`3yBQ zws}tWPF$eKID45Na1kHzdci?L*u9Htx`x&C{bzZg6ac^7>urx-?l?MlFh+6fv(H}FD2iav%T%^**JDI_ zzro?*+X#jU?x^ACYYl(XI0B=tyzZbc#Mq2L!~fr=KQ1!^U2U9Zq+exIepxdE$QGAk zYG5r#!EKi^9dHH}Uo_ryk&pgIUvdbaE?~buc1Z?a`u1a8tu0mQF@;w4swfQv%EQ?U z>wohb`!@i)q~4bp=3hQE_pw`V_|gy0eCy0A_kUDbCtQYk5g5Nd__7eNaVxLfxpGVd z7+$r0*tO>+M$@Y^1OCt4n0q~CQ|+ha0Jsd}Epi)wx5If?wwZ9e!k}WXuR5r*t~!`_ z+jgyB2f}6J5ZL1dpJv{hb$@1Tt{1Htj}id6+6O57BMp(UwA^DPX*D);5CDk)1%$wN zHp9{M?3TYWoKZxQ4IIp#3Z5^8G{)AD+m2LQ6x3FT672rq+HFH@OI6{vbD7(cp=~)X zQ+egz0BoIur&p8QI?^)HSDhlU$z8VvPAvIK35;LVZg&7#Y^_&dZA-@jL!ph)1xiTh z!%vJwTb!{a%4aY=J0%?+)^W!6P)oZ;j~-uauvcSy0mnWL4#h@w1(Q+Z)n2EaX%P)K zp8C>I3qNwnP7XctX-k?63VRwyZ|!S3IzAPgC>v5~Jl0Vy1zWl)oH{h=+QHb+I|{B0 zo85nO4@iI9Uj~?R94e(n^i&4vOLi@!zHRSXi2Z4oXW)_hXFv4gH?I8X+;=Xl4o4TY+3|Tx z-vyfM1J(eSLAw+ttZCxiqGV;KE=RjOS665FxY;3n`o5iR?)*Fs%Hk&s-V|L3-(VxZ zdQgC#NZ)vA!2Oet?Yx(|(F27`>u=AgGEgv(y}1CQ%5)|RB1)%$P{SA+i0te_U<67c z_PYh%-=*}}Wh9Ezi#1_a_$Y#S$;F^J)n7v)3l6bajCQNW2I$SGQ8g}duvhu|38+A0 z)&iAzTo?n7o7~$B(o@h% zXzTBk&#P~%+ z%f`N~SIgGRm&gEacDf%szq~Cvn~_uI8zw-QeBCoy2fDD~qc1 zm{CQ!@cK{LJpk(P-Ppn52R*$sG&LF&dJxl#baZ(nFE?ZKb|=^l zGMc<4DF&`uA;s5m+S|&GNqw`$FfzE6Ego_>wqDJcTNl#=K6B!+iQ4@s2kS>*-)h00)Fa zA!Jfl4Wh_V4kpxiVYG^Ka8MIcJ6PZ7KLga|@P4GsC$q?nO z_dUi^_VDP;O%LDx!#Co;i2nO`9{H^!doRq)>aviF0h7c^;H4uq>}u+`R)?|?bVZjL zpzW91!y|7yI}6_Icpt_Q8&8R(>^zo9arGGP26tRlgco}_2T4?hHv`_)Rj0TKo1c#o zD68-yFb?5-o5<>sTd{%7+Da14rl@laq^eFM*u+j34unJGI7u&63<14}g3lU`f53$! zu$vI{)wey}U1Nk48-95i=d zA~Y+kM0r!yxR?oUIhYEj0hlEiY4S_l(a0ejYn*b1Ql8|6jAAmnqrhMvDbb^AQgJ)j zNiBViM+-}pF0WA10>$Ip`Th-nGjTaB@{80myUw`JDuk6vw~Pr;HO6+otA#am5x*(; zk?$XT`X_Jr=12B__no=i)yMCh*b|onPDA^PJ5&pUn-EI36SLHx;i7f;j05K6P zl!57~;cxuVjTSuS>s}cE?by7>+AIv3+{d`{f{gbBv66(hV7--tDI{SCfmK%oM`2eHJtBe& zL2P|fQnZXjfd-$-jUo9yfD!A8GtNvedUL>H;e!waGs4N7H50K#n7DQ+9ASdm5j~Pr zCoy(6xRW!Sy{xA@Uinx98T!_RV5JF49B$h&v@QiO157^9EsbTgb(D!CaR}skG(Yi~ zn!-OQVeAp$K{4Eq)4bo&aWcr4rru7{a|4H!p0m5mzVMk{Mgo9~MHyiq-CTg=-;M_u z>!Wof`Pvk1t~Pfa*)9%OL9Gk|5lK0yKn-~JO2ny@PheH@ccssscM4l=py6LF{j z9-aiq&lU!t5r={e2ItrD;ne=P%nampig0C|39W@75~r8?rrWJd;gS5!i*Nt#&5zyE zKl&?6yTAG4d)Cg);$2*B&D>>N26%B-Ye_%|6Xq1um10D zSif!Q@fTNlInFDxmV+)PToS&j$ZCu)DOxhQgn;o9LfaqrpMkpB;hN2j$n5!JGv2qn zDQW{V!MeWlrM8PyYj+hTZY3*?K29jV+2pGTQZhL6VOOmx{)))Yg z1+?`djbfO=04WG!x3NY}7@H;yR~-ilwt@^>alH189KxW5cj;uei)H43Q}w8z)6h3K1jH7!_M%5&Z1h zM!EIE{bYcJ%Jt&vWgVG+zI0+SSx2c-A6Ds6yy@Zhy?^GhuR4MU$NLG|n|DJ7Uiu%J zzxUz+doi%!-sMsHSTbBl*r8Tpmk$>=&f%}e?1s7aV|+*%zz2bTCOAG=r#yHdw1W*nEvH`3muwn~mk3u(c(^4;I;^@muN4P^MUumtUz4YRB zRE~WrzY|J?ne3FV5zXTOeMPfIbkV@%SLdstbzPWC(`h>;bbJX0t*q9j3-aX47m(Vqb9=;w(rfi1_vwh@}ljCo+ToD3#Qt;)Ko}Wy9a!2&t%q0|2PJdDdOtlz} zJ~O@VDQ_P<`ofXldiE0jf_Q@Z^X|*Q2hZ*u;B(zLSX&jH+c2+4DmeEyuQz$bVo-N# z@clQfr=dSTJTtJqIePAI9C_!-rOoO61AN1d>jWtcf))>#jlu4E$vr$X zwzIQ3?VDY<3z~`TZST+s1gI&^fJoivZb6;qa%VWR)2Olw zW4%cP0VusSdk2qKO3Wu+;Dk0}!jWyd9=qTSwP zv&SpEBCyZPW5%FwVoI%IP;ZSVKtA=`XG{Cigu`i2$FzhikfX76bmQ4>|3ux{ADFc5 z>e6Qk3Bb1<}NaDc{8XtL6((`Wjh z0Avd9_sn&uRJ!6SxSX^^+j_*lgUWcHRRfxods?`{?wQ^9w090~+E{t>-A@%^&=?EAKnI zH1eZAOP{wI%33oKiPr_)KxM5HLK<#IT$Fe@>W}-+K-}z@P9<3$%w6oqxS+c* z3E_>EnO2c#;v>B>9?vpS3}I>v_5d@3DV%n{Zo_eNkY2ZK4#q)su`tqZBv$~$)i|i` zj&uhIR>y)h1TUi|IwH$78pMMT6*a$#w)O?L?ByR5>GSq2{1CKJpJyOZ!h1X@7Qt0KLW%z032|XI0xPo z)wPdSNP<-3>QSSkn>!>VMM@;ma4z9c(ZHS-0nCtzN!q~6JzOlet*IJKdP^nF77}u* z@?0@HBJkj4fH*Hq>z9Cu$Q_LxpwIajCv09&?HiL-2Qs@jjDcsZ7-^^gK*7Ywr+IFq z8UzYd0Ks4M^luMV(StWG>nAz&MiLky))OpV&!cgJxy?b?4At#)AyZG zbzR`Bc{m>jALg;JOQEZdkhF-z3^S8GZPS^vkOo|Mlw*A9~})d)N1m z@VN`F5iJRvDf{a0<>6U-g~-aa(U|OORJa4?i&ANO;gT6ReiAo3?LK6Z$@C#fY4$zS zB}uDyta|?TKWn0!IPR+^Q7bPOs|Wyv%^;jrS#*gah6Vztr!2kH=&A5LD>SX{u+N8z z7GR89Iz(Tmb^+N!^@VBN$spuXtmk7edw4pr(a<;u>bD-Hbx=>)Fvm|9^!PF?m31bK zsA$Jm(I%o($Y`?U|9yo~YmkZU3XAKBR3mDQ^vO6(1omFAL=%ySCT z{Lt4Kc}+~GAHaPG1<0E_$)^u%mxUY>Mjs??LhR(H8T9rc@ZX!-;Rb*U%@sO{VUZt!9BX)Drh z);C@qTZ~{#LH+`d)~EAr9q-T>FxW(BRxGVlgc@D$L@zElG9iqq80z;NYQ{|3N0xr{c7 zj;y-et^%^idSty+o~T8^gtS*AA25}bwG^TJ*c%Lv?^*oe5A8Yd%HwzZ0sgdne_YcU zxbsg}FYtfW(RO7qbrE1qF>F;fE;X8ks@-jB!$uc>>2DvprYG4C?tx_BgLkhz_Vy!> zd&}tK_`uJUwlpu-ULmmpxHfnJ7OyOnc!@}@pB)Wwbi3BYhnF3=l(Rv7d&vx}9LLSh zckoPFo?V=*h%V;7JhLX=%PL?NN8e0S1)(8HV5oA**os0f&A0QQG_{bB%N>Cz`^ccA z<{+qr6{{i+0c4{AYLAmE4RTCDSX0q47RzwB9-oDly={yTN2)6#6s?^0n6SGEh@^qY zT&XXoRv-jlTQS>e#+9b;*kCmPZP`i~_jTAZh7cG%QFpu#QM%$k0a)T2fQjjKYlx

pdK- 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�KpN(OuUK#wS7awzQA@An0_5s!vnoJlf=EKD~#%g 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_167x167@1x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_167x167@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4799fe563d82e118393d2242b389d671c0a5f2e1 GIT binary patch literal 18288 zcmaI719WAYN+nU&R@@4M5@4frK>%DKE)u(G$)vv0$ zx_X~p>+}wjmlcDB!h!+-0DzSc7gqf4i~lwVpzrTD=k@mQ4#Z4AMgRbyHU|3L0QCEw zz(`zC1^~d56ae67AOOJYH|ysy0DucU0Klm}003tS006puMwdxvi(ws(iHnawRgQRu0vHxocfZLt( zo3t@;HXv}fv9@*Mbmt-bhX&_2{g+KgNbnC8XDc2;bs2dAAv;GC0#;gjT6#iWC;|ck zZbxHNPDNqSf5E@+cnHm%o$Wd4=-k}gXx*4-?HtYM7&tgM=;#^g7#V54HE5hXY@H3< zX>6T{{%PdD>){Kg+g)=WBH{Jin{!f(p|G;?J z{tNT(%>M*v{BMANXZ|NZ&e6i;yUhOv_BR9n28a&l9rdHx6KVa=S5m60>p`q%s={zzEi%G^LynVObfn0N!>d!bNiz-U7cdbP_TesIX zjJbVAdLHDHF(Vv*(@P@yA=}z3z{{gz+<|KNw6?i6wHb6>)p@$;4z9AXa*oUMEg9Kx z7kt@f*A|W*<2962qtVNmZbwMpgrtKS4F-*sX`Dty_}JOZps8iETxa8!Jc(BD;W6X+ z3i<7p%(4aQqW9DLGLepFE0FE5X$Sy%jpJN2L3@_~vJA#+fDbFZmqx!%vEKPFBgb6M z#kk!hMa>>9Fqi(^He@jwo0Rft);rhY!bWupZ=(q33^tU*XT98vd+rD1LF((ndu`g-+P8(w~%z5k_Tm&JS_Kg|5<_I7{OmEita0(ghGrBv)7gxqj~gPWkXBI0tI zX?L^j*;U=c=MvsqgmxNp#nyEr=#6|G?7+0u+BOyIDCpEzNhf@A>Hf2fohVlDd{SDb8HnT#Or;Z_K*NX%DWAfB| zSH}e9d=0T~u{P(P9rXB$s|eK3|fX zMl&QbuZdEZuc_)EN0?l_V-X3{dWg^WoPNESWd~+34?MVsM_HkKt!l+4Xsbt~US@41 zgEorSn+;q=JH;VIP8+2K(g>H>^?#s?P=Ex7P#QuhQv0a($K??SdGU{`Q;U7>Z2VoE zjCVJ0Wa)gsaun756N}Rc7NUmJ$%w>Blaj|k2=RkdEWhe zNF6qc>FP~?)~FBgSVIt?i_=$QHGk^hX>mrnx{nWkofnJb^2O!aFpxDwKGLD2y-z@i z*%@Gg61HgYdX7tl+UAN`$KUL{}Ur-fCj6@ zfhZm@$i`oUHG24&u!x@LI1&j$C$aQcf_jlrg(sK9P?CF3N_f(Ip?Vlahz+T&YW@yc zMdia+=H_kRk{>b%#%}~F*u`(=9#k6DOBDDmz11}WEqp9gIponT&x`eEXP~36n z0Yw!J)&ZvMcXm7Xb)yx~%7H`Mrg080O7rEb&wE#8*aS445z4HMpzwox=DQ{EpgPRD+-}-DcPan%%zgBu<#rod!vs@P(h`K*! zkD0(>)T(L20~Mj-TVaoihN)q%YE@7zfNFF3^@^+S3YJ#KUcD+tLJP4$=&^WIAcO^M z-#Lqv3miXZ=1^sX@O#3gCdaTk+gNoK;>pQbW?*xG5qx@5fQF-YC|v?{=%qehY;sMC z?^yjj6}Hz6wjS-B-I#3u)aeKOR!b3nbe`kJBqCba1?FRx3<4E<{gp}fF)5Z9t?Fcs zP`Qfa;}s1s4kJcZf&^d$%?3-N-9uS~+4xYK#!KK>0OZzVuSt^=1G

am*d`{jZR8QvLBE#yG`6Nq615EOnn2WNR|!14 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 Z13rG)M-oU}-d_BN8tlJ_SIUV_`wufOE4=^! literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_20x20@2x-1.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_20x20@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..58e44f4cb19a81cf066e8e0aced1a7549235c432 GIT binary patch literal 3899 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 Gu)Ymk!EEfwit%(H`~;ZT7=YFqKQf<-Go$h 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 U5Izbsl7HVhJGk1PrLkiE1&7XoBme*a literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x-1.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d999f7beef5bbc2ac650159f8f55f7eba6feae0c GIT binary patch literal 5514 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d999f7beef5bbc2ac650159f8f55f7eba6feae0c GIT binary patch literal 5514 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_29x29@3x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..babab5aa6e410fe6e035755e645d1f5a92343096 GIT binary patch literal 8347 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 K6^i8^2mU|kNvgR3 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_40x40@2x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..494089280b1a8f4116c1c14890b279088dd85a33 GIT binary patch literal 7575 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 K6^i8^2mU|kNvgR3 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_40x40@3x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f8ceece84a86c5ea75cfdfa9e7fc6dc0d8611764 GIT binary patch literal 12086 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 OTR}!ux<=A0=>Gvz1VCW` literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_60x60@2x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f8ceece84a86c5ea75cfdfa9e7fc6dc0d8611764 GIT binary patch literal 12086 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 OTR}!ux<=A0=>Gvz1VCW` literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_60x60@3x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..16fbd33ede0e8e709e4a9b968620cca15b12d486 GIT binary patch literal 20218 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_76x76@1x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/AppIcon.appiconset/icon_76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..531cda66d4a03c8d709d8dc4ef25a7d445b85c2e GIT binary patch literal 7239 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/Contents.json b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/Contents.json b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/Contents.json new file mode 100644 index 000000000..c1277fd3a --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "spatial_self@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "spatial_self@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/spatial_self@2x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/spatial_self@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1610dab9cdb61379ae7165fb3d7d3309f8c5c21b GIT binary patch literal 3019 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/spatial_self@3x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_remote.imageset/spatial_self@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..202ccd27a7ddd6f35a7b43a09874a52441173c79 GIT binary patch literal 4201 zcmY*cXIN89v`r{V2_RLP5a}Q!p_haxAV^811?kO5iF61Mq=?d`$pxfHFQF(%lNtdD zNJl_L=}n4ol`bHN54^s6-<$Kz*=zQ!wf5}!&Yu%waPtNO9XA~S0ASG3zHW3HHP0r^ zxzjgq{1x%j0Q51sp$@1V;{9^E2zM~kaYUm55~r93Kn-L8P@Yjv9{`XWK>Zs70J=b) zf3Xoz><@}-F;LD zssg_mDyR4?4HW?Yrr=#v1A+wx!uyV+iqUngKl0O+s(>>d z@2LWX`uqDs{AD2?-cC?yWo2b3Oa>|=BX!D<@(FOq+Y_YReFXn8`Cp&w4nA0KoF^XV z;SN6YwZHA*i&qs8I4kt;_~)E>oa29$+za9KFqhyUyTUiQ;$YsZxtxNJ*Na_`iQ zT%T5-A6f58j%H%mSU+(f33-ze#J9#dD(7$O8>sU_BM>)feG4vl*IZb;Ftk4xl*@J- z`hz5eZkir^lDlC$Dho3-xEvTXnKpJGCSLe=Yzm7hy)EQ%d$vERr=anG-fKMkSNR?oAvaAYzD;i!B743R*)WNusW6GL^SIECIv zTWy{XV%VH!O1SD(({z+e(&8XPz8<(gGvt_-_iUAk|3J(>d~V9+J%1u{t=>e-1lO6h zJAiq!ot1xSbjQ@awe_gUk24%GK|wfqqbQqQoUTlMbWXRkGt!Yc7Bkg5%2E%Y~o57`}FR^uwHK`;&+AC}}wurvV3T3dP2+gf~ zWz(Sbk%d6FXdE5;aXHbX?;rve$Ji*+H+ZKI#tq8gK8WI%vcpFet#C7W0{OjIJlX}? z`J=2U3Y`_%#BD?RzYPSd9okS+Wajwc08Et%b9PCxrypuJY3$r$dgqO-P9Dxv0k7hT zV$yM!|C0U=`p|UHs0@Q0!_F2Dlf}Nu)L*ErG1@Jn93Q#iEF*?Jyy zd9dv$XFZe#n?*7QBSNd;Kg~3z8o`3gDEhd37rQF5gjs{)?0#2yNmS?6nH^20V`jZx zB9HbZa-D&}z1(q<-J~~xC6}L9BDz>6)vyhAY;gt5;Vsod!-5l%)o}$W{=hK~ z>z<(FWKIFv($WWcaN0vb>N4cey7Yql3^q48K{}k4dvt7_r-F|Grc z1KBdO)ujr>bRGo=FZ<~jg0jjP8PW)GmC9;J*#l)xxc>ETdR-6P&1*n>WOr_F#?gL zZ=|pjfp{j4ep+sy9zHgkokZDA6Enal7(^?RA8#JJnLclDG%r6x-~B+&d^m&>!I9-0 ztxBW3eRHb(AaV6wsG4A*^GIcR(A<;lAjw`~8R;7eETdih+G4g@*ch(qNClc5?FuBq zaj5KPT&q5Jk`QkYSTiB+5ozTJ#T3SuW`eALt$KW6y}Fl&6m zMqnq)UPMHf&0njgOtuGJ?#u{}pZz?B!U`;>dzM^fN>z$6)EbDa?88SrdO@sdvIe3T zgC}V8Y5C|snJ4Wtc!}nGC}@kzV$Ps}+od)bmbYz2UfKL)ebHs$%3x5stNFJLzzfw< zTn{{?Lcn@KBxH@5vv_MU;S<)scOtA7HT#1neHq3i{Y9b3;SyJwe3v(gg5=IzJwq*|9aCT z)S1S)Rv=HQH<(b#aO3rnSUw{*czxf5WOOnyc%@k};X~QXUi5WKjRI$f0gA(IY$>QA zUHsKYt_-}366$llUQnkF$-6Gv$fH&{ z$lta(OP?Q?cI~qbDr|DlJ(TyThMU>y5{C;*du6m`+F$YvS*5zI6u}+6MZS1I)&HM*XKPz(I zGF}1kjJ*vY%W=4_4KAc65o!mWakQ!qLQNdcJEclFGfa_dumx9g!S<7Ouwb=_vdgHL zXLlxyVxxyFXYpzXA}+jra0Bx*m@L zaw)1QBY zutsk2(nG^rfLHnEUWglz<1BeP5`|=Pj7c0DHEy6H(4w>E-SwP;Vx}m=ZoBXHe|x*N zLoUWPd-XwUP$wxG0o>|59U^jfp2ku5c}^k$fxAaF;j>56Hjrh1d&+ERkLRV)q2(m# zp)uovLI~Rtib}7vJ`F@QrG6;0N;roz7h0mm?n;Jp}!={Ap-cd1`UTOO%8q=-p`Hf)9@j6aNh;~3ja_oep+&z+Pw zzubge!>aGY-xxZHH5+AY^!kOB*Eofz1CtoPXzL^8LYF5yCPez82OGWF-ZJl(UE?RN z>upF_h5MsI!f4VTGJ+zMD2={~GA-PvXk3U{_tB3y)}q1f^fvMoD}0Bxw0IUyC%qaJ zzj&pQPZhnmui~fj)LXafX?>7rgYLS`pov>Ona0mc%Y{m9AvqIP1J6Fn@}9Tn6p0uZ z_uPosAJ^YMe`zVf|5JE#d|L@dIQT2G1M*(eE=Q$u5T6Z8a69a4Q)~Br%GybKA32zH z-*zYBzVEL`I&Y(PFK=!g^WE1kD=1M@8pT|I_RU&I1qJxy=S@_*$#-|L_eYaL5DbR> zfgK1<`if=B1eF}U+6ikzNJ0=~uu8|t$FJDH?47bygAoswVq3eyP-MWk&fs$z343M literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_self.imageset/Contents.json b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_self.imageset/Contents.json new file mode 100644 index 000000000..93244f89d --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_self.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "spatial_self.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_self.imageset/spatial_self.svg b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_self.imageset/spatial_self.svg new file mode 100644 index 000000000..2844804e7 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_self.imageset/spatial_self.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/Contents.json b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/Contents.json new file mode 100644 index 000000000..62119e059 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "spatial_sound2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "spatial_sound2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/spatial_sound2@2x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/spatial_sound2@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..84781d99f2f79c1a186635de5e4a720a8e79c724 GIT binary patch literal 9146 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 literal 0 HcmV?d00001 diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/spatial_sound2@3x.png b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/spatial_sound2.imageset/spatial_sound2@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..95defe9c5f7860eafde96692d498ff65ddc2e3da GIT binary patch literal 16328 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 \ No newline at end of file diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/videoBackground.colorset/Contents.json b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/videoBackground.colorset/Contents.json new file mode 100644 index 000000000..120046013 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/videoBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.921", + "green" : "0.921", + "red" : "0.921" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.130", + "green" : "0.130", + "red" : "0.130" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/videoPlaceholder.colorset/Contents.json b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/videoPlaceholder.colorset/Contents.json new file mode 100644 index 000000000..e7a66eb91 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Assets.xcassets/videoPlaceholder.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.476", + "green" : "0.476", + "red" : "0.476" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.664", + "green" : "0.664", + "red" : "0.664" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ARKit/ARVideoRenderer.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ARKit/ARVideoRenderer.swift new file mode 100755 index 000000000..35fc82ae8 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ARKit/ARVideoRenderer.swift @@ -0,0 +1,139 @@ +// +// ARVideoRenderer.swift +// Agora-Video-With-ARKit +// +// Created by GongYuhua on 2017/12/27. +// Copyright © 2017年 Agora.io All rights reserved. +// + +import Foundation +import MetalKit +import SceneKit +import AgoraRtcKit + +class ARVideoRenderer: NSObject { + fileprivate var yTexture: MTLTexture? + fileprivate var uTexture: MTLTexture? + fileprivate var vTexture: MTLTexture? + fileprivate var rgbTexture: MTLTexture? + + fileprivate let device = MTLCreateSystemDefaultDevice() + fileprivate var commandQueue: MTLCommandQueue? + + fileprivate var defaultLibrary: MTLLibrary? + + fileprivate var threadsPerThreadgroup = MTLSizeMake(16, 16, 1) + fileprivate var threadgroupsPerGrid = MTLSizeMake(128, 96, 1) + fileprivate var pipelineState: MTLComputePipelineState? + + var renderNode: SCNNode? + var pixelBuffer: CVPixelBuffer? + + override init() { + super.init() + + defaultLibrary = device?.makeDefaultLibrary() + + if let device = device, let function = defaultLibrary?.makeFunction(name: "writeRGBFromYUV") { + pipelineState = try? device.makeComputePipelineState(function: function) + } + + commandQueue = device?.makeCommandQueue() + } + + func shouldDispose() { + yTexture = nil + uTexture = nil + vTexture = nil + rgbTexture = nil + renderNode?.geometry?.firstMaterial?.diffuse.contents = createEmptyRGBTexture(width: 1, height: 1) + } +} + +extension ARVideoRenderer: AgoraVideoFrameDelegate { +// func onCapture(_ videoFrame: AgoraOutputVideoFrame) -> Bool { +// +// videoFrame.pixelBuffer = pixelBuffer +// +// return true +// } + + func getVideoFormatPreference() -> AgoraVideoFormat { + .cvPixelI420 + } + + func getVideoFrameProcessMode() -> AgoraVideoFrameProcessMode { + .readWrite + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { + guard let node = renderNode, let rawData = videoFrame.alphaBuffer else { + return true + } + + let width = Int(videoFrame.width) + let height = Int(videoFrame.height) + + yTexture = createTexture(withData: rawData, + width: width, + height: height) + uTexture = createTexture(withData: rawData + width * height, + width: width / 2, + height: height / 2) + vTexture = createTexture(withData: rawData + width * height * 5 / 4, + width: width / 2, + height: height / 2) + + rgbTexture = createEmptyRGBTexture(width: width, height: height) + + node.geometry?.firstMaterial?.diffuse.contents = rgbTexture + renderRGBTexture() + + return true + } +} + +private extension ARVideoRenderer { + func createTexture(withData data: UnsafeMutableRawPointer, width: Int, height: Int) -> MTLTexture? { + let descriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .r8Uint, + width: width, + height: height, + mipmapped: false) + let texture = device?.makeTexture(descriptor: descriptor) + texture?.replace(region: MTLRegionMake2D(0, 0, width, height), + mipmapLevel: 0, + withBytes: data, + bytesPerRow: width) + + return texture + } + + func createEmptyRGBTexture(width: Int, height: Int) -> MTLTexture? { + let rgbaDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba16Float, + width: width, + height: height, + mipmapped: false) + rgbaDescriptor.usage = [.shaderWrite, .shaderRead] + let rgbTexture = device?.makeTexture(descriptor: rgbaDescriptor) + return rgbTexture + } + + func renderRGBTexture() { + guard let state = pipelineState, + let buffer = commandQueue?.makeCommandBuffer(), + let encoder = buffer.makeComputeCommandEncoder() else { + return + } + + encoder.setComputePipelineState(state) + encoder.setTexture(yTexture, index: 0) + encoder.setTexture(uTexture, index: 1) + encoder.setTexture(vTexture, index: 2) + encoder.setTexture(rgbTexture, index: 3) + encoder.dispatchThreadgroups(threadgroupsPerGrid, + threadsPerThreadgroup: threadsPerThreadgroup) + encoder.endEncoding() + + buffer.commit() + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/AgoraExtension.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/AgoraExtension.swift new file mode 100644 index 000000000..40df8c6ae --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/AgoraExtension.swift @@ -0,0 +1,301 @@ +// +// AgoraCode.swift +// OpenLive +// +// Created by CavanSu on 2019/9/16. +// Copyright © 2019 Agora. All rights reserved. +// + +import AgoraRtcKit + +extension String { + var localized: String { NSLocalizedString(self, comment: "") } +} + +extension AgoraErrorCode { + var description: String { + var text: String + switch self { + case .joinChannelRejected: text = "join channel rejected" + case .leaveChannelRejected: text = "leave channel rejected" + case .invalidAppId: text = "invalid app id" + case .invalidToken: text = "invalid token" + case .invalidChannelId: text = "invalid channel id" + default: text = "\(self.rawValue)" + } + return text + } +} + +extension AgoraWarningCode { + var description: String { + var text: String + switch self { + case .invalidView: text = "invalid view" + default: text = "\(self.rawValue)" + } + return text + } +} + +extension AgoraNetworkQuality { + func description() -> String { + switch self { + case .excellent: return "excel" + case .good: return "good" + case .poor: return "poor" + case .bad: return "bad" + case .vBad: return "vBad" + case .down: return "down" + case .unknown: return "NA" + default: return "NA" + } + } +} + +extension AgoraVideoOutputOrientationMode { + func description() -> String { + switch self { + case .fixedPortrait: return "fixed portrait".localized + case .fixedLandscape: return "fixed landscape".localized + case .adaptative: return "adaptive".localized + default: return "\(self.rawValue)" + } + } +} + +extension AgoraClientRole { + func description() -> String { + switch self { + case .broadcaster: return "Broadcaster".localized + case .audience: return "Audience".localized + default: + return "\(self.rawValue)" + } + } +} + +extension AgoraAudioProfile { + func description() -> String { + switch self { + case .default: return "Default".localized + case .musicStandard: return "Music Standard".localized + case .musicStandardStereo: return "Music Standard Stereo".localized + case .musicHighQuality: return "Music High Quality".localized + case .musicHighQualityStereo: return "Music High Quality Stereo".localized + case .speechStandard: return "Speech Standard".localized + default: + return "\(self.rawValue)" + } + } + static func allValues() -> [AgoraAudioProfile] { + return [.default, .speechStandard, .musicStandard, .musicStandardStereo, .musicHighQuality, .musicHighQualityStereo] + } +} + +extension AgoraAudioScenario { + func description() -> String { + switch self { + case .default: return "Default".localized + case .gameStreaming: return "Game Streaming".localized + default: + return "\(self.rawValue)" + } + } + + static func allValues() -> [AgoraAudioScenario] { + return [.default, .gameStreaming] + } +} + +extension AgoraEncryptionMode { + func description() -> String { + switch self { + case .AES128GCM2: return "AES128GCM" + case .AES256GCM2: return "AES256GCM" + default: + return "\(self.rawValue)" + } + } + + static func allValues() -> [AgoraEncryptionMode] { + return [.AES128GCM2, .AES256GCM2] + } +} + +extension AgoraVoiceBeautifierPreset { + func description() -> String { + switch self { + case .presetOff: return "Off".localized + case .presetChatBeautifierFresh: return "FemaleFresh".localized + case .presetChatBeautifierMagnetic: return "MaleMagnetic".localized + case .presetChatBeautifierVitality: return "FemaleVitality".localized + case .timbreTransformationVigorous: return "Vigorous".localized + case .timbreTransformationDeep: return "Deep".localized + case .timbreTransformationMellow: return "Mellow".localized + case .timbreTransformationFalsetto: return "Falsetto".localized + case .timbreTransformationFull: return "Full".localized + case .timbreTransformationClear: return "Clear".localized + case .timbreTransformationResounding: return "Resounding".localized + case .timbreTransformatRinging: return "Ringing".localized + default: return "\(self.rawValue)" + } + } +} + +extension AgoraAudioReverbPreset { + func description() -> String { + switch self { + case .off: return "Off".localized + case .fxUncle: return "FxUncle".localized + case .fxSister: return "FxSister".localized + case .fxPopular: return "Pop".localized + case .fxRNB: return "R&B".localized + case .fxVocalConcert: return "Vocal Concert".localized + case .fxKTV: return "KTV".localized + case .fxStudio: return "Studio".localized + case .fxPhonograph: return "Phonograph".localized + default: return "\(self.rawValue)" + } + } +} + +extension AgoraAudioEffectPreset { + func description() -> String { + switch self { + case .off: return "Off".localized + case .voiceChangerEffectUncle: return "FxUncle".localized + case .voiceChangerEffectOldMan: return "Old Man".localized + case .voiceChangerEffectBoy: return "Baby Boy".localized + case .voiceChangerEffectSister: return "FxSister".localized + case .voiceChangerEffectGirl: return "Baby Girl".localized + case .voiceChangerEffectPigKin: return "ZhuBaJie".localized + case .voiceChangerEffectHulk: return "Hulk".localized + case .styleTransformationRnb: return "R&B".localized + case .styleTransformationPopular: return "Pop".localized + case .roomAcousticsKTV: return "KTV".localized + case .roomAcousVocalConcer: return "Vocal Concert".localized + case .roomAcousStudio: return "Studio".localized + case .roomAcousPhonograph: return "Phonograph".localized + case .roomAcousVirtualStereo: return "Virtual Stereo".localized + case .roomAcousSpatial: return "Spacial".localized + case .roomAcousEthereal: return "Ethereal".localized + case .roomAcous3DVoice: return "3D Voice".localized + case .pitchCorrection: return "Pitch Correction".localized + default: return "\(self.rawValue)" + } + } +} + +extension AgoraAudioEqualizationBandFrequency { + func description() -> String { + switch self { + case .band31: return "31Hz" + case .band62: return "62Hz" + case .band125: return "125Hz" + case .band250: return "250Hz" + case .band500: return "500Hz" + case .band1K: return "1kHz" + case .band2K: return "2kHz" + case .band4K: return "4kHz" + case .band8K: return "8kHz" + case .band16K: return "16kHz" + default: return "\(self.rawValue)" + } + } +} + +extension AgoraAudioReverbType { + func description() -> String { + switch self { + case .dryLevel: return "Dry Level".localized + case .wetLevel: return "Wet Level".localized + case .roomSize: return "Room Size".localized + case .wetDelay: return "Wet Delay".localized + case .strength: return "Strength".localized + @unknown default: return "\(self.rawValue)" + } + } +} + +extension AUDIO_AINS_MODE { + func description() -> String { + switch self { + case .AINS_MODE_AGGRESSIVE: return "AGGRESSIVE".localized + case .AINS_MODE_BALANCED: return "BALANCED".localized + case .AINS_MODE_ULTRALOWLATENCY: return "ULTRALOWLATENCY".localized + @unknown default: return "\(self.rawValue)" + } + } +} + +extension AgoraVoiceConversionPreset { + func description() -> String { + switch self { + case .off: return "Off".localized + case .neutral: return "Neutral".localized + case .sweet: return "Sweet".localized + case .changerSolid: return "Solid".localized + case .changerBass: return "Bass".localized + default: return "\(self.rawValue)" + } + } +} + +extension UIAlertController { + func addCancelAction() { + self.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil)) + } +} + +extension UIApplication { + /// The top most view controller + static var topMostViewController: UIViewController? { + return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController + } +} + +extension UIViewController { + /// The visible view controller from a given view controller + var visibleViewController: UIViewController? { + if let navigationController = self as? UINavigationController { + return navigationController.topViewController?.visibleViewController + } else if let tabBarController = self as? UITabBarController { + return tabBarController.selectedViewController?.visibleViewController + } else if let presentedViewController = presentedViewController { + return presentedViewController.visibleViewController + } else { + return self + } + } +} + +extension OutputStream { + + /// Write `String` to `OutputStream` + /// + /// - parameter string: The `String` to write. + /// - parameter encoding: The `String.Encoding` to use when writing the string. This will default to `.utf8`. + /// - parameter allowLossyConversion: Whether to permit lossy conversion when writing the string. Defaults to `false`. + /// + /// - returns: Return total number of bytes written upon success. Return `-1` upon failure. + func write(_ string: String, encoding: String.Encoding = .utf8, allowLossyConversion: Bool = false) -> Int { + + if let data = string.data(using: encoding, allowLossyConversion: allowLossyConversion) { + let bytes = data.withUnsafeBytes({ $0 }) + if let address = bytes.baseAddress { + write(address, maxLength: bytes.count) + } + } + return -1 + } + +} + +extension Date { + func getFormattedDate(format: String) -> String { + let dateformat = DateFormatter() + dateformat.dateFormat = format + return dateformat.string(from: self) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/CustomEncryption/AgoraCustomEncryption.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/CustomEncryption/AgoraCustomEncryption.h new file mode 100644 index 000000000..377019342 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/CustomEncryption/AgoraCustomEncryption.h @@ -0,0 +1,18 @@ +// +// AgoraCustomEncryption.h +// AgoraRtcCustomizedEncryptionTutorial +// +// Created by suleyu on 2018/7/6. +// Copyright © 2018 Agora.io. All rights reserved. +// + +#import +#import + +@interface AgoraCustomEncryption : NSObject + ++ (void)registerPacketProcessing:(AgoraRtcEngineKit *)rtcEngineKit; + ++ (void)deregisterPacketProcessing:(AgoraRtcEngineKit *)rtcEngineKit; + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/CustomEncryption/AgoraCustomEncryption.mm b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/CustomEncryption/AgoraCustomEncryption.mm new file mode 100644 index 000000000..713c055e6 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/CustomEncryption/AgoraCustomEncryption.mm @@ -0,0 +1,122 @@ +// +// AgoraCustomEncryption.m +// AgoraRtcCustomizedEncryptionTutorial +// +// Created by suleyu on 2018/7/6. +// Copyright © 2018 Agora.io. All rights reserved. +// + +#import "AgoraCustomEncryption.h" + +#include +#include + +class AgoraCustomEncryptionObserver : public agora::rtc::IPacketObserver +{ +public: + AgoraCustomEncryptionObserver() + { + m_txAudioBuffer.resize(2048); + m_rxAudioBuffer.resize(2048); + m_txVideoBuffer.resize(2048); + m_rxVideoBuffer.resize(2048); + } + virtual bool onSendAudioPacket(Packet& packet) + { + int i; + //encrypt the packet + const unsigned char* p = packet.buffer; + const unsigned char* pe = packet.buffer+packet.size; + + + for (i = 0; p < pe && i < m_txAudioBuffer.size(); ++p, ++i) + { + m_txAudioBuffer[i] = *p ^ 0x55; + } + //assign new buffer and the length back to SDK + packet.buffer = &m_txAudioBuffer[0]; + packet.size = i; + return true; + } + + virtual bool onSendVideoPacket(Packet& packet) + { + int i; + //encrypt the packet + const unsigned char* p = packet.buffer; + const unsigned char* pe = packet.buffer+packet.size; + for (i = 0; p < pe && i < m_txVideoBuffer.size(); ++p, ++i) + { + m_txVideoBuffer[i] = *p ^ 0x55; + } + //assign new buffer and the length back to SDK + packet.buffer = &m_txVideoBuffer[0]; + packet.size = i; + return true; + } + + virtual bool onReceiveAudioPacket(Packet& packet) + { + int i = 0; + //decrypt the packet + const unsigned char* p = packet.buffer; + const unsigned char* pe = packet.buffer+packet.size; + for (i = 0; p < pe && i < m_rxAudioBuffer.size(); ++p, ++i) + { + m_rxAudioBuffer[i] = *p ^ 0x55; + } + //assign new buffer and the length back to SDK + packet.buffer = &m_rxAudioBuffer[0]; + packet.size = i; + return true; + } + + virtual bool onReceiveVideoPacket(Packet& packet) + { + int i = 0; + //decrypt the packet + const unsigned char* p = packet.buffer; + const unsigned char* pe = packet.buffer+packet.size; + + + for (i = 0; p < pe && i < m_rxVideoBuffer.size(); ++p, ++i) + { + m_rxVideoBuffer[i] = *p ^ 0x55; + } + //assign new buffer and the length back to SDK + packet.buffer = &m_rxVideoBuffer[0]; + packet.size = i; + return true; + } + +private: + std::vector m_txAudioBuffer; //buffer for sending audio data + std::vector m_txVideoBuffer; //buffer for sending video data + + std::vector m_rxAudioBuffer; //buffer for receiving audio data + std::vector m_rxVideoBuffer; //buffer for receiving video data +}; + +static AgoraCustomEncryptionObserver s_packetObserver; + +@implementation AgoraCustomEncryption + ++ (void)registerPacketProcessing:(AgoraRtcEngineKit *)rtcEngineKit { + if (!rtcEngineKit) { + return; + } + + agora::rtc::IRtcEngine* rtc_engine = (agora::rtc::IRtcEngine*)rtcEngineKit.getNativeHandle; + rtc_engine->registerPacketObserver(&s_packetObserver); +} + ++ (void)deregisterPacketProcessing:(AgoraRtcEngineKit *)rtcEngineKit { + if (!rtcEngineKit) { + return; + } + + agora::rtc::IRtcEngine* rtc_engine = (agora::rtc::IRtcEngine*)rtcEngineKit.getNativeHandle; + rtc_engine->registerPacketObserver(NULL); +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AgoraPcmSourcePush.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AgoraPcmSourcePush.swift new file mode 100644 index 000000000..ff0693df0 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AgoraPcmSourcePush.swift @@ -0,0 +1,79 @@ +// +// AgoraPcmSourcePush.swift +// APIExample +// +// Created by XC on 2021/1/10. +// Copyright © 2021 Agora Corp. All rights reserved. +// + +import Foundation + +protocol AgoraPcmSourcePushDelegate { + func onAudioFrame(data: UnsafeMutablePointer) +} + +class AgoraPcmSourcePush: NSObject { + fileprivate var delegate: AgoraPcmSourcePushDelegate? + private let filePath: String + private let sampleRate: Int + private let channelsPerFrame: Int + private let bitPerSample: Int + private let samples: Int + + private var state: State = .Stop + private let captureQueue: DispatchQueue + + enum State { + case Play + case Stop + } + + init(delegate: AgoraPcmSourcePushDelegate?, filePath: String, sampleRate: Int, channelsPerFrame: Int, bitPerSample: Int, samples: Int) { + self.delegate = delegate + self.filePath = filePath + self.sampleRate = sampleRate + self.channelsPerFrame = channelsPerFrame + self.bitPerSample = bitPerSample + self.samples = samples + captureQueue = DispatchQueue(label: "MyCaptureQueue") + } + + func start() { + if state == .Stop { + state = .Play + play() + } + } + + func stop() { + if state == .Play { + state = .Stop + } + } + + private func play() { + captureQueue.async { + guard let input = InputStream(fileAtPath: self.filePath) else { return } + input.open() + + let bufferSize = self.samples * self.bitPerSample / 8 * self.channelsPerFrame + let audioIntervalPreCall = TimeInterval(self.samples) / TimeInterval(self.sampleRate) + let buffer = UnsafeMutablePointer.allocate(capacity: bufferSize) + var index: Double = 0 + var firstPush: Double = 0 + while input.hasBytesAvailable && self.state == .Play { + if firstPush == 0 { + firstPush = CFAbsoluteTimeGetCurrent() + } + input.read(buffer, maxLength: bufferSize) + self.delegate?.onAudioFrame(data: buffer) + index += 1 + let nextPush = firstPush + index * audioIntervalPreCall + let sleep = nextPush - CFAbsoluteTimeGetCurrent() + Thread.sleep(forTimeInterval: sleep) + } + buffer.deallocate() + input.close() + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioController.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioController.h new file mode 100644 index 000000000..4149e80b9 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioController.h @@ -0,0 +1,35 @@ +// +// AudioController.h +// AudioCapture +// +// Created by CavanSu on 10/11/2017. +// Copyright © 2017 Agora. All rights reserved. +// + +#import +#import +#import "AudioOptions.h" + +@class AudioController; +@protocol AudioControllerDelegate +@optional +- (void)audioController:(AudioController *)controller + didCaptureData:(unsigned char *)data + bytesLength:(int)bytesLength; +- (int)audioController:(AudioController *)controller + didRenderData:(unsigned char *)data + bytesLength:(int)bytesLength; +- (void)audioController:(AudioController *)controller + error:(OSStatus)error + info:(NSString *)info; +@end + + +@interface AudioController : NSObject +@property (nonatomic, weak) id delegate; + ++ (instancetype)audioController; +- (void)setUpAudioSessionWithSampleRate:(int)sampleRate channelCount:(int)channelCount audioCRMode:(AudioCRMode)audioCRMode IOType:(IOUnitType)ioType; +- (void)startWork; +- (void)stopWork; + @end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioController.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioController.m new file mode 100644 index 000000000..1cd84fa85 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioController.m @@ -0,0 +1,417 @@ +// +// AudioController.m +// AudioCapture +// +// Created by CavanSu on 10/11/2017. +// Copyright © 2017 Agora. All rights reserved. +// + +#import "AudioController.h" +#import "AudioWriteToFile.h" + +#define InputBus 1 +#define OutputBus 0 + +@interface AudioController () +@property (nonatomic, assign) int sampleRate; +@property (nonatomic, assign) int channelCount; +@property (nonatomic, assign) AudioCRMode audioCRMode; +@property (nonatomic, assign) OSStatus error; + +@property (nonatomic, assign) AudioUnit remoteIOUnit; +#if TARGET_OS_MAC +@property (nonatomic, assign) AudioUnit macPlayUnit; +#endif +@end + +@implementation AudioController + +#if TARGET_OS_IPHONE +static double preferredIOBufferDuration = 0.02; +#endif + ++ (instancetype)audioController { + AudioController *audioController = [[self alloc] init]; + return audioController; +} + +#pragma mark - +static OSStatus captureCallBack(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, // inputBus = 1 + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + AudioController *audioController = (__bridge AudioController *)inRefCon; + + AudioUnit captureUnit = [audioController remoteIOUnit]; + + if (!inRefCon) return 0; + + AudioBuffer buffer; + buffer.mData = NULL; + buffer.mDataByteSize = 0; + buffer.mNumberChannels = audioController.channelCount; + + AudioBufferList bufferList; + bufferList.mNumberBuffers = 1; + bufferList.mBuffers[0] = buffer; + + OSStatus status = AudioUnitRender(captureUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames, + &bufferList); + + if (!status) { + if ([audioController.delegate respondsToSelector:@selector(audioController:didCaptureData:bytesLength:)]) { + [audioController.delegate audioController:audioController didCaptureData:(unsigned char *)bufferList.mBuffers[0].mData bytesLength:bufferList.mBuffers[0].mDataByteSize]; + } + } + else { + [audioController error:status position:@"captureCallBack"]; + } + + return 0; +} + +#pragma mark - +static OSStatus renderCallBack(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + AudioController *audioController = (__bridge AudioController *)(inRefCon); + + if (*ioActionFlags == kAudioUnitRenderAction_OutputIsSilence) { + return noErr; + } + + int result = 0; + + if ([audioController.delegate respondsToSelector:@selector(audioController:didRenderData:bytesLength:)]) { + result = [audioController.delegate audioController:audioController didRenderData:(uint8_t*)ioData->mBuffers[0].mData bytesLength:ioData->mBuffers[0].mDataByteSize]; + } + + if (result == 0) { + *ioActionFlags = kAudioUnitRenderAction_OutputIsSilence; + ioData->mBuffers[0].mDataByteSize = 0; + } + + return noErr; +} + + +#pragma mark - +- (void)setUpAudioSessionWithSampleRate:(int)sampleRate channelCount:(int)channelCount audioCRMode:(AudioCRMode)audioCRMode IOType:(IOUnitType)ioType{ + if (_audioCRMode == AudioCRModeSDKCaptureSDKRender) { + return; + } + + self.audioCRMode = audioCRMode; + self.sampleRate = sampleRate; + self.channelCount = channelCount; + +#if TARGET_OS_IPHONE + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + NSUInteger sessionOption = AVAudioSessionCategoryOptionMixWithOthers; + sessionOption |= AVAudioSessionCategoryOptionAllowBluetooth; + + [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:sessionOption error:nil]; + [audioSession setMode:AVAudioSessionModeDefault error:nil]; + [audioSession setPreferredIOBufferDuration:preferredIOBufferDuration error:nil]; + NSError *error; + BOOL success = [audioSession setActive:YES error:&error]; + if (!success) { + NSLog(@" audioSession setActive:YES error:nil"); + } + if (error) { + NSLog(@" setUpAudioSessionWithSampleRate : %@", error.localizedDescription); + } +#endif + + [self setupRemoteIOWithIOType:ioType]; +} + +#pragma mark - +- (void)setupRemoteIOWithIOType:(IOUnitType)ioType { +#if TARGET_OS_IPHONE + // AudioComponentDescription + AudioComponentDescription remoteIODesc; + remoteIODesc.componentType = kAudioUnitType_Output; + remoteIODesc.componentSubType = ioType == IOUnitTypeVPIO ? kAudioUnitSubType_VoiceProcessingIO : kAudioUnitSubType_RemoteIO; + remoteIODesc.componentManufacturer = kAudioUnitManufacturer_Apple; + remoteIODesc.componentFlags = 0; + remoteIODesc.componentFlagsMask = 0; + AudioComponent remoteIOComponent = AudioComponentFindNext(NULL, &remoteIODesc); + _error = AudioComponentInstanceNew(remoteIOComponent, &_remoteIOUnit); + [self error:_error position:@"AudioComponentInstanceNew"]; +#endif + + if (_audioCRMode == AudioCRModeExterCaptureSDKRender || _audioCRMode == AudioCRModeExterCaptureExterRender) { + +#if !TARGET_OS_IPHONE + AudioComponentDescription remoteIODesc; + remoteIODesc.componentType = kAudioUnitType_Output; + remoteIODesc.componentSubType = kAudioUnitSubType_HALOutput; + remoteIODesc.componentManufacturer = kAudioUnitManufacturer_Apple; + remoteIODesc.componentFlags = 0; + remoteIODesc.componentFlagsMask = 0; + AudioComponent remoteIOComponent = AudioComponentFindNext(NULL, &remoteIODesc); + _error = AudioComponentInstanceNew(remoteIOComponent, &_remoteIOUnit); + [self error:_error position:@"AudioComponentInstanceNew"]; + _error = AudioUnitInitialize(_remoteIOUnit); + [self error:_error position:@"AudioUnitInitialize"]; +#endif + [self setupCapture]; + } + + if (_audioCRMode == AudioCRModeSDKCaptureExterRender || _audioCRMode == AudioCRModeExterCaptureExterRender) { + +#if !TARGET_OS_IPHONE + AudioComponentDescription macPlayDesc; + macPlayDesc.componentType = kAudioUnitType_Output; + macPlayDesc.componentSubType = kAudioUnitSubType_DefaultOutput; + macPlayDesc.componentManufacturer = kAudioUnitManufacturer_Apple; + macPlayDesc.componentFlags = 0; + macPlayDesc.componentFlagsMask = 0; + AudioComponent macPlayComponent = AudioComponentFindNext(NULL, &macPlayDesc); + _error = AudioComponentInstanceNew(macPlayComponent, &_macPlayUnit); + [self error:_error position:@"AudioComponentInstanceNew"]; + _error = AudioUnitInitialize(_macPlayUnit); + [self error:_error position:@"AudioUnitInitialize"]; +#endif + [self setupRender]; + } + +} + +- (void)setupCapture { + // EnableIO + UInt32 one = 1; + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + InputBus, + &one, + sizeof(one)); + [self error:_error position:@"kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"]; + +#if !TARGET_OS_IPHONE + UInt32 disableFlag = 0; + + // Attention! set kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, disable + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + OutputBus, + &disableFlag, + sizeof(disableFlag)); + [self error:_error position:@"kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output"]; + + AudioDeviceID defaultDevice = kAudioDeviceUnknown; + UInt32 propertySize = sizeof(defaultDevice); + AudioObjectPropertyAddress defaultDeviceProperty = { + .mSelector = kAudioHardwarePropertyDefaultInputDevice, + .mScope = kAudioObjectPropertyScopeInput, + .mElement = kAudioObjectPropertyElementMaster + }; + + _error = AudioObjectGetPropertyData(kAudioObjectSystemObject, + &defaultDeviceProperty, + 0, + NULL, + &propertySize, + &defaultDevice); + [self error:_error position:@"AudioObjectGetPropertyData, kAudioObjectSystemObject"]; + + // Set the sample rate of the input device to the output samplerate (if possible) + Float64 temp = _sampleRate; + defaultDeviceProperty.mSelector = kAudioDevicePropertyNominalSampleRate; + + _error = AudioObjectSetPropertyData(defaultDevice, + &defaultDeviceProperty, + 0, + NULL, + sizeof(Float64), + &temp); + [self error:_error position:@"AudioObjectSetPropertyData, defaultDeviceProperty"]; + + // Set the input device to the system's default input device + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + InputBus, + &defaultDevice, + sizeof(defaultDevice)); + [self error:_error position:@"kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global"]; + +#endif + + // AudioStreamBasicDescription + AudioStreamBasicDescription streamFormatDesc = [self signedIntegerStreamFormatDesc]; + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + InputBus, + &streamFormatDesc, + sizeof(streamFormatDesc)); + [self error:_error position:@"kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output"]; + + // CallBack + AURenderCallbackStruct captureCallBackStruck; + captureCallBackStruck.inputProcRefCon = (__bridge void * _Nullable)(self); + captureCallBackStruck.inputProc = captureCallBack; + + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, + InputBus, + &captureCallBackStruck, + sizeof(captureCallBackStruck)); + [self error:_error position:@"kAudioOutputUnitProperty_SetInputCallback"]; +} + +- (void)setupRender { + +#if TARGET_OS_IPHONE + // EnableIO + UInt32 one = 1; + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + OutputBus, + &one, + sizeof(one)); + [self error:_error position:@"kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output"]; + + // AudioStreamBasicDescription + AudioStreamBasicDescription streamFormatDesc = [self signedIntegerStreamFormatDesc]; + _error = AudioUnitSetProperty(_remoteIOUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + OutputBus, + &streamFormatDesc, + sizeof(streamFormatDesc)); + [self error:_error position:@"kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input"]; + + // CallBack + AURenderCallbackStruct renderCallback; + renderCallback.inputProcRefCon = (__bridge void * _Nullable)(self); + renderCallback.inputProc = renderCallBack; + AudioUnitSetProperty(_remoteIOUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + OutputBus, + &renderCallback, + sizeof(renderCallback)); + [self error:_error position:@"kAudioUnitProperty_SetRenderCallback"]; + +#else + + // AudioStreamBasicDescription + AudioStreamBasicDescription streamFormatDesc = [self signedIntegerStreamFormatDesc]; + _error = AudioUnitSetProperty(_macPlayUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + OutputBus, + &streamFormatDesc, + sizeof(streamFormatDesc)); + [self error:_error position:@"kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input"]; + + // CallBack + AURenderCallbackStruct renderCallback; + renderCallback.inputProcRefCon = (__bridge void * _Nullable)(self); + renderCallback.inputProc = renderCallBack; + _error = AudioUnitSetProperty(_macPlayUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + OutputBus, + &renderCallback, + sizeof(renderCallback)); + [self error:_error position:@"kAudioUnitProperty_SetRenderCallback"]; +#endif + +} + +- (void)startWork { +#if TARGET_OS_IPHONE + _error = AudioOutputUnitStart(_remoteIOUnit); + [self error:_error position:@"AudioOutputUnitStart"]; +#else + if (_audioCRMode == AudioCRModeExterCaptureSDKRender || _audioCRMode == AudioCRModeExterCaptureExterRender) { + _error = AudioOutputUnitStart(_remoteIOUnit); + if (_error != noErr) { + [self error:_error position:@"AudioOutputUnitStart"]; + return; + } + } + + if (self.audioCRMode == AudioCRModeExterCaptureExterRender || self.audioCRMode == AudioCRModeSDKCaptureExterRender) { + _error = AudioOutputUnitStart(_macPlayUnit); + [self error:_error position:@"AudioOutputUnitStart"]; + } +#endif +} + +- (void)stopWork { +#if TARGET_OS_IPHONE + AudioOutputUnitStop(_remoteIOUnit); +#else + if (_audioCRMode == AudioCRModeExterCaptureSDKRender || _audioCRMode == AudioCRModeExterCaptureExterRender) { + AudioOutputUnitStop(_remoteIOUnit); + } + + if (self.audioCRMode == AudioCRModeExterCaptureExterRender || self.audioCRMode == AudioCRModeSDKCaptureExterRender) { + AudioOutputUnitStop(_macPlayUnit); + } +#endif +} + +- (void)error:(OSStatus)error position:(NSString *)position { + if (error != noErr) { + NSString *errorInfo = [NSString stringWithFormat:@" Error: %d, Position: %@", (int)error, position]; + if ([self.delegate respondsToSelector:@selector(audioController:error:info:)]) { + [self.delegate audioController:self error:error info:position]; + } + NSLog(@" :%@", errorInfo); + } +} + +- (AudioStreamBasicDescription)signedIntegerStreamFormatDesc { + AudioStreamBasicDescription streamFormatDesc; + streamFormatDesc.mSampleRate = _sampleRate; + streamFormatDesc.mFormatID = kAudioFormatLinearPCM; + streamFormatDesc.mFormatFlags = (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked); + streamFormatDesc.mChannelsPerFrame = _channelCount; + streamFormatDesc.mFramesPerPacket = 1; + streamFormatDesc.mBitsPerChannel = 16; + streamFormatDesc.mBytesPerFrame = streamFormatDesc.mBitsPerChannel / 8 * streamFormatDesc.mChannelsPerFrame; + streamFormatDesc.mBytesPerPacket = streamFormatDesc.mBytesPerFrame * streamFormatDesc.mFramesPerPacket; + + return streamFormatDesc; +} + +- (void)dealloc { + if (_remoteIOUnit) { + AudioOutputUnitStop(_remoteIOUnit); + AudioComponentInstanceDispose(_remoteIOUnit); + _remoteIOUnit = nil; + } + +#if !TARGET_OS_IPHONE + if (_macPlayUnit) { + AudioOutputUnitStop(_macPlayUnit); + AudioComponentInstanceDispose(_macPlayUnit); + _macPlayUnit = nil; + } +#endif + + NSLog(@" AudioController dealloc"); +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioOptions.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioOptions.h new file mode 100644 index 000000000..0a40ef9cc --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioOptions.h @@ -0,0 +1,40 @@ +// +// AudioOptions.h +// AgoraAudioIO +// +// Created by CavanSu on 12/03/2018. +// Copyright © 2018 CavanSu. All rights reserved. +// + +#ifndef AudioOptions_h +#define AudioOptions_h + +typedef NS_ENUM(int, AudioCRMode) { + AudioCRModeExterCaptureSDKRender = 1, + AudioCRModeSDKCaptureExterRender = 2, + AudioCRModeSDKCaptureSDKRender = 3, + AudioCRModeExterCaptureExterRender = 4 +}; + +typedef NS_ENUM(int, IOUnitType) { + IOUnitTypeVPIO, + IOUnitTypeRemoteIO +}; + +typedef NS_ENUM(int, ChannelMode) { + ChannelModeCommunication = 0, + ChannelModeLiveBroadcast = 1 +}; + +typedef NS_ENUM(int, ClientRole) { + ClientRoleAudience = 0, + ClientRoleBroadcast = 1 +}; + +#if TARGET_OS_IPHONE +#import "UIColor+CSRGB.h" +#import "UIView+CSshortFrame.h" +#define ThemeColor [UIColor Red: 122 Green: 203 Blue: 253] +#endif + +#endif /* AudioOptions_h */ diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioWriteToFile.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioWriteToFile.h new file mode 100644 index 000000000..9ccf24b14 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioWriteToFile.h @@ -0,0 +1,13 @@ +// +// AudioWriteToFile.h +// AudioCapture +// +// Created by CavanSu on 08/11/2017. +// Copyright © 2017 Agora. All rights reserved. +// + +#import + +@interface AudioWriteToFile : NSObject ++ (void)writeToFileWithData:(void *)data length:(int)bytes; +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioWriteToFile.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioWriteToFile.m new file mode 100644 index 000000000..54558635a --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/AudioWriteToFile.m @@ -0,0 +1,39 @@ +// +// AudioWriteToFile.m +// AudioCapture +// +// Created by CavanSu on 08/11/2017. +// Copyright © 2017 Agora. All rights reserved. +// + +#import "AudioWriteToFile.h" + +@implementation AudioWriteToFile + +static NSFileHandle *file = nil; +static dispatch_queue_t queue = nil; + ++ (void)load { + queue = dispatch_queue_create("writeFile", NULL); +} + ++ (void)writeToFileWithData:(void *)data length:(int)bytes { + if(NULL == data || bytes < 1) return; + + dispatch_async(queue, ^{ + + if (file == nil) { + NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"1.pcm"]; + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + if (![[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil]) { + + } + else { + file = [NSFileHandle fileHandleForWritingAtPath:path]; + } + } + [file writeData:[NSData dataWithBytes:data length:bytes]]; + }); +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ExternalAudio.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ExternalAudio.h new file mode 100644 index 000000000..8b1c20564 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ExternalAudio.h @@ -0,0 +1,31 @@ +// +// ExternalAudio.h +// AgoraAudioIO +// +// Created by CavanSu on 22/01/2018. +// Copyright © 2018 CavanSu. All rights reserved. +// + +#import +#import "AudioOptions.h" + +@class AgoraRtcEngineKit; +@class ExternalAudio; +@protocol ExternalAudioDelegate +@optional +- (void)externalAudio:(ExternalAudio *)externalAudio errorInfo:(NSString *)errorInfo; +@end + +@interface ExternalAudio : NSObject +@property (nonatomic, weak) id delegate; + ++ (instancetype)sharedExternalAudio; +- (void)setupExternalAudioWithAgoraKit:(AgoraRtcEngineKit *)agoraKit + sampleRate:(uint)sampleRate + channels:(uint)channels + trackId:(int)trackId + audioCRMode:(AudioCRMode)audioCRMode + IOType:(IOUnitType)ioType; +- (void)startWork; +- (void)stopWork; +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ExternalAudio.mm b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ExternalAudio.mm new file mode 100644 index 000000000..4067c6590 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ExternalAudio.mm @@ -0,0 +1,343 @@ +// +// ExternalAudio.m +// AgoraAudioIO +// +// Created by CavanSu on 22/01/2018. +// Copyright © 2018 CavanSu. All rights reserved. +// + +#import "ExternalAudio.h" +#import "AudioController.h" +#import "AudioWriteToFile.h" + +#if TARGET_OS_IPHONE +#import +#import +#import +#else +#import +#import +#import +#endif + +@interface ExternalAudio () +@property (nonatomic, strong) AudioController *audioController; +@property (nonatomic, assign) AudioCRMode audioCRMode; +@property (nonatomic, assign) int sampleRate; +@property (nonatomic, assign) int channelCount; +@property (nonatomic, weak) AgoraRtcEngineKit *agoraKit; +@property (nonatomic, assign) int trackId; +@end + +@implementation ExternalAudio + +static NSObject *threadLockCapture; +static NSObject *threadLockPlay; + +#pragma mark - C++ ExternalAudioFrameObserver +class ExternalAudioFrameObserver : public agora::media::IAudioFrameObserver +{ +private: + + // total buffer length of per second + enum { kBufferLengthBytes = 441 * 2 * 2 * 50 }; // + + // capture + char byteBuffer[kBufferLengthBytes]; // char take up 1 byte, byterBuffer[] take up 88200 bytes + int readIndex = 0; + int writeIndex = 0; + int availableBytes = 0; + int channels = 1; + + // play + char byteBuffer_play[kBufferLengthBytes]; + int readIndex_play = 0; + int writeIndex_play = 0; + int availableBytes_play = 0; + int channels_play = 1; + +public: + int sampleRate = 0; + int sampleRate_play = 0; + + bool isExternalCapture = false; + bool isExternalRender = false; + +#pragma mark- + // push audio data to special buffer(Array byteBuffer) + // bytesLength = date length + void pushExternalData(void* data, int bytesLength) + { + @synchronized(threadLockCapture) { + + if (availableBytes + bytesLength > kBufferLengthBytes) { + + readIndex = 0; + writeIndex = 0; + availableBytes = 0; + } + + if (writeIndex + bytesLength > kBufferLengthBytes) { + + int left = kBufferLengthBytes - writeIndex; + memcpy(byteBuffer + writeIndex, data, left); + memcpy(byteBuffer, (char *)data + left, bytesLength - left); + writeIndex = bytesLength - left; + } + else { + + memcpy(byteBuffer + writeIndex, data, bytesLength); + writeIndex += bytesLength; + } + availableBytes += bytesLength; + } + + } + + // copy byteBuffer to audioFrame.buffer + virtual bool onRecordAudioFrame(const char* channelId, AudioFrame& audioFrame) override + { + @synchronized(threadLockCapture) { + + if (isExternalCapture == false) return true; + + int readBytes = sampleRate / 100 * channels * audioFrame.bytesPerSample; + + if (availableBytes < readBytes) { + return false; + } + + audioFrame.samplesPerSec = sampleRate; + unsigned char tmp[960]; // The most rate:@48k fs, channels = 1, the most total size = 960; + + if (readIndex + readBytes > kBufferLengthBytes) { + int left = kBufferLengthBytes - readIndex; + memcpy(tmp, byteBuffer + readIndex, left); + memcpy(tmp + left, byteBuffer, readBytes - left); + readIndex = readBytes - left; + } + else { + memcpy(tmp, byteBuffer + readIndex, readBytes); + readIndex += readBytes; + } + + availableBytes -= readBytes; + + if (channels == audioFrame.channels) { + memcpy(audioFrame.buffer, tmp, readBytes); + } + [AudioWriteToFile writeToFileWithData:audioFrame.buffer length:readBytes]; + return true; + } + + } + +#pragma mark- + // read Audio data from byteBuffer_play to audioUnit + int readAudioData(void* data, int bytesLength) + { + @synchronized(threadLockPlay) { + + if (NULL == data || bytesLength < 1 || availableBytes_play < bytesLength) { + return 0; + } + + int readBytes = bytesLength; + + unsigned char tmp[4096]; // unsigned char takes up 1 byte + + if (readIndex_play + readBytes > kBufferLengthBytes) { + + int left = kBufferLengthBytes - readIndex_play; + memcpy(tmp, byteBuffer_play + readIndex_play, left); + memcpy(tmp + left, byteBuffer_play, readBytes - left); + readIndex_play = readBytes - left; + } + else { + + memcpy(tmp, byteBuffer_play + readIndex_play, readBytes); + readIndex_play += readBytes; + } + + availableBytes_play -= readBytes; + + if (channels_play == 1) { + memcpy(data, tmp, readBytes); + } + + [AudioWriteToFile writeToFileWithData:data length:readBytes]; + + return readBytes; + } + + } + + virtual bool onEarMonitoringAudioFrame(AudioFrame& audioFrame) override { + return true; + } + + // recive remote audio stream, push audio data to byteBuffer_play + virtual bool onPlaybackAudioFrame(const char* channelId, AudioFrame& audioFrame) override + { + @synchronized(threadLockPlay) { + + if (isExternalRender == false) return true; + + int bytesLength = audioFrame.samplesPerChannel * audioFrame.channels * audioFrame.bytesPerSample; + char *data = (char *)audioFrame.buffer; + + sampleRate_play = audioFrame.samplesPerSec; + channels_play = audioFrame.channels; + + if (availableBytes_play + bytesLength > kBufferLengthBytes) { + + readIndex_play = 0; + writeIndex_play = 0; + availableBytes_play = 0; + } + + if (writeIndex_play + bytesLength > kBufferLengthBytes) { + + int left = kBufferLengthBytes - writeIndex_play; + memcpy(byteBuffer_play + writeIndex_play, data, left); + memcpy(byteBuffer_play, (char *)data + left, bytesLength - left); + writeIndex_play = bytesLength - left; + } + else { + + memcpy(byteBuffer_play + writeIndex_play, data, bytesLength); + writeIndex_play += bytesLength; + } + + availableBytes_play += bytesLength; + + return true; + } + + } + + virtual AudioParams getEarMonitoringAudioParams() override { + return AudioParams(); + } + + virtual bool onPlaybackAudioFrameBeforeMixing(const char* channelId, agora::rtc::uid_t uid, AudioFrame& audioFrame) override { return true; } + + virtual bool onMixedAudioFrame(const char* channelId, AudioFrame& audioFrame) override { return true; } + + virtual int getObservedAudioFramePosition() override { + return AUDIO_FRAME_POSITION_NONE; + } + virtual AudioParams getPlaybackAudioParams() override { + return AudioParams(); + } + virtual AudioParams getRecordAudioParams() override { + return AudioParams(); + } + virtual AudioParams getMixedAudioParams() override { + return AudioParams(); + } +}; + +static ExternalAudioFrameObserver* s_audioFrameObserver; + + ++ (instancetype)sharedExternalAudio { + ExternalAudio *audio = [[ExternalAudio alloc] init]; + return audio; +} + +- (void)setupExternalAudioWithAgoraKit:(AgoraRtcEngineKit *)agoraKit + sampleRate:(uint)sampleRate + channels:(uint)channels + trackId:(int)trackId + audioCRMode:(AudioCRMode)audioCRMode + IOType:(IOUnitType)ioType { + + threadLockCapture = [[NSObject alloc] init]; + threadLockPlay = [[NSObject alloc] init]; + + // AudioController + self.audioController = [AudioController audioController]; + self.audioController.delegate = self; + [self.audioController setUpAudioSessionWithSampleRate:sampleRate channelCount:channels audioCRMode:audioCRMode IOType:ioType]; + + // Agora Engine of C++ + agora::rtc::IRtcEngine* rtc_engine = (agora::rtc::IRtcEngine*)agoraKit.getNativeHandle; + agora::util::AutoPtr mediaEngine; + mediaEngine.queryInterface(rtc_engine, agora::rtc::AGORA_IID_MEDIA_ENGINE); + + if (mediaEngine) { + s_audioFrameObserver = new ExternalAudioFrameObserver(); + s_audioFrameObserver -> sampleRate = sampleRate; + s_audioFrameObserver -> sampleRate_play = channels; + mediaEngine->registerAudioFrameObserver(s_audioFrameObserver); + } + + if (audioCRMode == AudioCRModeExterCaptureExterRender || audioCRMode == AudioCRModeSDKCaptureExterRender) { + s_audioFrameObserver -> isExternalRender = true; + } + if (audioCRMode == AudioCRModeExterCaptureExterRender || audioCRMode == AudioCRModeExterCaptureSDKRender) { + s_audioFrameObserver -> isExternalCapture = true; + } + + self.agoraKit = agoraKit; + self.audioCRMode = audioCRMode; + self.trackId = trackId; + self.sampleRate = sampleRate; +} + +- (void)startWork { + [self.audioController startWork]; +} + +- (void)stopWork { + [self.audioController stopWork]; + [self cancelRegister]; +} + +- (void)cancelRegister { + agora::rtc::IRtcEngine* rtc_engine = (agora::rtc::IRtcEngine*)self.agoraKit.getNativeHandle; + agora::util::AutoPtr mediaEngine; + mediaEngine.queryInterface(rtc_engine, agora::rtc::AGORA_IID_MEDIA_ENGINE); + mediaEngine->registerAudioFrameObserver(NULL); +} + +- (void)audioController:(AudioController *)controller didCaptureData:(unsigned char *)data bytesLength:(int)bytesLength { + + if (self.audioCRMode != AudioCRModeExterCaptureSDKRender) { + if (s_audioFrameObserver) { + s_audioFrameObserver -> pushExternalData(data, bytesLength); + } + } + else { +// [self.agoraKit pushExternalAudioFrameNSData:[NSData dataWithBytes:data length:bytesLength] sourceId:1 timestamp:0]; + [self.agoraKit pushExternalAudioFrameRawData: data + samples: self.sampleRate + trackId:self.trackId + timestamp:0]; + } + +} + +- (int)audioController:(AudioController *)controller didRenderData:(unsigned char *)data bytesLength:(int)bytesLength { + int result = 0; + + if (s_audioFrameObserver) { + result = s_audioFrameObserver -> readAudioData(data, bytesLength); + } + + return result; +} + +- (void)audioController:(AudioController *)controller error:(OSStatus)error info:(NSString *)info { + if ([self.delegate respondsToSelector:@selector(externalAudio:errorInfo:)]) { + NSString *errorInfo = [NSString stringWithFormat:@" error:%d, info:%@", error, info]; + [self.delegate externalAudio:self errorInfo:errorInfo]; + } +} + +- (void)dealloc { + NSLog(@"ExAudio dealloc"); +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIColor+CSRGB.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIColor+CSRGB.h new file mode 100755 index 000000000..5027c3e5d --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIColor+CSRGB.h @@ -0,0 +1,12 @@ +// +// UIColor+CSRGB.h +// +// Created by CavanSu on 17/3/3. +// Copyright © 2017 CavanSu. All rights reserved. +// + +#import + +@interface UIColor (CSRGB) ++ (UIColor*)Red:(CGFloat)red Green:(CGFloat)green Blue:(CGFloat)blue; +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIColor+CSRGB.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIColor+CSRGB.m new file mode 100755 index 000000000..2c454a76b --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIColor+CSRGB.m @@ -0,0 +1,15 @@ +// +// UIColor+CSRGB.m +// +// Created by CavanSu on 17/3/3. +// Copyright © 2017 CavanSu. All rights reserved. +// + +#import "UIColor+CSRGB.h" + +@implementation UIColor (CSRGB) ++ (UIColor*)Red:(CGFloat)red Green:(CGFloat)green Blue:(CGFloat)blue { + UIColor *color = [UIColor colorWithRed:red / 255 green:green / 255 blue:blue / 255 alpha: 1]; + return color; +} +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIView+CSshortFrame.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIView+CSshortFrame.h new file mode 100755 index 000000000..f0b6e43ed --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIView+CSshortFrame.h @@ -0,0 +1,19 @@ +// +// UIView+CSshortFrame.h +// +// Created by CavanSu on 23/02/2017. +// Copyright © 2017 CavanSu. All rights reserved. +// + +#import + +@interface UIView (CSshortFrame) +@property (assign, nonatomic) CGFloat x_CS; +@property (assign, nonatomic) CGFloat y_CS; +@property (assign, nonatomic) CGFloat width_CS; +@property (assign, nonatomic) CGFloat height_CS; +@property (assign, nonatomic) CGSize size_CS; +@property (assign, nonatomic) CGPoint origin_CS; +@property (assign, nonatomic) CGFloat centerX_CS; +@property (assign, nonatomic) CGFloat centerY_CS; +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIView+CSshortFrame.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIView+CSshortFrame.m new file mode 100755 index 000000000..b7ebd834d --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/UIView+CSshortFrame.m @@ -0,0 +1,90 @@ +// +// UIView+CSshortFrame.m +// +// Created by CavanSu on 23/02/2017. +// Copyright © 2017 CavanSu. All rights reserved. +// + +#import "UIView+CSshortFrame.h" + +@implementation UIView (CSshortFrame) +-(void)setX_CS:(CGFloat)x_CS { + CGRect frame = self.frame; + frame.origin.x = x_CS; + self.frame = frame; +} + +-(CGFloat)x_CS { + return self.frame.origin.x; +} + +-(void)setY_CS:(CGFloat)y_CS { + CGRect frame = self.frame; + frame.origin.y = y_CS; + self.frame = frame; +} + +-(CGFloat)y_CS { + return self.frame.origin.y; +} + +-(void)setWidth_CS:(CGFloat)width_CS { + CGRect frame = self.frame; + frame.size.width = width_CS; + self.frame = frame; +} + +-(CGFloat)width_CS { + return self.frame.size.width; +} + +-(void)setHeight_CS:(CGFloat)height_CS { + CGRect frame = self.frame; + frame.size.height = height_CS; + self.frame = frame; +} + +-(CGFloat)height_CS { + return self.frame.size.height; +} + +-(void)setSize_CS:(CGSize)size_CS { + CGRect frame = self.frame; + frame.size = size_CS; + self.frame = frame; +} + +-(CGSize)size_CS { + return self.frame.size; +} + +-(void)setOrigin_CS:(CGPoint)origin_CS { + CGRect frame = self.frame; + frame.origin = origin_CS; + self.frame = frame; +} + +-(CGPoint)origin_CS { + return self.frame.origin; +} + +-(void)setCenterX_CS:(CGFloat)centerX_CS { + CGPoint center = self.center; + center.x = centerX_CS; + self.center = center; +} + +-(CGFloat)centerX_CS { + return self.center.x; +} + +-(void)setCenterY_CS:(CGFloat)centerY_CS { + CGPoint center = self.center; + center.y = centerY_CS; + self.center = center; +} + +-(CGFloat)centerY_CS { + return self.center.y; +} +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ZSNBoxingView.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ZSNBoxingView.h new file mode 100644 index 000000000..065316760 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ZSNBoxingView.h @@ -0,0 +1,33 @@ +// +// ZSNBoxingView.h +// DemoAPIOCZhaosn +// +// Created by zhaosuning on 2022/12/1. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ZSNBoxingView : UIView + +@property (nonatomic, copy) void (^itemLevelCallback)(void); + +@property (nonatomic) NSUInteger numberOfItems; + +@property (nonatomic) UIColor * itemColor; + +@property (nonatomic) CGFloat level; + +@property (nonatomic) UILabel *timeLabel; + +@property (nonatomic) NSString *text; + +@property (nonatomic) CGFloat middleInterval; + +- (void)start; +- (void)stop; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ZSNBoxingView.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ZSNBoxingView.m new file mode 100644 index 000000000..c2e3ffa95 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalAudio/ZSNBoxingView.m @@ -0,0 +1,221 @@ +// +// ZSNBoxingView.m +// DemoAPIOCZhaosn +// +// Created by zhaosuning on 2022/12/1. +// + +#import "ZSNBoxingView.h" + +@interface ZSNBoxingView() + +@property (nonatomic, strong) NSMutableArray * levels; +@property (nonatomic, strong) NSMutableArray * itemLineLayers; +@property (nonatomic) CGFloat itemHeight; +@property (nonatomic) CGFloat itemWidth; +@property (nonatomic) CGFloat lineWidth;//自适应 + +@property (nonatomic, strong) CADisplayLink *displayLink; + + +@end + +@implementation ZSNBoxingView + +- (id)init { + NSLog(@"init"); + if(self = [super init]) { + [self setup]; + } + + return self; +} + + + +- (id)initWithFrame:(CGRect)frame { + NSLog(@"initWithFrame"); + if (self = [super initWithFrame:frame]) { + [self setup]; + } + + return self; +} + +- (void)awakeFromNib +{ + [super awakeFromNib]; + NSLog(@"awakeFromNib"); + [self setup]; +} + +- (void)setup { + + NSLog(@"setup"); + + self.numberOfItems = 20.f;//偶数 + + self.itemColor = [UIColor colorWithRed:255/255.f green:0/255.f blue:255/255.f alpha:1.0]; + + self.middleInterval = 30.f; + + self.timeLabel = [[UILabel alloc]init]; + self.timeLabel.text = @""; + [self.timeLabel setTextColor:[UIColor grayColor]]; + [self.timeLabel setTextAlignment:NSTextAlignmentCenter]; + [self addSubview:self.timeLabel]; +} + +#pragma mark - layout + +- (void)layoutSubviews { + [super layoutSubviews]; + + self.itemHeight = CGRectGetHeight(self.bounds); + self.itemWidth = CGRectGetWidth(self.bounds); + + [self.timeLabel sizeToFit]; + self.timeLabel.center = CGPointMake(self.itemWidth * 0.5f, self.itemHeight * 0.5f); + + self.lineWidth = (self.itemWidth - self.middleInterval) / 2.f / self.numberOfItems; +} + +#pragma mark - setter + +- (void)setItemColor:(UIColor *)itemColor { + _itemColor = itemColor; + for (CAShapeLayer *itemLine in self.itemLineLayers) { + itemLine.strokeColor = [self.itemColor CGColor]; + } +} + +- (void)setNumberOfItems:(NSUInteger)numberOfItems { + if (_numberOfItems == numberOfItems) { + return; + } + _numberOfItems = numberOfItems; + + self.levels = [[NSMutableArray alloc]init]; + for(int i = 0 ; i < self.numberOfItems / 2 ; i++){ + [self.levels addObject:@(0)]; + } + + + for (CAShapeLayer *itemLine in self.itemLineLayers) { + [itemLine removeFromSuperlayer]; + } + self.itemLineLayers = [NSMutableArray array]; + for(int i=0; i < numberOfItems; i++) { + CAShapeLayer *itemLine = [CAShapeLayer layer]; + itemLine.lineCap = kCALineCapButt; + itemLine.lineJoin = kCALineJoinRound; + itemLine.strokeColor = [[UIColor clearColor] CGColor]; + itemLine.fillColor = [[UIColor clearColor] CGColor]; + itemLine.strokeColor = [self.itemColor CGColor]; + itemLine.lineWidth = self.lineWidth; + + [self.layer addSublayer:itemLine]; + [self.itemLineLayers addObject:itemLine]; + } +} + +- (void)setLineWidth:(CGFloat)lineWidth { + if (_lineWidth != lineWidth) { + _lineWidth = lineWidth; + for (CAShapeLayer *itemLine in self.itemLineLayers) { + itemLine.lineWidth = lineWidth; + } + } +} + +- (void)setItemLevelCallback:(void (^)(void))itemLevelCallback { + NSLog(@"setItemLevelCallback"); + + _itemLevelCallback = itemLevelCallback; + + [self start]; + +} + + +- (void)setLevel:(CGFloat)level { + //NSLog(@"setLevel:%f",level); + level = (level+37.5)*3.2; + if( level < 0 ) level = 0; + + [self.levels removeObjectAtIndex:self.numberOfItems/2-1]; + [self.levels insertObject:@(level / 2.f) atIndex:0]; + + [self updateItems]; + +} + + +- (void)setText:(NSString *)text{ + self.timeLabel.text = text; +} + +- (void)setMiddleInterval:(CGFloat)middleInterval { + if (_middleInterval != middleInterval) { + _middleInterval = middleInterval; + [self setNeedsLayout]; + } +} + + +#pragma mark - update + +- (void)updateItems { + //NSLog(@"updateMeters"); + + UIGraphicsBeginImageContext(self.frame.size); + + int lineOffset = self.lineWidth * 2.f; + + int leftX = (self.itemWidth - self.middleInterval + self.lineWidth) / 2.f; + int rightX = (self.itemWidth + self.middleInterval - self.lineWidth) / 2.f; + + + for(int i = 0; i < self.numberOfItems / 2; i++) { + + CGFloat lineHeight = self.lineWidth + [self.levels[i] floatValue] * self.lineWidth / 2.f; + //([[self.levels objectAtIndex:i]intValue]+1)*self.lineWidth/2.f; + CGFloat lineTop = (self.itemHeight - lineHeight) / 8; + CGFloat lineBottom = (self.itemHeight + lineHeight) / 8; + + + leftX -= lineOffset; + + UIBezierPath *linePathLeft = [UIBezierPath bezierPath]; + [linePathLeft moveToPoint:CGPointMake(leftX, lineTop)]; + [linePathLeft addLineToPoint:CGPointMake(leftX, lineBottom)]; + CAShapeLayer *itemLine2 = [self.itemLineLayers objectAtIndex:i + self.numberOfItems / 2]; + itemLine2.path = [linePathLeft CGPath]; + + + rightX += lineOffset; + + UIBezierPath *linePathRight = [UIBezierPath bezierPath]; + [linePathRight moveToPoint:CGPointMake(rightX, lineTop)]; + [linePathRight addLineToPoint:CGPointMake(rightX, lineBottom)]; + CAShapeLayer *itemLine = [self.itemLineLayers objectAtIndex:i]; + itemLine.path = [linePathRight CGPath]; + } + + UIGraphicsEndImageContext(); +} + +- (void)start { + if (self.displayLink == nil) { + self.displayLink = [CADisplayLink displayLinkWithTarget:_itemLevelCallback selector:@selector(invoke)]; + self.displayLink.preferredFramesPerSecond = 6.f; + [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + } +} + +- (void)stop { + [self.displayLink invalidate]; + self.displayLink = nil; +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraCameraSourcePush.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraCameraSourcePush.swift new file mode 100644 index 000000000..7ada1cbe2 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraCameraSourcePush.swift @@ -0,0 +1,170 @@ +//// +//// MyVideoCapture.swift +//// Agora-Video-Source +//// +//// Created by GongYuhua on 2017/4/11. +//// Copyright © 2017年 Agora. All rights reserved. +//// +// +//import UIKit +//import AVFoundation +// +//protocol AgoraCameraSourcePushDelegate { +// func myVideoCapture(_ capture: AgoraCameraSourcePush, didOutputSampleBuffer pixelBuffer: CVPixelBuffer, rotation: Int, timeStamp: CMTime) +//} +// +//enum Camera: Int { +// case front = 1 +// case back = 0 +// +// static func defaultCamera() -> Camera { +// return .front +// } +// +// func next() -> Camera { +// switch self { +// case .back: return .front +// case .front: return .back +// } +// } +//} +// +//class AgoraCameraSourcePush: NSObject { +// +// fileprivate var delegate: AgoraCameraSourcePushDelegate? +// private var videoView: CustomVideoSourcePreview +// +// private var currentCamera = Camera.defaultCamera() +// private let captureSession: AVCaptureSession +// private let captureQueue: DispatchQueue +// private var currentOutput: AVCaptureVideoDataOutput? { +// if let outputs = self.captureSession.outputs as? [AVCaptureVideoDataOutput] { +// return outputs.first +// } else { +// return nil +// } +// } +// +// init(delegate: AgoraCameraSourcePushDelegate?, videoView: CustomVideoSourcePreview) { +// self.delegate = delegate +// self.videoView = videoView +// +// captureSession = AVCaptureSession() +// captureSession.usesApplicationAudioSession = false +// +// let captureOutput = AVCaptureVideoDataOutput() +// captureOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] +// if captureSession.canAddOutput(captureOutput) { +// captureSession.addOutput(captureOutput) +// } +// +// captureQueue = DispatchQueue(label: "MyCaptureQueue") +// +// let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) +// videoView.insertCaptureVideoPreviewLayer(previewLayer: previewLayer) +// } +// +// deinit { +// captureSession.stopRunning() +// } +// +// func startCapture(ofCamera camera: Camera) { +// guard let currentOutput = currentOutput else { +// return +// } +// +// currentCamera = camera +// currentOutput.setSampleBufferDelegate(self, queue: captureQueue) +// +// captureQueue.async { [weak self] in +// guard let strongSelf = self else { +// return +// } +// strongSelf.changeCaptureDevice(toIndex: camera.rawValue, ofSession: strongSelf.captureSession) +// strongSelf.captureSession.beginConfiguration() +// if strongSelf.captureSession.canSetSessionPreset(AVCaptureSession.Preset.vga640x480) { +// strongSelf.captureSession.sessionPreset = AVCaptureSession.Preset.vga640x480 +// } +// strongSelf.captureSession.commitConfiguration() +// strongSelf.captureSession.startRunning() +// } +// } +// +// func stopCapture() { +// currentOutput?.setSampleBufferDelegate(nil, queue: nil) +// captureQueue.async { [weak self] in +// self?.captureSession.stopRunning() +// } +// } +// +// func switchCamera() { +// stopCapture() +// currentCamera = currentCamera.next() +// startCapture(ofCamera: currentCamera) +// } +//} +// +//private extension AgoraCameraSourcePush { +// func changeCaptureDevice(toIndex index: Int, ofSession captureSession: AVCaptureSession) { +// guard let captureDevice = captureDevice(atIndex: index) else { +// return +// } +// +// let currentInputs = captureSession.inputs as? [AVCaptureDeviceInput] +// let currentInput = currentInputs?.first +// +// if let currentInputName = currentInput?.device.localizedName, +// currentInputName == captureDevice.uniqueID { +// return +// } +// +// guard let newInput = try? AVCaptureDeviceInput(device: captureDevice) else { +// return +// } +// +// captureSession.beginConfiguration() +// if let currentInput = currentInput { +// captureSession.removeInput(currentInput) +// } +// if captureSession.canAddInput(newInput) { +// captureSession.addInput(newInput) +// } +// captureSession.commitConfiguration() +// } +// +// func captureDevice(atIndex index: Int) -> AVCaptureDevice? { +// let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], +// mediaType: .video, +// position: .back) +// let devices = deviceDiscoverySession.devices +// +// let count = devices.count +// guard !devices.isEmpty, index >= 0 else { +// return nil +// } +// +// let device: AVCaptureDevice +// if index >= count, let d = devices.last { +// device = d +// } else { +// device = devices[index] +// } +// return device +// } +//} +// +//extension AgoraCameraSourcePush: AVCaptureVideoDataOutputSampleBufferDelegate { +// func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { +// guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { +// return +// } +// let time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) +// DispatchQueue.main.async {[weak self] in +// guard let weakSelf = self else { +// return +// } +// +// weakSelf.delegate?.myVideoCapture(weakSelf, didOutputSampleBuffer: pixelBuffer, rotation: 90, timeStamp: time) +// } +// } +//} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraMetalRender.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraMetalRender.swift new file mode 100644 index 000000000..d7af2e947 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraMetalRender.swift @@ -0,0 +1,361 @@ +// +// AgoraMetalRender.swift +// Agora-Custom-Media-Device +// +// Created by GongYuhua on 2017/11/15. +// Copyright © 2017年 Agora.io All rights reserved. +// + +import CoreMedia +import Metal +import MetalKit + +#if os(iOS) && (!arch(i386) && !arch(x86_64)) + import MetalKit +#endif +import AgoraRtcKit + +protocol AgoraMetalRenderMirrorDataSource: NSObjectProtocol { + func renderViewShouldMirror(renderView: AgoraMetalRender) -> Bool +} + +enum AgoraVideoRotation: Int { + /** 0: No rotation */ + case rotationNone = 0 + /** 1: 90 degrees */ + case rotation90 = 1 + /** 2: 180 degrees */ + case rotation180 = 2 + /** 3: 270 degrees */ + case rotation270 = 3 +} + +class AgoraMetalRender: UIView { + weak var mirrorDataSource: AgoraMetalRenderMirrorDataSource? + + fileprivate var textures: [MTLTexture]? + fileprivate var vertexBuffer: MTLBuffer? + fileprivate var viewSize = CGSize.zero + + fileprivate var device = MTLCreateSystemDefaultDevice() + fileprivate var renderPipelineState: MTLRenderPipelineState? + fileprivate let semaphore = DispatchSemaphore(value: 1) + fileprivate var metalDevice = MTLCreateSystemDefaultDevice() +#if os(iOS) && (!arch(i386) && !arch(x86_64)) + fileprivate var metalView: MTKView! + fileprivate var textureCache: CVMetalTextureCache? +#endif + fileprivate var commandQueue: MTLCommandQueue? + + fileprivate var userId: UInt = 0 + + init() { + super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) + initializeMetalView() + initializeTextureCache() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initializeMetalView() + initializeTextureCache() + } + + override init(frame frameRect: CGRect) { + super.init(frame: frameRect) + initializeMetalView() + initializeTextureCache() + } + + override var bounds: CGRect { + didSet { + viewSize = bounds.size + } + } + + func startRender(uid: UInt) { + userId = uid + initializeRenderPipelineState() +#if os(iOS) && (!arch(i386) && !arch(x86_64)) + metalView.delegate = self +#endif + } + + func stopRender(uid: UInt) { + userId = 0 +#if os(iOS) && (!arch(i386) && !arch(x86_64)) + metalView.delegate = nil +#endif + } +} + +func getAgoraRotation(rotation: Int32) -> AgoraVideoRotation? { + switch rotation { + case 0: + return .rotationNone + case 90: + return .rotation90 + case 180: + return .rotation180 + case 270: + return .rotation270 + default: + return nil + } +} + +extension AgoraMetalRender: AgoraVideoFrameDelegate { + func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { + true + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { + if uid != userId { + return false + } + +#if os(iOS) && (!arch(i386) && !arch(x86_64)) + guard let rotation = getAgoraRotation(rotation: videoFrame.rotation) else { + return false + } + + guard let pixelBuffer = videoFrame.pixelBuffer else { + return false + } + guard CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly) == kCVReturnSuccess else { + return false + } + defer { + CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly) + } + + let isPlanar = CVPixelBufferIsPlanar(pixelBuffer) + let width = isPlanar ? CVPixelBufferGetWidthOfPlane(pixelBuffer, 0) : CVPixelBufferGetWidth(pixelBuffer) + let height = isPlanar ? CVPixelBufferGetHeightOfPlane(pixelBuffer, 0) : CVPixelBufferGetHeight(pixelBuffer) + let size = CGSize(width: width, height: height) + + let mirror = mirrorDataSource?.renderViewShouldMirror(renderView: self) ?? false + if let renderedCoordinates = rotation.renderedCoordinates(mirror: mirror, + videoSize: size, + viewSize: viewSize) { + let byteLength = 4 * MemoryLayout.size(ofValue: renderedCoordinates[0]) + vertexBuffer = device?.makeBuffer(bytes: renderedCoordinates, length: byteLength, options: [.storageModeShared]) + } + + if let yTexture = texture(pixelBuffer: pixelBuffer, textureCache: textureCache, planeIndex: 0, pixelFormat: .r8Unorm), + let uvTexture = texture(pixelBuffer: pixelBuffer, textureCache: textureCache, planeIndex: 1, pixelFormat: .rg8Unorm) { + self.textures = [yTexture, uvTexture] + } +#endif + return true + } + + func getVideoFrameProcessMode() -> AgoraVideoFrameProcessMode { + return .readOnly + } + + func onPreEncode(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { + true + } + + func getVideoFormatPreference() -> AgoraVideoFormat { + .cvPixelNV12 + } + func getObservedFramePosition() -> AgoraVideoFramePosition { + .preRenderer + } +} + +private extension AgoraMetalRender { + func initializeMetalView() { + #if os(iOS) && (!arch(i386) && !arch(x86_64)) + metalView = MTKView(frame: bounds, device: device) + metalView.framebufferOnly = true + metalView.colorPixelFormat = .bgra8Unorm + metalView.contentScaleFactor = UIScreen.main.scale + metalView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + addSubview(metalView) + commandQueue = device?.makeCommandQueue() + #endif + } + + func initializeRenderPipelineState() { + guard let device = device, let library = device.makeDefaultLibrary() else { + return + } + + let pipelineDescriptor = MTLRenderPipelineDescriptor() + pipelineDescriptor.sampleCount = 1 + pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm + pipelineDescriptor.depthAttachmentPixelFormat = .invalid + + pipelineDescriptor.vertexFunction = library.makeFunction(name: "mapTexture") + pipelineDescriptor.fragmentFunction = library.makeFunction(name: "displayNV12Texture") + + renderPipelineState = try? device.makeRenderPipelineState(descriptor: pipelineDescriptor) + } + + func initializeTextureCache() { + #if os(iOS) && (!arch(i386) && !arch(x86_64)) + guard let metalDevice = metalDevice, + CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, metalDevice, nil, &textureCache) == kCVReturnSuccess else { + return + } + #endif + } + +#if os(iOS) && (!arch(i386) && !arch(x86_64)) + func texture(pixelBuffer: CVPixelBuffer, + textureCache: CVMetalTextureCache?, + planeIndex: Int = 0, + pixelFormat: MTLPixelFormat = .bgra8Unorm) -> MTLTexture? { + guard let textureCache = textureCache, + CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly) == kCVReturnSuccess else { + return nil + } + defer { + CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly) + } + + let isPlanar = CVPixelBufferIsPlanar(pixelBuffer) + let width = isPlanar ? CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex) : CVPixelBufferGetWidth(pixelBuffer) + let height = isPlanar ? CVPixelBufferGetHeightOfPlane(pixelBuffer, planeIndex) : CVPixelBufferGetHeight(pixelBuffer) + + var imageTexture: CVMetalTexture? + let result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, + textureCache, + pixelBuffer, + nil, + pixelFormat, + width, + height, + planeIndex, + &imageTexture) + + guard let unwrappedImageTexture = imageTexture, + let texture = CVMetalTextureGetTexture(unwrappedImageTexture), + result == kCVReturnSuccess + else { + return nil + } + + return texture + } +#endif +} + +#if os(iOS) && (!arch(i386) && !arch(x86_64)) +extension AgoraMetalRender: MTKViewDelegate { + public func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { + + } + + public func draw(in: MTKView) { + guard viewSize.width > 0 && viewSize.height > 0 else { + return + } + + _ = semaphore.wait(timeout: .distantFuture) + guard let textures = textures, let device = device, + let commandBuffer = commandQueue?.makeCommandBuffer(), let vertexBuffer = vertexBuffer else { + semaphore.signal() + return + } + + render(textures: textures, withCommandBuffer: commandBuffer, device: device, vertexBuffer: vertexBuffer) + } + + private func render(textures: [MTLTexture], withCommandBuffer commandBuffer: MTLCommandBuffer, device: MTLDevice, vertexBuffer: MTLBuffer) { + guard let currentRenderPassDescriptor = metalView.currentRenderPassDescriptor, + let currentDrawable = metalView.currentDrawable, + let renderPipelineState = renderPipelineState, + let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: currentRenderPassDescriptor) else { + semaphore.signal() + return + } + + encoder.pushDebugGroup("Agora-Custom-Render-Frame") + encoder.setRenderPipelineState(renderPipelineState) + encoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0) + + if let textureY = textures.first, let textureUV = textures.last { + encoder.setFragmentTexture(textureY, index: 0) + encoder.setFragmentTexture(textureUV, index: 1) + encoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4) + } + + encoder.popDebugGroup() + encoder.endEncoding() + + commandBuffer.addScheduledHandler { [weak self] _ in + self?.semaphore.signal() + } + commandBuffer.present(currentDrawable) + commandBuffer.commit() + } +} +#endif +extension AgoraVideoRotation { + func renderedCoordinates(mirror: Bool, + videoSize: CGSize, + viewSize: CGSize) -> [simd_float4]? { + guard viewSize.width > 0, + viewSize.height > 0, + videoSize.width > 0, + videoSize.height > 0 else { + return nil + } + + let widthAspito: Float + let heightAspito: Float + if self == .rotation90 || self == .rotation270 { + widthAspito = Float(videoSize.height / viewSize.width) + heightAspito = Float(videoSize.width / viewSize.height) + } else { + widthAspito = Float(videoSize.width / viewSize.width) + heightAspito = Float(videoSize.height / viewSize.height) + } + + let x: Float + let y: Float + if widthAspito < heightAspito { + x = 1 + y = heightAspito / widthAspito + } else { + x = widthAspito / heightAspito + y = 1 + } + + let A = simd_float4(x, -y, 0.0, 1.0) + let B = simd_float4(-x, -y, 0.0, 1.0) + let C = simd_float4(x, y, 0.0, 1.0) + let D = simd_float4(-x, y, 0.0, 1.0) + + switch self { + case .rotationNone: + if mirror { + return [A, B, C, D] + } else { + return [B, A, D, C] + } + case .rotation90: + if mirror { + return [C, A, D, B] + } else { + return [D, B, C, A] + } + case .rotation180: + if mirror { + return [D, C, B, A] + } else { + return [C, D, A, B] + } + case .rotation270: + if mirror { + return [B, D, A, C] + } else { + return [A, C, B, D] + } + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraMetalShader.metal b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraMetalShader.metal new file mode 100644 index 000000000..f324b228f --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraMetalShader.metal @@ -0,0 +1,49 @@ +// +// AgoraMetalShader.metal +// Agora-Custom-Media-Device +// +// Created by GongYuhua on 2017/11/15. +// Copyright © 2017年 Agora. All rights reserved. +// + +#include + +using namespace metal; + +typedef struct { + float4 renderedCoordinate [[position]]; + float2 textureCoordinate; +} TextureMappingVertex; + +vertex TextureMappingVertex mapTexture(unsigned int vertex_id [[ vertex_id ]], + const device packed_float4* vertex_array [[ buffer(0) ]]) { + + float4x4 renderedCoordinates = float4x4(vertex_array[0], vertex_array[1], vertex_array[2], vertex_array[3]); + float4x2 textureCoordinates = float4x2(float2( 0.0, 1.0 ), + float2( 1.0, 1.0 ), + float2( 0.0, 0.0 ), + float2( 1.0, 0.0 )); + + TextureMappingVertex outVertex; + outVertex.renderedCoordinate = renderedCoordinates[vertex_id]; + outVertex.textureCoordinate = textureCoordinates[vertex_id]; + + return outVertex; +} + +fragment float4 displayNV12Texture(TextureMappingVertex mappingVertex [[stage_in]], + texture2d textureY [[ texture(0) ]], + texture2d textureUV [[ texture(1) ]]) { + constexpr sampler colorSampler(mip_filter::linear, + mag_filter::linear, + min_filter::linear); + + const float4x4 ycbcrToRGBTransform = float4x4(float4(+1.0000f, +1.0000f, +1.0000f, +0.0000f), + float4(+0.0000f, -0.3441f, +1.7720f, +0.0000f), + float4(+1.4020f, -0.7141f, +0.0000f, +0.0000f), + float4(-0.7010f, +0.5291f, -0.8860f, +1.0000f)); + + float4 ycbcr = float4(textureY.sample(colorSampler, mappingVertex.textureCoordinate).r, + textureUV.sample(colorSampler, mappingVertex.textureCoordinate).rg, 1.0); + return ycbcrToRGBTransform * ycbcr; +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraPictureInPictureController.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraPictureInPictureController.h new file mode 100644 index 000000000..c8ca14124 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraPictureInPictureController.h @@ -0,0 +1,35 @@ +// +// AgoraPictureInPictureController.h +// APIExample +// +// Created by 胡润辰 on 2022/4/1. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +#import +#import "AgoraSampleBufferRender.h" +#import + +NS_ASSUME_NONNULL_BEGIN +@protocol AgoraPictureInPictureControllerDelegate + +@optional + +@end + +//仅支持IOS15以后 +@interface AgoraPictureInPictureController : NSObject + +@property (nonatomic, weak) id delegate; + +@property (nonatomic, strong, readonly) AVPictureInPictureController *pipController; + +@property (nonatomic, strong, readonly) AgoraSampleBufferRender *displayView; + +- (instancetype)initWithDisplayView:(AgoraSampleBufferRender *)displayView; + +- (void)releasePIP; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraPictureInPictureController.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraPictureInPictureController.m new file mode 100644 index 000000000..0958ba80c --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraPictureInPictureController.m @@ -0,0 +1,62 @@ +// +// AgoraPictureInPictureController.m +// APIExample +// +// Created by 胡润辰 on 2022/4/1. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +#import "AgoraPictureInPictureController.h" + +@interface AgoraPictureInPictureController () + +@end + +@implementation AgoraPictureInPictureController + +- (instancetype)initWithDisplayView:(AgoraSampleBufferRender *)displayView { + if (@available(iOS 15.0, *)) { + if ([AVPictureInPictureController isPictureInPictureSupported]) { + self = [super init]; + if (self) { + _displayView = displayView; + AVPictureInPictureControllerContentSource *pipControllerContentSource = [[AVPictureInPictureControllerContentSource alloc] initWithSampleBufferDisplayLayer:_displayView.displayLayer playbackDelegate:self]; + + _pipController = [[AVPictureInPictureController alloc] initWithContentSource:pipControllerContentSource]; + } + return self; + } + } + return nil; +} + +- (void)releasePIP { + _pipController.delegate = nil; + _pipController = nil; + [_displayView reset]; + _displayView = nil; +} + +#pragma mark - + +- (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController didTransitionToRenderSize:(CMVideoDimensions)newRenderSize { + +} + +- (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController setPlaying:(BOOL)playing { + +} + +- (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController skipByInterval:(CMTime)skipInterval completionHandler:(nonnull void (^)(void))completionHandler { + +} + +- (BOOL)pictureInPictureControllerIsPlaybackPaused:(nonnull AVPictureInPictureController *)pictureInPictureController { + return NO; +} + +- (CMTimeRange)pictureInPictureControllerTimeRangeForPlayback:(nonnull AVPictureInPictureController *)pictureInPictureController { + return CMTimeRangeMake(kCMTimeZero, CMTimeMake(INT64_MAX, 1000)); +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraSampleBufferRender.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraSampleBufferRender.h new file mode 100644 index 000000000..99fab0205 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraSampleBufferRender.h @@ -0,0 +1,29 @@ +// +// AgoraSampleBufferRender.h +// APIExample +// +// Created by 胡润辰 on 2022/4/2. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface AgoraSampleBufferRender : UIView + +@property (nonatomic, readonly) AVSampleBufferDisplayLayer *displayLayer; + +- (void)reset; + +- (void)renderVideoData:(AgoraOutputVideoFrame *_Nonnull)videoData; + +- (void)renderVideoPixelBuffer:(AgoraOutputVideoFrame *_Nonnull)videoData; + +- (void)renderVideoSampleBuffer:(CMSampleBufferRef)sampleBufferRef size:(CGSize)size; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraSampleBufferRender.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraSampleBufferRender.m new file mode 100644 index 000000000..8ab72834b --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraSampleBufferRender.m @@ -0,0 +1,259 @@ +// +// AgoraSampleBufferRender.m +// APIExample +// +// Created by 胡润辰 on 2022/4/2. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +#import "AgoraSampleBufferRender.h" + +@interface AgoraSampleBufferRender () { + NSInteger _videoWidth, _videoHeight; +} + +@property (nonatomic, strong) AVSampleBufferDisplayLayer *displayLayer; + +@end + +@implementation AgoraSampleBufferRender + +- (AVSampleBufferDisplayLayer *)displayLayer { + if (!_displayLayer) { + _displayLayer = [AVSampleBufferDisplayLayer new]; + } + + return _displayLayer; +} + +- (instancetype)init { + if (self = [super init]) { + [self.layer addSublayer:self.displayLayer]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self.layer addSublayer:self.displayLayer]; + } + return self; +} + +- (void)awakeFromNib { + [super awakeFromNib]; + [self.layer addSublayer:self.displayLayer]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + self.clipsToBounds = YES; + [self layoutDisplayLayer]; +} + +- (void)layoutDisplayLayer { + if (_videoWidth == 0 || _videoHeight == 0 || CGSizeEqualToSize(self.frame.size, CGSizeZero)) { + return; + } + + CGFloat viewWidth = self.frame.size.width; + CGFloat viewHeight = self.frame.size.height; + CGFloat videoRatio = (CGFloat)_videoWidth/(CGFloat)_videoHeight; + CGFloat viewRatio = viewWidth/viewHeight; + + CGSize videoSize; + if (videoRatio >= viewRatio) { + videoSize.height = viewHeight; + videoSize.width = videoSize.height * videoRatio; + }else { + videoSize.width = viewWidth; + videoSize.height = videoSize.width / videoRatio; + } + + CGRect renderRect = CGRectMake(0.5 * (viewWidth - videoSize.width), 0.5 * (viewHeight - videoSize.height), videoSize.width, videoSize.height); + + if (!CGRectEqualToRect(renderRect, self.displayLayer.frame)) { + self.displayLayer.frame = renderRect; + } +} + +- (void)reset { + [self.displayLayer flushAndRemoveImage]; +} + +- (OSType)getFormatType: (NSInteger)type { + switch (type) { + case 1: + return kCVPixelFormatType_420YpCbCr8Planar; + + case 2: + return kCVPixelFormatType_32BGRA; + + default: + return kCVPixelFormatType_32BGRA; + } +} + +- (void)renderVideoData:(AgoraOutputVideoFrame *_Nonnull)videoData { + if (!videoData) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + self->_videoWidth = videoData.width; + self->_videoHeight = videoData.height; + + [self layoutDisplayLayer]; + }); + + size_t width = videoData.width; + size_t height = videoData.height; + size_t yStride = videoData.yStride; + size_t uStride = videoData.uStride; + size_t vStride = videoData.vStride; + + void* yBuffer = videoData.yBuffer; + void* uBuffer = videoData.uBuffer; + void* vBuffer = videoData.vBuffer; + + @autoreleasepool { + CVPixelBufferRef pixelBuffer = NULL; + NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}}; + OSType type = [self getFormatType:videoData.type]; + CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault, + width, + height, + type, + (__bridge CFDictionaryRef)(pixelAttributes), + &pixelBuffer); + + if (result != kCVReturnSuccess) { + NSLog(@"Unable to create cvpixelbuffer %d", result); + } + + CVPixelBufferLockBaseAddress(pixelBuffer, 0); + + void *yPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); + int pixelBufferYBytes = (int)CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + + if (yStride == pixelBufferYBytes) { + memcpy(yPlane, yBuffer, yStride*height); + }else { + for (int i = 0; i < height; ++i) { + memcpy(yPlane + pixelBufferYBytes * i, yBuffer + yStride * i, MIN(yStride, pixelBufferYBytes)); + } + } + + void *uPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1); + int pixelBufferUBytes = (int)CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1); + if (uStride == pixelBufferUBytes) { + memcpy(uPlane, uBuffer, uStride*height/2); + }else { + for (int i = 0; i < height/2; ++i) { + memcpy(uPlane + pixelBufferUBytes * i, uBuffer + uStride * i, MIN(uStride, pixelBufferUBytes)); + } + } + + void *vPlane = (void *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2); + int pixelBufferVBytes = (int)CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 2); + if (vStride == pixelBufferVBytes) { + memcpy(vPlane, vBuffer, vStride*height/2); + }else { + for (int i = 0; i < height/2; ++i) { + memcpy(vPlane + pixelBufferVBytes * i, vBuffer + vStride * i, MIN(vStride, pixelBufferVBytes)); + } + } + + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + + CMVideoFormatDescriptionRef videoInfo; + CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer, &videoInfo); + + CMSampleTimingInfo timingInfo; + timingInfo.duration = kCMTimeZero; + timingInfo.decodeTimeStamp = kCMTimeInvalid; + timingInfo.presentationTimeStamp = CMTimeMake(CACurrentMediaTime()*1000, 1000); + + CMSampleBufferRef sampleBuffer; + CMSampleBufferCreateReadyWithImageBuffer(kCFAllocatorDefault, pixelBuffer, videoInfo, &timingInfo, &sampleBuffer); + + [self.displayLayer enqueueSampleBuffer:sampleBuffer]; + if (self.displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) { + [self.displayLayer flush]; + } + CMSampleBufferInvalidate(sampleBuffer); + CFRelease(sampleBuffer); + + CVPixelBufferRelease(pixelBuffer); + } +} + +- (void)renderVideoSampleBuffer:(CMSampleBufferRef)sampleBufferRef size:(CGSize)size { + if (!sampleBufferRef) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + self->_videoWidth = size.width; + self->_videoHeight = size.height; + + [self layoutDisplayLayer]; + }); + @autoreleasepool { + CMSampleTimingInfo timingInfo; + timingInfo.duration = kCMTimeZero; + timingInfo.decodeTimeStamp = kCMTimeInvalid; + timingInfo.presentationTimeStamp = CMTimeMake(CACurrentMediaTime()*1000, 1000); + + if (sampleBufferRef) { + [self.displayLayer enqueueSampleBuffer:sampleBufferRef]; + [self.displayLayer setNeedsDisplay]; + [_displayLayer display]; + [self.layer display]; + } + } +} + +- (void)renderVideoPixelBuffer:(AgoraOutputVideoFrame *_Nonnull)videoData { + if (!videoData) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + self->_videoWidth = videoData.width; + self->_videoHeight = videoData.height; + + [self layoutDisplayLayer]; + }); + + @autoreleasepool { + CVPixelBufferRef pixelBuffer = videoData.pixelBuffer; + + CMVideoFormatDescriptionRef videoInfo; + CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, + pixelBuffer, + &videoInfo); + + CMSampleTimingInfo timingInfo; + timingInfo.duration = kCMTimeZero; + timingInfo.decodeTimeStamp = kCMTimeInvalid; + timingInfo.presentationTimeStamp = CMTimeMake(CACurrentMediaTime()*1000, 1000); + + CMSampleBufferRef sampleBuffer; + CMSampleBufferCreateReadyWithImageBuffer(kCFAllocatorDefault, + pixelBuffer, + videoInfo, + &timingInfo, + &sampleBuffer); + + [self.displayLayer enqueueSampleBuffer:sampleBuffer]; + if (self.displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) { + [self.displayLayer flush]; + } + CMSampleBufferInvalidate(sampleBuffer); + CFRelease(sampleBuffer); + } +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraScreenShareSourcePush.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraScreenShareSourcePush.h new file mode 100644 index 000000000..8c739ce6a --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraScreenShareSourcePush.h @@ -0,0 +1,28 @@ +// +// AgoraScreenShare.h +// AgoraShareSrceen +// +// Created by XC on 2021/7/3. +// +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN +@class AgoraScreenShareSourcePush; +@protocol AgoraScreenShareSourcePushDelegate + +- (void)screenSourceCapture:(AgoraScreenShareSourcePush *)capture outputBuffer:(CVPixelBufferRef)pixelBuffer rotation:(int)rotation time:(CMTime)time; +- (void)pushAudioAppFrame:(unsigned char *)inAudioFrame frameSize:(int64_t)frameSize; +//- (void)pushAudioAppFrame:(CMSampleBufferRef)inAudioFrame; +//- (void)pushAudioMicFrame:(unsigned char *)inAudioFrame frameSize:(int64_t)frameSize; +- (void)screenShareStop; +@end + +@interface AgoraScreenShareSourcePush : NSObject +- (instancetype)initWithDelegate:(id)delegate port:(uint16_t) port; +- (void)startCapture; +- (void)stopCapture; +- (void)localSnapshot:(void (^ _Nullable)(UIImage * _Nonnull image))completion; +@end +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraScreenShareSourcePush.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraScreenShareSourcePush.m new file mode 100644 index 000000000..5e6d670b7 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraScreenShareSourcePush.m @@ -0,0 +1,394 @@ +//// +//// AgoraScreenShareSourcePush.m +//// AgoraShareSrceen +//// +//// Created by XC on 2021/7/3. +//// +// +//#import "AgoraScreenShareSourcePush.h" +//#import "GCDAsyncSocket.h" +//#import +//#import "TransferFrame.h" +//#include "CircularBuffer.h" +//#import +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#import +// +//#define SOCKET_TIMEOUT (60 * 10) +// +//typedef void (^imageBlock)(UIImage *image); +// +//@interface AgoraScreenShareSourcePush() +//{ +// CircularBuffer recvVideoBuffer; +// CircularBuffer recvAudioBuffer; +//} +// +//@property (nonatomic,weak) id delegate; +//@property (strong, nonatomic) GCDAsyncSocket *serverSocket; +//@property (strong, nonatomic) GCDAsyncSocket *videoSocket; +//@property (strong, nonatomic) GCDAsyncSocket *audioSocket; +// +//@property (nonatomic, assign) BOOL getOneDidCaptureVideoFrame; +//@property (nonatomic, copy) imageBlock imageBlock; +//@property (nonatomic, assign) uint16_t port; +// +//@end +// +//@implementation AgoraScreenShareSourcePush +// +//+ (dispatch_queue_t)RECV_SERIAL_QUEUE { +// static dispatch_queue_t serialQueue = nil; +// static dispatch_once_t onceToken; +// dispatch_once(&onceToken, ^{ +// serialQueue = dispatch_queue_create("io.agora.recv.data", DISPATCH_QUEUE_SERIAL); +// }); +// return serialQueue; +//} +// +//- (void)dealloc { +// if (recvVideoBuffer != NULL) { +// CircularBufferFree(recvVideoBuffer); +// } +//} +// +//- (instancetype)initWithDelegate:(id)delegate port:(uint16_t) port +//{ +// self = [super init]; +// if (self) { +// self.delegate = delegate; +// self.port = port; +// recvVideoBuffer = CircularBufferCreate(30 * 1024 * 1024); +// recvAudioBuffer = CircularBufferCreate(5 * 1024 * 1024); +// } +// return self; +//} +// +//- (void)startCapture { +// if (self.serverSocket != nil) { +// return; +// } +// self.serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:[[self class] RECV_SERIAL_QUEUE]]; +// self.serverSocket.autoDisconnectOnClosedReadStream = YES; +// __autoreleasing NSError *error = nil; +// BOOL result = [self.serverSocket acceptOnPort:self.port error:&error]; +// if(error || !result){ +// NSLog(@"server socket result:%@ error:%@", error, @(result)); +// }else { +// NSLog(@"server socket:%@ listen %d", self.serverSocket, self.port); +// } +//} +// +//- (void)stopCapture { +// if (self.serverSocket != nil) { +// [self.serverSocket disconnect]; +// } +// self.serverSocket = nil; +// self.videoSocket = nil; +// self.audioSocket = nil; +//} +// +//int findMagic(char *buffer, int len) +//{ +// int i = 0; +// if(buffer == NULL || len < 4) +// return -1; +// while(i <= len - 4) { +// if(*(int32_t *)(buffer+i) == MAGIC_NUMBER) +// return i; +// } +// +// return -1; +//} +// +////- (CMSampleBufferRef)bufferConvertAudioBuffer:(void *)buffer frameSize:(int64_t)frameSize { +//// AVAudioChannelLayout *chLayout = [[AVAudioChannelLayout alloc] initWithLayoutTag:kAudioChannelLayoutTag_Stereo]; +//// AVAudioFormat *pcmBuffer = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 +//// sampleRate:48000 +//// interleaved:NO +//// channelLayout:chLayout]; +//// +//// // 创建一个基于上述配置的帧缓存结构 +//// AVAudioPCMBuffer *thePCMBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:pcmBuffer frameCapacity:1024]; +//// thePCMBuffer.frameLength = thePCMBuffer.frameCapacity; +//// +//// // 初始化数据区 +//// for (AVAudioChannelCount ch = 0; ch < pcmBuffer.channelCount; ++ch) { +//// memset(thePCMBuffer.floatChannelData[ch], 0, thePCMBuffer.frameLength * pcmBuffer.streamDescription->mBytesPerFrame); +//// } +//// +//// memcpy(thePCMBuffer.floatChannelData[0], buffer, frameSize); +//// +//// AudioStreamBasicDescription asbd = *thePCMBuffer.format.streamDescription; +//// CMSampleBufferRef sampleBuffer = NULL; +//// CMAudioFormatDescriptionRef format = NULL; +//// +//// OSStatus error = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &asbd, 0, NULL, 0, NULL, NULL, &format); +//// if (error != noErr) { +//// return nil; +//// } +//// +//// //CMTime PTS = CMTimeMake([AVAudioTime secondsForHostTime:ATS.hostTime] * ATS.sampleRate, ATS.sampleRate); +//// CMTime PTS = CMTimeMake(CACurrentMediaTime()*1000, 1000); +//// CMItemCount count = thePCMBuffer.audioBufferList->mBuffers[1].mDataByteSize / asbd.mBytesPerFrame; +//// +//// error = CMAudioSampleBufferCreateReadyWithPacketDescriptions(kCFAllocatorDefault, +//// NULL, +//// format, +//// count, +//// PTS, +//// NULL, +//// &sampleBuffer); +//// +//// if (error != noErr) { +//// CFRelease(format); +//// NSLog(@"CMAudioSampleBufferCreateReadyWithPacketDescriptions returned error: %d", (int)error); +//// return nil; +//// } +//// +//// error = CMSampleBufferSetDataBufferFromAudioBufferList(sampleBuffer, kCFAllocatorDefault, kCFAllocatorDefault, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, thePCMBuffer.audioBufferList); +//// +//// if (error != noErr) { +//// CFRelease(format); +//// NSLog(@"CMSampleBufferSetDataBufferFromAudioBufferList returned error: %d", (int)error); +//// return nil; +//// } +//// +//// CFRelease(format); +//// return sampleBuffer; +////} +// +//- (CVPixelBufferRef)bufferConvertPixelBuffer:(void *)buffer width:(size_t)bufferWidth height:(size_t)bufferHeight +//{ +// // Copy the pixel buffer +// CVPixelBufferRef pixelBufferCopy = NULL; +// CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, +// bufferWidth, +// bufferHeight, +// kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, +// NULL, +// &pixelBufferCopy); +// if (status != kCVReturnSuccess) { +// NSLog(@"bufferConvertPixelBuffer failed !!!"); +// } +// +// CVPixelBufferLockBaseAddress(pixelBufferCopy, 0); +// +// uint8_t *yDestPlane = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(pixelBufferCopy, 0); +// memcpy(yDestPlane, buffer, bufferWidth * bufferHeight); +// uint8_t *uvDestPlane = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(pixelBufferCopy, 1); +// memcpy(uvDestPlane, (unsigned char *)buffer + bufferWidth * bufferHeight, bufferWidth * bufferHeight/2); +// +// CVPixelBufferUnlockBaseAddress(pixelBufferCopy, 0); +// +// return pixelBufferCopy; +//} +// +//- (void)handleRecvVideoData { +// size_t frameSize = sizeof(TransferFrame); +// size_t recvLength = CircularBufferGetDataSize(recvVideoBuffer); +// if (recvLength < frameSize) { +// //NSLog(@"handleRecvVideoData return"); +// CircularBufferReset(recvVideoBuffer); +// return; +// } +// +// TransferFrame frame = {0}; +// CircularBufferRead(recvVideoBuffer, frameSize, &frame); +// +// if (frame.magic == MAGIC_NUMBER && frame.length <= recvLength ) { +// CircularBufferPop(recvVideoBuffer, frameSize, NULL); +// void *buffer = malloc(frame.length); +// CircularBufferPop(recvVideoBuffer, frame.length, buffer); +// +// if (frame.frameType == 1) { +// CVPixelBufferRef pixelBuffer = [self bufferConvertPixelBuffer:buffer +// width:frame.width +// height:frame.height]; +// CMTime time = CMTimeMake(frame.timevalues, (int32_t)frame.timescale); +// int rotation = (int)frame.rotation; +// switch (rotation) { +// case 2: +// rotation = 180; +// break; +// case 1: +// rotation = 90; +// break; +// case 3: +// rotation = 270; +// break; +// default: +// break; +// } +// +// //CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); +// if ([self.delegate respondsToSelector:@selector(screenSourceCapture:outputBuffer:rotation:time:)]) { +// [self.delegate screenSourceCapture:self outputBuffer:pixelBuffer rotation:rotation time:time]; +// } +// //CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); +// // screenshot +// if (self.getOneDidCaptureVideoFrame) { +// self.getOneDidCaptureVideoFrame = false; +// [self CVBufferRefToImage:pixelBuffer]; +// } +// CVPixelBufferRelease(pixelBuffer); +// } +// +// free(buffer); +// } +//} +// +//- (void)CVBufferRefToImage:(CVBufferRef)imageBuffer { +// if (self.imageBlock) { +// CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer]; +// +// CIContext *temporaryContext = [CIContext contextWithOptions:nil]; +// CGImageRef videoImage = [temporaryContext +// createCGImage:ciImage +// fromRect:CGRectMake(0, 0, +// CVPixelBufferGetWidth(imageBuffer), +// CVPixelBufferGetHeight(imageBuffer))]; +// UIImage *uiImage = [UIImage imageWithCGImage:videoImage]; +// CGImageRelease(videoImage); +// self.imageBlock(uiImage); +// } +//} +// +//- (void)handleRecvAudioData { +// size_t frameSize = sizeof(TransferFrame); +// size_t recvLength = CircularBufferGetDataSize(recvAudioBuffer); +// if (recvLength < frameSize) { +// CircularBufferReset(recvAudioBuffer); +// return; +// } +// +// TransferFrame frame = {0}; +// CircularBufferRead(recvAudioBuffer, frameSize, &frame); +// +// if (frame.magic == MAGIC_NUMBER && frame.length <= recvLength ) { +// +// CircularBufferPop(recvAudioBuffer, frameSize, NULL); +// +//// NSLog(@"handle recv frame size:%@ length:%@ w:%@,h:%@ rotation:%@ frametype:%@",@(frameSize), +//// @(frame.length), +//// @(frame.width), +//// @(frame.height), +//// @(frame.rotation), +//// @(frame.frameType)); +// +// void *buffer = malloc(frame.length); +// CircularBufferPop(recvAudioBuffer, frame.length, buffer); +// +// if (frame.frameType == 2) { +// if ([self.delegate respondsToSelector:@selector(pushAudioAppFrame:frameSize:)]) { +// [self.delegate pushAudioAppFrame:buffer frameSize:frame.length]; +// } +//// if ([self.delegate respondsToSelector:@selector(pushAudioAppFrame:)]) { +//// CMSampleBufferRef audoFrame = [self bufferConvertAudioBuffer:buffer frameSize:frame.length]; +//// if (audoFrame != nil) { +//// [self.delegate pushAudioAppFrame:audoFrame]; +//// } +//// } +// } else if (frame.frameType == 3) { +// //if ([self.delegate respondsToSelector:@selector(pushAudioMicFrame:frameSize:)]) { +// //[self.delegate pushAudioMicFrame:buffer frameSize:frame.length]; +// //} +// } +// +// free(buffer); +// } +// +//} +// +// +// +///** +// 读取客户端发送的数据 +// +// @param sock 客户端的Socket +// @param data 客户端发送的数据 +// @param tag 当前读取的标记 +// */ +//- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag +//{ +// if (sock == self.videoSocket) { +// CircularBufferPush(recvVideoBuffer, (void *)data.bytes, data.length); +// [self handleRecvVideoData]; +// } +// +// if (sock == self.audioSocket) { +// CircularBufferPush(recvAudioBuffer, (void *)data.bytes, data.length); +// [self handleRecvAudioData]; +// } +// +// [sock readDataWithTimeout:SOCKET_TIMEOUT tag:0]; +// +//} +// +///** +// * Conditionally called if the read stream closes, but the write stream may still be writeable. +// * +// * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO. +// * See the discussion on the autoDisconnectOnClosedReadStream method for more information. +//**/ +//- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock { +// +// if (sock == self.videoSocket) { +// CircularBufferReset(recvVideoBuffer); +// } +// if (sock == self.audioSocket) { +// CircularBufferReset(recvAudioBuffer); +// } +//} +// +//- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err { +// NSLog(@"server -- socketDidDisconnect error:%@", err); +// if(self.videoSocket.isDisconnected) { +// CircularBufferReset(recvVideoBuffer); +// NSLog(@"server videoSocket socketDidDisconnect error:%@", err); +// self.videoSocket = nil; +// } +// if (self.audioSocket.isDisconnected) { +// CircularBufferReset(recvAudioBuffer); +// NSLog(@"server audioSocket socketDidDisconnect error:%@", err); +// self.audioSocket = nil; +// } +// +// if (self.videoSocket == nil && self.audioSocket == nil) { +// if ([self.delegate respondsToSelector:@selector(screenShareStop)]) { +// [self.delegate screenShareStop]; +// } +// } +//} +// +//- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket { +// +// if (nil == self.videoSocket) { +// self.videoSocket = newSocket; +// [self.videoSocket enableBackgroundingOnSocket]; +// }else if (nil == self.audioSocket) { +// self.audioSocket = newSocket; +// [self.audioSocket enableBackgroundingOnSocket]; +// } +// +// [newSocket readDataWithTimeout:SOCKET_TIMEOUT tag:0]; +// +// NSLog(@"connectedPort:%@, localPort:%@, connectedAddress:%@, localAddress:%@", @(newSocket.connectedPort), +// @(newSocket.localPort), +// newSocket.connectedAddress, +// newSocket.localAddress); +//} +// +//- (void)localSnapshot:(void (^ _Nullable)(UIImage * _Nonnull image))completion { +// self.imageBlock = completion; +// self.getOneDidCaptureVideoFrame = true; +//} +// +// +//@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraYUVImageSourcePush.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraYUVImageSourcePush.h new file mode 100644 index 000000000..58168a13b --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraYUVImageSourcePush.h @@ -0,0 +1,33 @@ +// +// AgoraYUVImageSourcePush.h +// APIExample +// +// Created by 张乾泽 on 2020/11/6. +// Copyright © 2020 Agora Corp. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol AgoraYUVImageSourcePushDelegate + +-(void)onVideoFrame:(CVPixelBufferRef)buffer + size:(CGSize)size + trackId: (NSUInteger)trackId + rotation:(int)rotation; + +@end + +@interface AgoraYUVImageSourcePush : NSObject +- (instancetype)initWithSize: (CGSize)size fileName: (NSString *)fileName frameRate: (int)frameRate; +@property(nonatomic, assign)UInt32 trackId; +@property(nonatomic, weak)id delegate; + +-(void)startSource; +-(void)stopSource; +@end + + +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraYUVImageSourcePush.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraYUVImageSourcePush.m new file mode 100644 index 000000000..926d5f9e6 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/AgoraYUVImageSourcePush.m @@ -0,0 +1,114 @@ +// +// AgoraYUVImageSourcePush.m +// APIExample +// +// Created by 张乾泽 on 2020/11/6. +// Copyright © 2020 Agora Corp. All rights reserved. +// + +#import "AgoraYUVImageSourcePush.h" +#import +#import "MediaUtils.h" + +@interface AgoraYUVImageSourcePush () +@property(nonatomic, strong) NSData* yuvData; +@property (nonatomic,strong)dispatch_source_t timer; +@property(nonatomic, assign) int videoW; +@property(nonatomic, assign) int videoH; +@property(nonatomic, strong)NSFileHandle *fileHandle; +@property(nonatomic, assign) int frameRate; +@property(nonatomic, copy) NSString *fileName; +@end + +@implementation AgoraYUVImageSourcePush + +- (instancetype)initWithSize: (CGSize)size fileName: (NSString *)fileName frameRate: (int)frameRate { + if(self = [super init]) { + self.fileName = fileName; + self.videoW = size.width; + self.videoH = size.height; + self.frameRate = frameRate; + [self loadData]; + } + return self; +} + +- (void)loadData { + NSString *yuvPath = [[NSBundle mainBundle] pathForResource:self.fileName ofType:@"yuv"]; + self.fileHandle = [NSFileHandle fileHandleForReadingAtPath:yuvPath]; +} + +- (void) initTimer { + self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0)); + /** + 定时器设置 + @param 定时器 + @param 什么时候开始 + @param 定时器延迟多久 + @param 每隔几秒执行 + @param 允许多少误差 + */ + //GCD要求传入纳秒,所以要用秒乘以NSEC_PER_SEC + dispatch_source_set_timer( + self.timer, + dispatch_time(DISPATCH_TIME_NOW, 0.0 * NSEC_PER_SEC),//开始事件,从 0 秒后开始 + self.frameRate / 100.0 * NSEC_PER_SEC,//间隔 秒 + 0 + ); +} + +-(void)startSource +{ + if(self.timer == nil) { + [self initTimer]; + } + NSUInteger frameSizeY = self.videoW*self.videoH; + NSUInteger frameSizeU = self.videoW*self.videoH/4; + NSUInteger frameSizeV = self.videoW*self.videoH/4; + + __block NSUInteger i = 0; + NSTimeInterval sT = NSDate.date.timeIntervalSince1970; + + __weak AgoraYUVImageSourcePush * weakSelf = self; + dispatch_source_set_event_handler(self.timer, ^{ + if(weakSelf.delegate) { + NSData *dataY = [weakSelf.fileHandle readDataOfLength:frameSizeY]; + NSData *dataU = [weakSelf.fileHandle readDataOfLength:frameSizeU]; + NSData *dataV = [weakSelf.fileHandle readDataOfLength:frameSizeV]; + + if (dataY.length==0 || dataV.length==0 || dataU.length==0) { + i = 0; + [weakSelf loadData]; + dataY = [weakSelf.fileHandle readDataOfLength:frameSizeY]; + dataU = [weakSelf.fileHandle readDataOfLength:frameSizeU]; + dataV = [weakSelf.fileHandle readDataOfLength:frameSizeV]; + } + CVPixelBufferRef pixelBuffer = [MediaUtils i420ToPixelBuffer:(void *)dataY.bytes + srcU:(void *)dataU.bytes + srcV:(void *)dataV.bytes + width:weakSelf.videoW + height:weakSelf.videoH]; + [weakSelf.delegate onVideoFrame:pixelBuffer size:CGSizeMake(weakSelf.videoW, weakSelf.videoH) trackId: self.trackId rotation:0]; + CVPixelBufferRelease(pixelBuffer); + NSTimeInterval cT = NSDate.date.timeIntervalSince1970; + NSTimeInterval dT = cT-sT; + NSTimeInterval tT = i/25.0; + if (dT + +struct s_circularBuffer{ + + size_t size; //capacity bytes size + size_t dataSize; //occupied data size + size_t tailOffset; //head offset, the oldest byte position offset + size_t headOffset; //tail offset, the lastest byte position offset + void *buffer; + +}; + +extern CircularBuffer CircularBufferCreate(size_t size) +{ + size_t totalSize = sizeof(struct s_circularBuffer) + size; + void *p = malloc(totalSize); + CircularBuffer buffer = (CircularBuffer)p; + buffer->buffer = p + sizeof(struct s_circularBuffer); + buffer->size = size; + CircularBufferReset(buffer); + return buffer; +} + +void CircularBufferFree(CircularBuffer cBuf) +{ + CircularBufferReset(cBuf); + cBuf->size = 0; + cBuf->dataSize = 0; + cBuf->buffer = NULL; + free(cBuf); +} + +void CircularBufferReset(CircularBuffer cBuf) +{ + cBuf->headOffset = -1; + cBuf->tailOffset = -1; + cBuf->dataSize = 0; +} + +size_t CircularBufferGetCapacity(CircularBuffer cBuf) { + + return cBuf->size; +} + +size_t CircularBufferGetSize(CircularBuffer cBuf) +{ + return cBuf->size; +} + +size_t CircularBufferGetDataSize(CircularBuffer cBuf) +{ + return cBuf->dataSize; +} + +void CircularBufferPush(CircularBuffer cBuf,void *src, size_t length) +{ + if(length == 0) + return; + + size_t writableLen = length; + void *pSrc = src; + + if(writableLen > cBuf->size)//in case of size overflow + { + size_t overFlowLen = writableLen - cBuf->size; + writableLen = cBuf->size; + pSrc = src + overFlowLen; + } + + + bool resetHead = false; + //in case the circle buffer won't be full after adding the data + if(cBuf->tailOffset+writableLen < cBuf->size) + { + memcpy(&cBuf->buffer[cBuf->tailOffset + 1], pSrc, writableLen); + + if((cBuf->tailOffset < cBuf->headOffset) && (cBuf->tailOffset+writableLen >= cBuf->headOffset) ) + resetHead = true; + + cBuf->tailOffset += writableLen; + } + else//in case the circle buffer will be overflow after adding the data + { + size_t remainSize = cBuf->size - cBuf->tailOffset - 1; //the remain size + memcpy(&cBuf->buffer[cBuf->tailOffset+1], pSrc, remainSize); + + size_t coverSize = writableLen - remainSize; //size of data to be covered from the beginning + memcpy(cBuf->buffer, pSrc+remainSize, coverSize); + + if(cBuf->tailOffset < cBuf->headOffset) + resetHead = true; + else + { + if(coverSize>cBuf->headOffset) + resetHead = true; + } + + cBuf->tailOffset = coverSize - 1; + } + + if(cBuf->headOffset == -1) + cBuf->headOffset = 0; + + if(resetHead) + { + if(cBuf->tailOffset+1 < cBuf->size) + cBuf->headOffset = cBuf->tailOffset + 1; + else + cBuf->headOffset = 0; + + cBuf->dataSize = cBuf->size; + } + else + { + if(cBuf->tailOffset >= cBuf->headOffset) + cBuf->dataSize = cBuf->tailOffset - cBuf->headOffset + 1; + else + cBuf->dataSize = cBuf->size - (cBuf->headOffset - cBuf->tailOffset - 1); + } +} + +size_t inter_circularBuffer_read(CircularBuffer cBuf, size_t length, void *dataOut, bool resetHead) +{ + if(cBuf->dataSize == 0 || length == 0) + return 0; + + size_t rdLen = length; + + if(cBuf->dataSize < rdLen) + rdLen = cBuf->dataSize; + + + if(cBuf->headOffset <= cBuf->tailOffset) + { + if(dataOut) + memcpy(dataOut, &cBuf->buffer[cBuf->headOffset], rdLen); + + if(resetHead) + { + cBuf->headOffset += rdLen; + if(cBuf->headOffset > cBuf->tailOffset) + { + cBuf->headOffset = -1; + cBuf->tailOffset = -1; + } + } + } + else + { + if(cBuf->headOffset+rdLen <= cBuf->size) + { + if(dataOut) + memcpy(dataOut, &cBuf->buffer[cBuf->headOffset], rdLen); + + if(resetHead) + { + cBuf->headOffset += rdLen; + if(cBuf->headOffset == cBuf->size) + cBuf->headOffset = 0; + } + } + else + { + size_t frg1Len = cBuf->size - cBuf->headOffset; + if(dataOut) + memcpy(dataOut, &cBuf->buffer[cBuf->headOffset], frg1Len); + + size_t frg2len = rdLen - frg1Len; + if(dataOut) + memcpy(dataOut+frg1Len, cBuf->buffer, frg2len); + + if(resetHead) + { + cBuf->headOffset = frg2len; + if(cBuf->headOffset > cBuf->tailOffset) + { + cBuf->headOffset = -1; + cBuf->tailOffset = -1; + } + } + } + } + + if(resetHead) + cBuf->dataSize -= rdLen; + + return rdLen; +} + + +size_t CircularBufferPop(CircularBuffer cBuf, size_t length, void *dataOut) +{ + return inter_circularBuffer_read(cBuf,length,dataOut,true); +} + +size_t CircularBufferRead(CircularBuffer cBuf, size_t length, void *dataOut) +{ + return inter_circularBuffer_read(cBuf,length,dataOut,false); +} + + +//print circular buffer's content into str, +void CircularBufferPrint(CircularBuffer cBuf, bool hex) +{ + char *b = cBuf->buffer; + size_t cSize = CircularBufferGetSize(cBuf); + char *str = malloc(2*cSize+1); + + char c; + + for(size_t i=0; itailOffset < cBuf->headOffset) + { + if(i>cBuf->tailOffset && iheadOffset) + c = '_'; + else + c = b[i]; + } + else + { + if(i>cBuf->tailOffset || iheadOffset) + c = '_'; + else + c = b[i]; + } + if(hex) + sprintf(str+i*2, "%02X|",c); + else + sprintf(str+i*2, "%c|",c); + } + + printf("CircularBuffer: %s \n",str,CircularBufferGetSize(cBuf),CircularBufferGetDataSize(cBuf)); + + free(str); +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/CircularBuffer.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/CircularBuffer.h new file mode 100644 index 000000000..a4bfb1f83 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/ExternalVideo/CircularBuffer.h @@ -0,0 +1,50 @@ +// +// CircularBuffer.h +// +// Created by 罗亮富(Roen)zxllf23@163.com on 14-1-14. +// Copyright (c) 2014年 All rights reserved. +// + +#ifndef YYDJ_Roen_CircularBuffer_h +#define YYDJ_Roen_CircularBuffer_h +#include +#include +#include + +/* + A circular buffer(circular queue, cyclic buffer or ring buffer), is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams. visit https://en.wikipedia.org/wiki/Circular_buffer to see more information. + */ + +typedef struct s_circularBuffer* CircularBuffer; + +// Construct CircularBuffer with ‘size' in byte. You must call CircularBufferFree() in balance for destruction. +extern CircularBuffer CircularBufferCreate(size_t size); + +// Destruct CircularBuffer +extern void CircularBufferFree(CircularBuffer cBuf); + +// Reset the CircularBuffer +extern void CircularBufferReset(CircularBuffer cBuf); + +//get the capacity of CircularBuffer +extern size_t CircularBufferGetCapacity(CircularBuffer cBuf); + +//same as CircularBufferGetCapacity, Just for compatibility with older versions +extern size_t CircularBufferGetSize(CircularBuffer cBuf); + +//get occupied data size of CircularBuffer +extern size_t CircularBufferGetDataSize(CircularBuffer cBuf); + +// Push data to the tail of a circular buffer from 'src' with 'length' size in byte. +extern void CircularBufferPush(CircularBuffer cBuf,void *src, size_t length); + +// Pop data from a circular buffer to 'dataOut' with wished 'length' size in byte,return the actual data size in byte popped out,which is less or equal to the input 'length parameter. +extern size_t CircularBufferPop(CircularBuffer cBuf, size_t length, void *dataOut); + +// Read data from a circular buffer to 'dataOut' with wished 'length' size in byte,return the actual data size in byte popped out,which is less or equal to the input 'length parameter. +extern size_t CircularBufferRead(CircularBuffer cBuf, size_t length, void *dataOut); + +//for test purpose, print the circular buffer's data content by printf(...); the 'hex' parameters indicates that if the data should be printed in asscii string or hex data format. +extern void CircularBufferPrint(CircularBuffer cBuf, bool hex); + +#endif diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/KeyCenter.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/KeyCenter.swift new file mode 100644 index 000000000..efc27baff --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/KeyCenter.swift @@ -0,0 +1,46 @@ +// +// KeyCenter.swift +// OpenLive +// +// Created by GongYuhua on 6/25/16. +// Copyright © 2016 Agora. All rights reserved. +// + +import Foundation + +@objc +class KeyCenter: NSObject { + + /** + Agora APP ID. + Agora assigns App IDs to app developers to identify projects and organizations. + If you have multiple completely separate apps in your organization, for example built by different teams, + you should use different App IDs. + If applications need to communicate with each other, they should use the same App ID. + In order to get the APP ID, you can open the agora console (https://console.agora.io/) to create a project, + then the APP ID can be found in the project detail page. + 声网APP ID + Agora 给应用程序开发人员分配 App ID,以识别项目和组织。如果组织中有多个完全分开的应用程序,例如由不同的团队构建, + 则应使用不同的 App ID。如果应用程序需要相互通信,则应使用同一个App ID。 + 进入声网控制台(https://console.agora.io/),创建一个项目,进入项目配置页,即可看到APP ID。 + */ + @objc + static let AppId: String = <#APPID#> + + /** + Certificate. + Agora provides App certificate to generate Token. You can deploy and generate a token on your server, + or use the console to generate a temporary token. + In order to get the APP ID, you can open the agora console (https://console.agora.io/) to create a project with the App Certificate enabled, + then the APP Certificate can be found in the project detail page. + PS: If the project does not have certificates enabled, leave this field blank. + 声网APP证书 + Agora 提供 App certificate 用以生成 Token。您可以在您的服务器部署并生成 Token,或者使用控制台生成临时的 Token。 + 进入声网控制台(https://console.agora.io/),创建一个带证书鉴权的项目,进入项目配置页,即可看到APP证书。 + 注意:如果项目没有开启证书鉴权,这个字段留空。 + */ + static let Certificate: String? = nil + + + static let FaceCaptureLicense: String? = nil +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/JSONObject.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/JSONObject.swift new file mode 100644 index 000000000..c65476705 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/JSONObject.swift @@ -0,0 +1,139 @@ +// +// JSONObject.swift +// BreakoutRoom +// +// Created by zhaoyongqiang on 2021/11/2. +// + +import Foundation + +class JSONObject { + /// 字典转模型 + static func toModel(_ type: T.Type, value: Any?) -> T? { + guard let value = value else { return nil } + return toModel(type, value: value) + } + /// 字典转模型 + static func toModel(_ type: T.Type, value: Any) -> T? { + guard let data = try? JSONSerialization.data(withJSONObject: value) else { return nil } + let decoder = JSONDecoder() + decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", + negativeInfinity: "-Infinity", + nan: "NaN") + return try? decoder.decode(type, from: data) + } + /// JSON字符串转模型 + static func toModel(_ type: T.Type, value: String?) -> T? { + guard let value = value else { return nil } + return toModel(type, value: value) + } + /// JSON字符串转模型 + static func toModel(_ type: T.Type, value: String) -> T? { + let decoder = JSONDecoder() + decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", + negativeInfinity: "-Infinity", + nan: "NaN") + guard let data = value.data(using: .utf8), + let t = try? decoder.decode(T.self, from: data) + else { + return nil + } + return t + } + /// 模型转JSON字符串 + static func toJson(_ model: T) -> [String: Any] { + let jsonString = toJsonString(model) ?? "" + return toDictionary(jsonString: jsonString) + } + /// 模型转JSON数组字符串 + static func toJsonArray(_ model: T) -> [[String: Any]]? { + let jsonString = toJsonString(model) ?? "" + return toArray(jsonString: jsonString) + } + /// 模型转JSON字符串 + static func toJsonString(_ model: T) -> String? { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + guard let data = try? encoder.encode(model) else { return nil } + return String(data: data, encoding: .utf8) + } + /// JSON字符串转字典 + static func toDictionary(jsonString: String) -> [String: Any] { + guard let jsonData = jsonString.data(using: .utf8) else { return [:] } + guard let dict = try? JSONSerialization.jsonObject(with: jsonData, + options: .mutableContainers), + let result = dict as? [String: Any] + else { + return [:] + } + return result + } + /// JSON字符串转字典 + static func toDictionary(jsonStr: String) -> [String: String] { + guard let jsonData = jsonStr.data(using: .utf8) else { return [:] } + guard let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers), + let result = dict as? [String: Any] + else { + return [:] + } + var data = [String: String]() + for item in result { + data[item.key] = "\(item.value)" + } + return data + } + /// JSON字符串转数组 + static func toArray(jsonString: String) -> [[String: Any]]? { + guard let jsonData = jsonString.data(using: .utf8) else { return nil } + guard let array = try? JSONSerialization.jsonObject(with: jsonData, + options: .mutableContainers), + let result = array as? [[String: Any]] + else { + return nil + } + return result + } + /// 字典转JSON字符串 + static func toJsonString(dict: [String: Any]?) -> String? { + guard let dict = dict else { return nil } + if !JSONSerialization.isValidJSONObject(dict) { + print("字符串格式错误!") + return nil + } + guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else { return nil } + guard let jsonString = String(data: data, encoding: .utf8) else { return nil } + return jsonString + } + /// 字典数组转JSON字符串 + static func toJsonString(array: [[String: Any]?]?) -> String? { + guard let array = array else { return nil } + var jsonString = "[" + var i = 0 + let count = array.count + for dict in array { + guard let dict = dict else { return nil } + if !JSONSerialization.isValidJSONObject(dict) { + print("字符串格式错误!") + return nil + } + guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else { return nil } + guard let tmp = String(data: data, encoding: .utf8) else { return nil } + jsonString.append(tmp) + if i < count - 1 { + jsonString.append(",") + } + i += 1 + } + jsonString.append("]") + return jsonString + } +} + +extension String { + func toArray() -> [[String: Any]]? { + JSONObject.toArray(jsonString: self) + } + func toDictionary() -> [String: String] { + JSONObject.toDictionary(jsonStr: self) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/NetworkManager.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/NetworkManager.swift new file mode 100644 index 000000000..14c2a52eb --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/NetworkManager.swift @@ -0,0 +1,194 @@ +// +// NetworkManager.swift +// Scene-Examples +// +// Created by zhaoyongqiang on 2021/11/19. +// + +import UIKit + +@objc +class NetworkManager: NSObject { + enum HTTPMethods: String { + case GET + case POST + } + + typealias SuccessClosure = ([String: Any]) -> Void + typealias FailClosure = (String) -> Void + + private lazy var sessionConfig: URLSessionConfiguration = { + let config = URLSessionConfiguration.default + config.httpAdditionalHeaders = ["Content-Type": "application/json", + "X-LC-Id": "fkUjxadPMmvYF3F3BI4uvmjo-gzGzoHsz", + "X-LC-Key": "QAvFS62IOR28GfSFQO5ze45s", + "X-LC-Session": "qmdj8pdidnmyzp0c7yqil91oc"] + config.timeoutIntervalForRequest = 30 + config.timeoutIntervalForResource = 30 + config.requestCachePolicy = .reloadIgnoringLocalCacheData + return config + }() + + @objc + static let shared = NetworkManager() + private override init() { } + private let baseUrl = "https://test-toolbox.bj2.agoralab.co/v1/token/generate" + + @objc + func generateToken(channelName: String, uid: UInt = 0, success: @escaping (String?) -> Void) { + if KeyCenter.Certificate == nil || KeyCenter.Certificate?.isEmpty == true { + success(nil) + return + } + let params = ["appCertificate": KeyCenter.Certificate ?? "", + "appId": KeyCenter.AppId, + "channelName": channelName, + "expire": 900, + "src": "iOS", + "ts": "".timeStamp, + "type": 1, + "uid": "\(uid)"] as [String: Any] + ToastView.showWait(text: "loading...", view: nil) + NetworkManager.shared.postRequest(urlString: "https://toolbox.bj2.agoralab.co/v1/token/generate", params: params, success: { response in + let data = response["data"] as? [String: String] + let token = data?["token"] + print(response) + success(token) + ToastView.hidden() + }, failure: { error in + print(error) + success(nil) + ToastView.hidden() + }) + } + + func getRequest(urlString: String, success: SuccessClosure?, failure: FailClosure?) { + DispatchQueue.global().async { + self.request(urlString: urlString, params: nil, method: .GET, success: success, failure: failure) + } + } + + func download(urlString: String, success: SuccessClosure?, failure: FailClosure?) { + let session = URLSession(configuration: sessionConfig) + let request = URLRequest(url: URL(string: urlString) ?? URL(fileURLWithPath: urlString)) + let fileName = urlString.components(separatedBy: "/").last ?? "" + let documnets = NSTemporaryDirectory() + fileName + if FileManager.default.fileExists(atPath: documnets) { + success?(["fileName": fileName, "path": documnets]) + return + } + DispatchQueue.global().async { + let downloadTask = session.downloadTask(with: request) { location, _, _ in + guard let location = location else { return } + let locationPath = location.path + let fileManager = FileManager.default + try? fileManager.moveItem(atPath: locationPath, toPath: documnets) + success?(["fileName": fileName, "path": documnets]) + } + downloadTask.resume() + } + } + + func postRequest(urlString: String, params: [String: Any]?, success: SuccessClosure?, failure: FailClosure?) { + DispatchQueue.global().async { + self.request(urlString: urlString, params: params, method: .POST, success: success, failure: failure) + } + } + + private func request(urlString: String, + params: [String: Any]?, + method: HTTPMethods, + success: SuccessClosure?, + failure: FailClosure?) { + let session = URLSession(configuration: sessionConfig) + guard let request = getRequest(urlString: urlString, + params: params, + method: method, + success: success, + failure: failure) else { return } + session.dataTask(with: request) { data, response, _ in + DispatchQueue.main.async { + self.checkResponse(response: response, data: data, success: success, failure: failure) + } + }.resume() + } + + private func getRequest(urlString: String, + params: [String: Any]?, + method: HTTPMethods, + success: SuccessClosure?, + failure: FailClosure?) -> URLRequest? { + + let string = urlString.hasPrefix("http") ? urlString : baseUrl.appending(urlString) + guard let url = URL(string: string) else { + return nil + } + var request = URLRequest(url: url) + request.httpMethod = method.rawValue + if method == .POST { + request.httpBody = try? JSONSerialization.data(withJSONObject: params ?? [], + options: .sortedKeys) + } + let curl = request.cURL(pretty: true) + debugPrint("curl == \(curl)") + return request + } + + private func convertParams(params: [String: Any]?) -> String { + guard let params = params else { return "" } + let value = params.map({ String(format: "%@=%@", $0.key, "\($0.value)") }).joined(separator: "&") + return value + } + + private func checkResponse(response: URLResponse?, data: Data?, success: SuccessClosure?, failure: FailClosure?) { + if let httpResponse = response as? HTTPURLResponse { + switch httpResponse.statusCode { + case 200...201: + if let resultData = data { + let result = String(data: resultData, encoding: .utf8) + print(result ?? "") + success?(JSONObject.toDictionary(jsonString: result ?? "")) + } else { + failure?("Error in the request status code \(httpResponse.statusCode), response: \(String(describing: response))") + } + default: + failure?("Error in the request status code \(httpResponse.statusCode), response: \(String(describing: response))") + } + } + } +} + +extension URLRequest { + func cURL(pretty: Bool = false) -> String { + let newLine = pretty ? "\\\n" : "" + let method = (pretty ? "--request " : "-X ") + "\(httpMethod ?? "GET") \(newLine)" + let url: String = (pretty ? "--url " : "") + "\'\(url?.absoluteString ?? "")\' \(newLine)" + + var cURL = "curl " + var header = "" + var data: String = "" + + if let httpHeaders = allHTTPHeaderFields, !httpHeaders.keys.isEmpty { + for (key, value) in httpHeaders { + header += (pretty ? "--header " : "-H ") + "\'\(key): \(value)\' \(newLine)" + } + } + + if let bodyData = httpBody, let bodyString = String(data: bodyData, encoding: .utf8), !bodyString.isEmpty { + data = "--data '\(bodyString)'" + } + + cURL += method + url + header + data + + return cURL + } +} + +extension String { + var timeStamp: String { + let date = Date() + let timeInterval = date.timeIntervalSince1970 + let millisecond = CLongLong(timeInterval * 1000) + return "\(millisecond)" + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/ToastView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/ToastView.swift new file mode 100644 index 000000000..030540406 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/NetworkManager/ToastView.swift @@ -0,0 +1,236 @@ +// +// ToastView.swift +// Scene-Examples +// +// Created by zhaoyongqiang on 2021/11/10. +// +import UIKit +import SwiftUI + +enum ToastViewPostion { + case top, center, bottom +} + +class ToastView: UIView { + private lazy var tagImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.layer.masksToBounds = true + imageView.isHidden = true + return imageView + }() + private lazy var label: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .white + label.font = .systemFont(ofSize: 14) + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = UIScreen.main.bounds.width - 60 + return label + }() + + var text: String? { + didSet { + label.text = text + } + } + var textColor: UIColor? { + didSet { + guard let color = textColor else { return } + label.textColor = color + } + } + var font: UIFont? { + didSet { + label.font = font ?? .systemFont(ofSize: 14) + } + } + + var tagImage: UIImage? { + didSet { + guard tagImage != nil else { return } + tagImageView.image = tagImage + tagImageView.isHidden = tagImage == nil + } + } + static private var currentToastView: ToastView? + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + static func showWait(text: String, view: UIView? = nil) { + DispatchQueue.main.async { + self.currentToastView?.removeFromSuperview() + var textColor: UIColor = .white + if #available(iOS 13.0, *) { + textColor = .label + } + let toastView = show(text: text, + tagImage: nil, + textColor: textColor, + font: nil, + postion: .center, + view: view) + self.currentToastView = toastView + showAnimation(toastView: toastView, isRemove: false) + } + } + static func hidden(delay: CGFloat = 0.0) { + if delay <= 0 { + self.currentToastView?.removeFromSuperview() + return + } + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + UIView.animate(withDuration: 0.15) { + self.currentToastView?.alpha = 0 + } completion: { _ in + self.currentToastView?.removeFromSuperview() + } + } + } + + static func show(text: String, duration: CGFloat = 2.5, view: UIView? = nil) { + DispatchQueue.main.async { + let toastView = show(text: text, tagImage: nil, + textColor: .white, font: nil, + postion: .center, + view: view) + showAnimation(toastView: toastView, duration: duration) + } + } + + static func show(text: String, postion: ToastViewPostion = .center) { + DispatchQueue.main.async { + var textColor: UIColor = .white + let toastView = show(text: text, tagImage: nil, + textColor: textColor, font: nil, + postion: postion, + view: nil) + showAnimation(toastView: toastView) + } + } + + static func show(text: String, + postion: ToastViewPostion = .center, + duration: CGFloat = 2.5, + view: UIView? = nil) { + DispatchQueue.main.async { + let toastView = show(text: text, tagImage: nil, + textColor: .white, font: nil, + postion: postion, + view: view) + showAnimation(toastView: toastView, duration: duration) + } + } + + static func show(text: String, tagImage: UIImage? = nil, postion: ToastViewPostion = .center, view: UIView? = nil) { + DispatchQueue.main.async { + let toastView = show(text: text, tagImage: tagImage, + textColor: .white, font: nil, + postion: postion, + view: view) + + showAnimation(toastView: toastView) + } + } + + @discardableResult + static func show(text: String, + tagImage: UIImage? = nil, + textColor: UIColor = .white, + font: UIFont? = nil, + postion: ToastViewPostion = .center, + view: UIView?) -> ToastView { + let toastView = ToastView() + guard let currentView = view ?? UIViewController.keyWindow else { return toastView } + toastView.backgroundColor = UIColor.black.withAlphaComponent(0) + toastView.layer.cornerRadius = 10 + toastView.text = text + toastView.tagImage = tagImage + toastView.textColor = textColor + toastView.font = font + currentView.addSubview(toastView) + toastView.translatesAutoresizingMaskIntoConstraints = false + toastView.centerXAnchor.constraint(equalTo: currentView.centerXAnchor).isActive = true + switch postion { + case .top: + toastView.topAnchor.constraint(equalTo: currentView.safeAreaLayoutGuide.topAnchor, constant: 30).isActive = true + case .center: + toastView.centerYAnchor.constraint(equalTo: currentView.centerYAnchor).isActive = true + case .bottom: + toastView.bottomAnchor.constraint(equalTo: currentView.safeAreaLayoutGuide.bottomAnchor, constant: -100).isActive = true + } + return toastView + } + + private static func showAnimation(toastView: UIView, isRemove: Bool = true, duration: TimeInterval = 2.5) { + UIView.animate(withDuration: 0.15) { + toastView.backgroundColor = UIColor.black.withAlphaComponent(0.6) + } completion: { _ in + guard isRemove else { return } + DispatchQueue.main.asyncAfter(deadline: .now() + duration) { + UIView.animate(withDuration: 0.15) { + toastView.alpha = 0 + } completion: { _ in + toastView.removeFromSuperview() + } + } + } + } + + private func setupUI() { + backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6) + tagImageView.translatesAutoresizingMaskIntoConstraints = false + label.translatesAutoresizingMaskIntoConstraints = false + addSubview(tagImageView) + addSubview(label) + + tagImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true + tagImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + label.leadingAnchor.constraint(equalTo: tagImageView.trailingAnchor, constant: 5).isActive = true + label.topAnchor.constraint(equalTo: topAnchor, constant: 10).isActive = true + label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true + label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true + } +} +extension UIViewController { + static var keyWindow: UIWindow? { + // Get connected scenes + if #available(iOS 13.0, *) { + return UIApplication.shared.connectedScenes + // Keep only active scenes, onscreen and visible to the user + .filter { $0.activationState == .foregroundActive } + // Keep only the first `UIWindowScene` + .first(where: { $0 is UIWindowScene }) + // Get its associated windows + .flatMap({ $0 as? UIWindowScene })?.windows + // Finally, keep only the key window + .first(where: \.isKeyWindow) + } else { + return UIApplication.shared.keyWindow + } + } + static func cl_topViewController(_ viewController: UIViewController? = nil) -> UIViewController? { + let viewController = viewController ?? keyWindow?.rootViewController + + if let navigationController = viewController as? UINavigationController, + !navigationController.viewControllers.isEmpty { + return self.cl_topViewController(navigationController.viewControllers.last) + + } else if let tabBarController = viewController as? UITabBarController, + let selectedController = tabBarController.selectedViewController { + return self.cl_topViewController(selectedController) + + } else if let presentedController = viewController?.presentedViewController { + return self.cl_topViewController(presentedController) + } + return viewController + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/PickerView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/PickerView.swift new file mode 100644 index 000000000..3d69e7750 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/PickerView.swift @@ -0,0 +1,55 @@ +// +// PickerView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/4/1. +// + +import SwiftUI + +struct PickerView: View { + @Binding var dataArray: [String] + @State var onTapCancel: () -> Void + @State var onTapSure: (String) -> Void + @State private var selectedValue = "" + var body: some View { + ZStack { + Picker("", selection: $selectedValue) { + ForEach(dataArray, id: \.self) { value in + Text(value) + } + } + .pickerStyle(WheelPickerStyle()) + HStack { + Button("Cancel".localized) { + onTapCancel() + } + .padding(.horizontal, 5) + .padding(.vertical, 3) + .background(.blue) + .foregroundStyle(.white) + .clipShape(.rect(cornerRadius: 5)) + Spacer() + Button("Sure".localized) { + let value = selectedValue.isEmpty ? dataArray.first : selectedValue + onTapSure(value ?? "") + } + .padding(.horizontal, 5) + .padding(.vertical, 3) + .background(.blue) + .foregroundStyle(.white) + .clipShape(.rect(cornerRadius: 5)) + } + .padding(.horizontal, 20) + .padding(.bottom, 150) + }.background(ignoresSafeAreaEdges: .bottom) + } +} + +#Preview { + PickerView(dataArray: .constant(["aa", "bb", "cc"]), onTapCancel: { + + }, onTapSure: { value in + print(value) + }) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Settings/GlobalSettings.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Settings/GlobalSettings.swift new file mode 100644 index 000000000..facb6c44a --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Settings/GlobalSettings.swift @@ -0,0 +1,109 @@ +// +// GlobalSettings.swift +// APIExample +// +// Created by 张乾泽 on 2020/9/25. +// Copyright © 2020 Agora Corp. All rights reserved. +// + +import SwiftUI +import AgoraRtcKit + +let SCREEN_SHARE_UID_MIN: UInt = 501 +let SCREEN_SHARE_UID_MAX: UInt = 1000 +let SCREEN_SHARE_BROADCASTER_UID_MIN: UInt = 1001 +let SCREEN_SHARE_BROADCASTER_UID_MAX: UInt = 2000 + +let SCREEN_SHARE_UID = UInt.random(in: SCREEN_SHARE_UID_MIN...SCREEN_SHARE_UID_MAX) +let SCREEN_SHARE_BROADCASTER_UID = UInt.random(in: SCREEN_SHARE_BROADCASTER_UID_MIN...SCREEN_SHARE_BROADCASTER_UID_MAX) +// let SCREEN_SHARE_BROADCASTER_UID = 2000 // As per app group didn't enable in this demo, harded code screen share broadcaster uid + +struct SettingItemOption: Identifiable { + var id = UUID() + var idx: Int + var label: String + var value: Any +} + +class SettingItem { + var selected: Int + var options: [SettingItemOption] + + func selectedOption() -> SettingItemOption { + return options[selected] + } + + init(selected: Int, options: [SettingItemOption]) { + self.selected = selected + self.options = options + } +} + +class GlobalSettings { + // The region for connection. This advanced feature applies to scenarios that have regional restrictions. + /** For the regions that Agora supports, + * see https://docs.agora.io/en/Interactive%20Broadcast/API%20Reference/oc/Constants/AgoraAreaCode.html. + * After specifying the region, the SDK connects to the Agora servers within that region. + */ + var area: AgoraAreaCodeType = .global + static let shared = GlobalSettings() + var settings: [String: SettingItem] = [ + "resolution": SettingItem(selected: 3, options: [ + SettingItemOption(idx: 0, label: "90x90", value: CGSize(width: 90, height: 90)), + SettingItemOption(idx: 1, label: "160x120", value: CGSize(width: 160, height: 120)), + SettingItemOption(idx: 2, label: "320x240", value: CGSize(width: 320, height: 240)), + SettingItemOption(idx: 3, label: "960x540", value: CGSize(width: 960, height: 540)), + SettingItemOption(idx: 4, label: "1280x720", value: CGSize(width: 1280, height: 720)) + ]), + "fps": SettingItem(selected: 1, options: [ + SettingItemOption(idx: 0, label: "10fps", value: AgoraVideoFrameRate.fps10), + SettingItemOption(idx: 1, label: "15fps", value: AgoraVideoFrameRate.fps15), + SettingItemOption(idx: 2, label: "24fps", value: AgoraVideoFrameRate.fps24), + SettingItemOption(idx: 3, label: "30fps", value: AgoraVideoFrameRate.fps30), + SettingItemOption(idx: 4, label: "60fps", value: AgoraVideoFrameRate.fps60) + ]), + "orientation": SettingItem(selected: 0, options: [ + SettingItemOption(idx: 0, label: "adaptive", value: AgoraVideoOutputOrientationMode.adaptative), + SettingItemOption(idx: 1, label: "fixed portrait", value: AgoraVideoOutputOrientationMode.fixedPortrait), + SettingItemOption(idx: 2, label: "fixed landscape", value: AgoraVideoOutputOrientationMode.fixedLandscape) + ]), + "role": SettingItem(selected: 0, options: [ + SettingItemOption(idx: 0, label: "broadcaster", value: AgoraClientRole.broadcaster), + SettingItemOption(idx: 1, label: "audience", value: AgoraClientRole.audience) + ]) + ] + func getSetting(key: String) -> SettingItem? { + return settings[key] + } + + var cache: [String: Any] = [:] + + func getCache(key: String) -> String { + (cache[key] as? String) ?? "" + } + func getCache(key: String) -> Bool { + guard let value = cache[key] as? Bool else { return false } + return value + } + func getCache(key: String) -> Int { + guard let value = cache[key] as? Int else { return 0 } + return value + } + + func getUserRole() -> AgoraClientRole { + let role = cache["role"] as? AgoraClientRole + return role ?? .broadcaster + } + func getFps() -> AgoraVideoFrameRate { + let fps = cache["fps"] as? AgoraVideoFrameRate + return fps ?? .fps15 + } + func getResolution() -> CGSize { + let size = cache["resolution"] as? CGSize + return size ?? CGSize(width: 960, height: 540) + } + func getOrientation() -> AgoraVideoOutputOrientationMode { + let orientation = cache["orientation"] as? AgoraVideoOutputOrientationMode + return orientation ?? .adaptative + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Settings/SettingsView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Settings/SettingsView.swift new file mode 100644 index 000000000..e726bc784 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Settings/SettingsView.swift @@ -0,0 +1,163 @@ +// +// SettingsView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/20. +// + +import SwiftUI +import AgoraRtcKit + +enum SettingsCellType { + case text + case select + case input + case toggle +} + +class SettingsSectionModel: Identifiable, ObservableObject { + let id = UUID() + var name: String = "" + @Published var settingsModel: [SettingsModel] = [] + + init(name: String, settingsModel: [SettingsModel]) { + self.name = name + self.settingsModel = settingsModel + } +} + +class SettingsModel: Identifiable, ObservableObject { + let id = UUID() + var key: String = "" + var label: String = "" + var settingItem: SettingItem? + @Published var value: String = "" + var placeHolder: String? + @Published var isOn: Bool = false + @Published var isShowDialog: Bool = false + var type: SettingsCellType = .text + + init(key: String, label: String, settingItem: SettingItem? = nil, value: String = "", placeHolder: String? = nil, isOn: Bool = false, isShowDialog: Bool = false, type: SettingsCellType) { + self.key = key + self.label = label + self.settingItem = settingItem + self.value = value + self.placeHolder = placeHolder + self.isOn = isOn + self.isShowDialog = isShowDialog + self.type = type + } +} + +class ViewModel: ObservableObject { + @Published var items: [SettingsSectionModel] = [] + + init(items: [SettingsSectionModel] = []) { + self.items = items + createData() + } + + func addItem(_ item: SettingsSectionModel) { + items.append(item) + } + + private func createData() { + var videoSettingsModel = [SettingsModel]() + videoSettingsModel.append(SettingsModel(key: "resolution", label: "Resolution".localized, settingItem: GlobalSettings.shared.getSetting(key: "resolution"), value: GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().label ?? "", type: .select)) + videoSettingsModel.append(SettingsModel(key: "fps", label: "Frame Rate".localized, settingItem: GlobalSettings.shared.getSetting(key: "fps"), value: GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().label ?? "", type: .select)) + videoSettingsModel.append(SettingsModel(key: "orientation", label: "Orientation".localized, settingItem: GlobalSettings.shared.getSetting(key: "orientation"), value: GlobalSettings.shared.getSetting(key: "orientation")?.selectedOption().label ?? "", type: .select)) + videoSettingsModel.append(SettingsModel(key: "role", label: "Pick Role".localized, settingItem: GlobalSettings.shared.getSetting(key: "role"), value: GlobalSettings.shared.getSetting(key: "role")?.selectedOption().label ?? "", type: .select)) + let videoSectionModel = SettingsSectionModel(name: "Video Configurations", settingsModel: videoSettingsModel) + + addItem(videoSectionModel) + + var metadataSettingsModel = [SettingsModel]() + metadataSettingsModel.append(SettingsModel(key: "sdk_ver", label: "SDK Version", value: "\(AgoraRtcEngineKit.getSdkVersion())", type: .text)) + let metadata = SettingsSectionModel(name: "Metadata", settingsModel: metadataSettingsModel) + + addItem(metadata) + + var privateCloudSettingsModel = [SettingsModel]() + privateCloudSettingsModel.append(SettingsModel(key: "ip", label: "IP Address", value: GlobalSettings.shared.getCache(key: "ip"), placeHolder: "please input IP", type: .input)) + privateCloudSettingsModel.append(SettingsModel(key: "report", label: "Log Report", isOn: false, type: .toggle)) + privateCloudSettingsModel.append(SettingsModel(key: "log_server_domain", label: "Log Server Domain", value: GlobalSettings.shared.getCache(key: "log_server_domain"), placeHolder: "please input log server IP", type: .input)) + privateCloudSettingsModel.append(SettingsModel(key: "log_server_port", label: "Log Server Port", value: GlobalSettings.shared.getCache(key: "log_server_port"), placeHolder: "please input Server Port", type: .input)) + privateCloudSettingsModel.append(SettingsModel(key: "log_server_path", label: "Log Server Path", value: GlobalSettings.shared.getCache(key: "log_server_path"), placeHolder: "please input Server Path", type: .input)) + privateCloudSettingsModel.append(SettingsModel(key: "log_server_https", label: "Use Https", isOn: false, type: .toggle)) + let privateCloud = SettingsSectionModel(name: "Private cloud", settingsModel: privateCloudSettingsModel) + + addItem(privateCloud) + } +} + +struct SettingsView: View { + @ObservedObject var viewModel = ViewModel() + + var body: some View { + List { + ForEach(viewModel.items) { section in + Section(section.name) { + ForEach(section.settingsModel, id: \.id) { item in + let binding = bindindItem(item: item) + + switch item.type { + case .text: + HStack { + Text(item.label) + Spacer() + Text(item.value) + } + case .select: + HStack { + Text(item.label) + Spacer() + Button(item.value) { + item.isShowDialog = true + viewModel.objectWillChange.send() + } + .confirmationDialog(item.label, isPresented: binding.isShowDialog, titleVisibility: .visible) { + ForEach(item.settingItem?.options ?? []) { option in + Button(option.label) { + GlobalSettings.shared.cache[item.key] = option.value + item.value = option.label + } + } + } + } + case .toggle: + HStack { + Text(item.label) + Spacer() + Toggle("", isOn: binding.isOn) + .onChange(of: item.isOn) { value in + GlobalSettings.shared.cache[item.key] = value + } + } + case .input: + HStack { + Text(item.label) + Spacer() + TextField(item.placeHolder ?? "", text: binding.value) + .textFieldStyle(.roundedBorder) + .onChange(of: item.value) { text in + GlobalSettings.shared.cache[item.key] = text + } + } + } + } + } + } + } + .navigationTitle("Settings") + } + + private func bindindItem(item: SettingsModel) -> Binding { + let index = viewModel.items.firstIndex(where: { $0.settingsModel.contains(where: { $0.id == item.id } )}) ?? 0 + let subIndex = viewModel.items[index].settingsModel.firstIndex(where: { $0.id == item.id }) ?? 0 + return $viewModel.items[index].settingsModel[subIndex] + } +} + +#Preview { + SettingsView() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/StatisticsInfo.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/StatisticsInfo.swift new file mode 100755 index 000000000..49a5795ad --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/StatisticsInfo.swift @@ -0,0 +1,205 @@ +// +// MediaInfo.swift +// OpenVideoCall +// +// Created by GongYuhua on 4/11/16. +// Copyright © 2016 Agora. All rights reserved. +// + +import Foundation +import AgoraRtcKit + +struct StatisticsInfo { + struct LocalInfo { + var channelStats = AgoraChannelStats() + var videoStats = AgoraRtcLocalVideoStats() + var audioStats = AgoraRtcLocalAudioStats() + } + + struct RemoteInfo { + var videoStats = AgoraRtcRemoteVideoStats() + var audioStats = AgoraRtcRemoteAudioStats() + } + + enum StatisticsType { + case local(LocalInfo), remote(RemoteInfo) + + var isLocal: Bool { + switch self { + case .local: return true + case .remote: return false + } + } + } + + var dimension = CGSize.zero + var fps: UInt = 0 + var firstFrameElapsedTime: Double = 0 + var preloadElapsedTime: Double = 0 + var uid: UInt = 0 + var remoteUid: UInt = 0 + var metaInfo: String? + + var type: StatisticsType + + init(type: StatisticsType) { + self.type = type + } + + mutating func updateChannelStats(_ stats: AgoraChannelStats) { + guard self.type.isLocal else { + return + } + switch type { + case .local(let info): + var new = info + new.channelStats = stats + self.type = .local(new) + default: + break + } + } + + mutating func updateLocalVideoStats(_ stats: AgoraRtcLocalVideoStats) { + guard self.type.isLocal else { + return + } + switch type { + case .local(let info): + var new = info + new.videoStats = stats + self.type = .local(new) + default: + break + } + dimension = CGSize(width: Int(stats.encodedFrameWidth), height: Int(stats.encodedFrameHeight)) + fps = stats.sentFrameRate + } + + mutating func updateLocalAudioStats(_ stats: AgoraRtcLocalAudioStats) { + guard self.type.isLocal else { + return + } + switch type { + case .local(let info): + var new = info + new.audioStats = stats + self.type = .local(new) + default: + break + } + } + + mutating func updateVideoStats(_ stats: AgoraRtcRemoteVideoStats) { + switch type { + case .remote(let info): + var new = info + new.videoStats = stats + dimension = CGSize(width: Int(stats.width), height: Int(stats.height)) + fps = UInt(stats.rendererOutputFrameRate) + self.type = .remote(new) + default: + break + } + } + + mutating func updateAudioStats(_ stats: AgoraRtcRemoteAudioStats) { + switch type { + case .remote(let info): + var new = info + new.audioStats = stats + self.type = .remote(new) + default: + break + } + } + mutating func updateUid(uid: UInt) { + self.uid = uid + + } + mutating func updateRemoteUid(remoteUid: UInt) { + self.remoteUid = remoteUid + } + mutating func updateFirstFrameInfo(_ info: AgoraVideoRenderingTracingInfo) { + firstFrameElapsedTime = Double(info.elapsedTime) + preloadElapsedTime = Double(info.join2JoinSuccess) + } + + mutating func updateMetaInfo(data: String?) { + metaInfo = data + } + + func description(audioOnly: Bool) -> String { + var full: String + switch type { + case .local(let info): full = localDescription(info: info, audioOnly: audioOnly) + case .remote(let info): full = remoteDescription(info: info, audioOnly: audioOnly) + } + return full + } + + func localDescription(info: LocalInfo, audioOnly: Bool) -> String { + + let localUid = "uid: \(uid)" + let dimensionFps = "\(Int(dimension.width))×\(Int(dimension.height)),\(fps)fps" + + let lastmile = "LM Delay: \(info.channelStats.lastmileDelay)ms" + let videoSend = "VSend: \(info.videoStats.sentBitrate)kbps" + let audioSend = "ASend: \(info.audioStats.sentBitrate)kbps" + let cpu = "CPU: \(info.channelStats.cpuAppUsage)%/\(info.channelStats.cpuTotalUsage)%" + // TODO +// let vSendLoss = "VSend Loss: \(info.videoStats.txPacketLossRate)%" +// let aSendLoss = "ASend Loss: \(info.audioStats.txPacketLossRate)%" + let vSendLoss = "VSend Loss: MISSING%" + let aSendLoss = "ASend Loss: MISSING%" + + let firstFrame = "firstFrameTime: \(firstFrameElapsedTime)" + + if audioOnly { + let array = firstFrameElapsedTime > 0 + ? [firstFrame, lastmile, audioSend, cpu, aSendLoss] + : [lastmile, audioSend, cpu, aSendLoss] + return array.joined(separator: "\n") + } + var array = firstFrameElapsedTime > 0 + ? [localUid, firstFrame, dimensionFps, lastmile, videoSend, audioSend, cpu, vSendLoss, aSendLoss] + : [localUid, dimensionFps, lastmile, videoSend, audioSend, cpu, vSendLoss, aSendLoss] + if let metaInfo = metaInfo { + array.append(metaInfo) + } + return array.joined(separator: "\n") + } + + func remoteDescription(info: RemoteInfo, audioOnly: Bool) -> String { + let dimensionFpsBit = "\(Int(dimension.width))×\(Int(dimension.height)), \(fps)fps" + + var audioQuality: AgoraNetworkQuality + if let quality = AgoraNetworkQuality(rawValue: info.audioStats.quality) { + audioQuality = quality + } else { + audioQuality = AgoraNetworkQuality.unknown + } + let uid = "uid: \(remoteUid)" + let firstFrame = "firstFrameTime: \(firstFrameElapsedTime)" + let videoRecv = "VRecv: \(info.videoStats.receivedBitrate)kbps" + let audioRecv = "ARecv: \(info.audioStats.receivedBitrate)kbps" + + let videoLoss = "VLoss: \(info.videoStats.packetLossRate)%" + let audioLoss = "ALoss: \(info.audioStats.audioLossRate)%" + let aquality = "AQuality: \(audioQuality.description())" + let preloadTime = "join2Success: \(preloadElapsedTime)" + if audioOnly { + let array = firstFrameElapsedTime > 0 + ? [firstFrame, audioRecv, audioLoss, aquality] + : [audioRecv, audioLoss, aquality] + return array.joined(separator: "\n") + } + var array = firstFrameElapsedTime > 0 + ? [uid, firstFrame, dimensionFpsBit, videoRecv, audioRecv, videoLoss, audioLoss, aquality, preloadTime] + : [uid, dimensionFpsBit, videoRecv, audioRecv, videoLoss, audioLoss, aquality, preloadTime] + if preloadElapsedTime <= 0 { + array.removeLast() + } + return array.joined(separator: "\n") + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/KFMP4Demuxer.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/KFMP4Demuxer.h new file mode 100644 index 000000000..f8e05afa1 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/KFMP4Demuxer.h @@ -0,0 +1,68 @@ +// +// KFMP4Demuxer.h +// APIExample +// +// Created by zhaoyongqiang on 2023/6/25. +// Copyright © 2023 Agora Corp. All rights reserved. +// + +#import +#import +#import + + +typedef NS_ENUM(NSInteger, KFMediaType) { + KFMediaNone = 0, + KFMediaAudio = 1 << 0, // 仅音频。 + KFMediaVideo = 1 << 1, // 仅视频。 + KFMediaAV = KFMediaAudio | KFMediaVideo, // 音视频都有。 +}; + +typedef NS_ENUM(NSInteger, KFMP4DemuxerStatus) { + KFMP4DemuxerStatusUnknown = 0, + KFMP4DemuxerStatusRunning = 1, + KFMP4DemuxerStatusFailed = 2, + KFMP4DemuxerStatusCompleted = 3, + KFMP4DemuxerStatusCancelled = 4, +}; + + +@interface KFDemuxerConfig : NSObject +@property (nonatomic, strong) AVAsset *asset; // 待解封装的资源。 +@property (nonatomic, assign) KFMediaType demuxerType; // 解封装类型。 +@end + +@interface KFVideoPacketExtraData : NSObject +@property (nonatomic, strong) NSData *sps; +@property (nonatomic, strong) NSData *pps; +@property (nonatomic, strong) NSData *vps; +@end + + +@interface KFMP4Demuxer : NSObject ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithConfig:(KFDemuxerConfig *)config; + +@property (nonatomic, strong, readonly) KFDemuxerConfig *config; +@property (nonatomic, copy) void (^errorCallBack)(NSError *error); +@property (nonatomic, assign, readonly) BOOL hasAudioTrack; // 是否包含音频数据。 +@property (nonatomic, assign, readonly) BOOL hasVideoTrack; // 是否包含视频数据。 +@property (nonatomic, assign, readonly) CGSize videoSize; // 视频大小。 +@property (nonatomic, assign, readonly) CMTime duration; // 媒体时长。 +@property (nonatomic, assign, readonly) CMVideoCodecType codecType; // 编码类型。 +@property (nonatomic, assign, readonly) KFMP4DemuxerStatus demuxerStatus; // 解封装器状态。 +@property (nonatomic, assign, readonly) BOOL audioEOF; // 是否音频结束。 +@property (nonatomic, assign, readonly) BOOL videoEOF; // 是否视频结束。 +@property (nonatomic, assign, readonly) CGAffineTransform preferredTransform; // 图像的变换信息。比如:视频图像旋转。 +@property (nonatomic, copy) void (^dataCallBack)(NSData *data, CMSampleBufferRef sampleBuffer); // 解码完成的数据回调 + +- (void)startReading; // 开始读取数据解封装。 +- (void)cancelReading; // 取消读取。 + +- (BOOL)hasAudioSampleBuffer; // 是否还有音频数据。 +- (CMSampleBufferRef)copyNextAudioSampleBuffer CF_RETURNS_RETAINED; // 拷贝下一份音频采样。 + +- (BOOL)hasVideoSampleBuffer; // 是否还有视频数据。 +- (CMSampleBufferRef)copyNextVideoSampleBuffer CF_RETURNS_RETAINED; // 拷贝下一份视频采样。 +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/KFMP4Demuxer.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/KFMP4Demuxer.m new file mode 100644 index 000000000..1bfae527a --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/KFMP4Demuxer.m @@ -0,0 +1,626 @@ +// +// KFMP4Demuxer.m +// APIExample +// +// Created by zhaoyongqiang on 2023/6/25. +// Copyright © 2023 Agora Corp. All rights reserved. +// + +#import "KFMP4Demuxer.h" + +@implementation KFDemuxerConfig + +- (instancetype)init { + self = [super init]; + if (self) { + _demuxerType = KFMediaAV; + } + + return self; +} +@end + +@implementation KFVideoPacketExtraData + +@end + +#define KFMP4DemuxerBadFileError 2000 +#define KFMP4DemuxerAddVideoOutputError 2001 +#define KFMP4DemuxerAddAudioOutputError 2002 +#define KFMP4DemuxerQueueMaxCount 3 + +@interface KFMP4Demuxer () { + CMSimpleQueueRef _audioQueue; + CMSimpleQueueRef _videoQueue; +} +@property (nonatomic, strong, readwrite) KFDemuxerConfig* config; +@property (nonatomic, strong) AVAssetReader *demuxReader; // 解封装器实例。 +@property (nonatomic, strong) AVAssetReaderTrackOutput *readerAudioOutput; // Demuxer 的音频输出。 +@property (nonatomic, strong) AVAssetReaderTrackOutput *readerVideoOutput; // Demuxer 的视频输出。 +@property (nonatomic, strong) dispatch_queue_t demuxerQueue; +@property (nonatomic, strong) dispatch_semaphore_t demuxerSemaphore; +@property (nonatomic, strong) dispatch_semaphore_t audioQueueSemaphore; +@property (nonatomic, strong) dispatch_semaphore_t videoQueueSemaphore; +@property (nonatomic, assign) CMTime lastAudioCopyNextTime; // 上一次拷贝的音频采样的时间戳。 +@property (nonatomic, assign) CMTime lastVideoCopyNextTime; // 上一次拷贝的视频采样的时间戳。 +@property (nonatomic, assign, readwrite) BOOL hasAudioTrack; // 是否包含音频数据。 +@property (nonatomic, assign, readwrite) BOOL hasVideoTrack; // 是否包含视频数据。 +@property (nonatomic, assign, readwrite) CGSize videoSize; // 视频大小。 +@property (nonatomic, assign, readwrite) CMTime duration; // 媒体时长。 +@property (nonatomic, assign, readwrite) CMVideoCodecType codecType; // 编码类型。 +@property (nonatomic, assign, readwrite) KFMP4DemuxerStatus demuxerStatus; // 解封装器状态。 +@property (nonatomic, assign, readwrite) BOOL audioEOF; // 是否音频结束。 +@property (nonatomic, assign, readwrite) BOOL videoEOF; // 是否视频结束。 +@property (nonatomic, assign, readwrite) CGAffineTransform preferredTransform; // 图像的变换信息。比如:视频图像旋转。 +@end + +@implementation KFMP4Demuxer +#pragma mark - LifeCycle +- (instancetype)initWithConfig:(KFDemuxerConfig *)config { + self = [super init]; + if (self) { + _config = config; + _demuxerSemaphore = dispatch_semaphore_create(1); + _audioQueueSemaphore = dispatch_semaphore_create(1); + _videoQueueSemaphore = dispatch_semaphore_create(1); + _demuxerStatus = KFMP4DemuxerStatusUnknown; + _demuxerQueue = dispatch_queue_create("com.KeyFrameKit.demuxerQueue", DISPATCH_QUEUE_SERIAL); + CMSimpleQueueCreate(kCFAllocatorDefault, KFMP4DemuxerQueueMaxCount, &_audioQueue); + CMSimpleQueueCreate(kCFAllocatorDefault, KFMP4DemuxerQueueMaxCount, &_videoQueue); + } + return self; +} + +- (void)dealloc { + // 清理状态机。 + if (self.demuxerStatus == KFMP4DemuxerStatusRunning) { + self.demuxerStatus = KFMP4DemuxerStatusCancelled; + } + + // 清理解封装器实例。 + dispatch_semaphore_wait(_demuxerSemaphore, DISPATCH_TIME_FOREVER); + if (self.demuxReader && self.demuxReader.status == AVAssetReaderStatusReading) { + [self.demuxReader cancelReading]; + } + dispatch_semaphore_signal(_demuxerSemaphore); + + // 清理音频数据队列。 + dispatch_semaphore_wait(_audioQueueSemaphore, DISPATCH_TIME_FOREVER); + while (CMSimpleQueueGetCount(_audioQueue) > 0) { + CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)CMSimpleQueueDequeue(_audioQueue); + CFRelease(sampleBuffer); + } + dispatch_semaphore_signal(_audioQueueSemaphore); + + // 清理视频数据队列。 + dispatch_semaphore_wait(_videoQueueSemaphore, DISPATCH_TIME_FOREVER); + while (CMSimpleQueueGetCount(_videoQueue) > 0) { + CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)CMSimpleQueueDequeue(_videoQueue); + CFRelease(sampleBuffer); + } + dispatch_semaphore_signal(_videoQueueSemaphore); +} + +#pragma mark - Public Method +- (void)startReading { + __weak typeof(self) weakSelf = self; + dispatch_async(_demuxerQueue, ^{ + dispatch_semaphore_wait(weakSelf.demuxerSemaphore, DISPATCH_TIME_FOREVER); + + // 在第一次开始读数据时,创建解封装器实例。 + if (!weakSelf.demuxReader) { + NSError *error; + [weakSelf _setupDemuxReader:&error]; + weakSelf.audioEOF = !weakSelf.hasAudioTrack; + weakSelf.videoEOF = !weakSelf.hasVideoTrack; + weakSelf.demuxerStatus = error ? KFMP4DemuxerStatusFailed : KFMP4DemuxerStatusRunning; + dispatch_semaphore_signal(weakSelf.demuxerSemaphore); + if (error == nil) { + // Demuxer 启动成功后,就可以从它里面获取解封装后的数据了。 + [weakSelf fetchAndSaveDemuxedData]; + } else { + NSLog(@"KFMP4Demuxer error: %zi %@", error.code, error.localizedDescription); + } + return; + } + + dispatch_semaphore_signal(weakSelf.demuxerSemaphore); + }); +} + +- (void)cancelReading { + __weak typeof(self) weakSelf = self; + if (self.demuxerQueue == nil) { return; } + dispatch_async(_demuxerQueue, ^{ + if (weakSelf.demuxerSemaphore == nil) { return; } + dispatch_semaphore_wait(weakSelf.demuxerSemaphore, DISPATCH_TIME_FOREVER); + + // 取消读数据。 + if (weakSelf.demuxReader && weakSelf.demuxReader.status == AVAssetReaderStatusReading) { + [weakSelf.demuxReader cancelReading]; + } + weakSelf.demuxerStatus = KFMP4DemuxerStatusCancelled; + + dispatch_semaphore_signal(weakSelf.demuxerSemaphore); + }); +} + +- (BOOL)hasAudioSampleBuffer { + // 是否还有音频数据。 + if (self.hasAudioTrack && self.demuxerStatus == KFMP4DemuxerStatusRunning && !self.audioEOF) { + int32_t audioCount = 0; + dispatch_semaphore_wait(_audioQueueSemaphore, DISPATCH_TIME_FOREVER); + if (CMSimpleQueueGetCount(_audioQueue) > 0) { + audioCount = CMSimpleQueueGetCount(_audioQueue); + } + dispatch_semaphore_signal(_audioQueueSemaphore); + + return (audioCount == 0 && self.audioEOF) ? NO : YES; + } + + return NO; +} + +- (CMSampleBufferRef)copyNextAudioSampleBuffer CF_RETURNS_RETAINED { + // 拷贝下一份音频采样。 + CMSampleBufferRef sampleBuffer = NULL; + while (!sampleBuffer && self.demuxerStatus == KFMP4DemuxerStatusRunning && !self.audioEOF) { + // 先从缓冲队列取数据。 + dispatch_semaphore_wait(_audioQueueSemaphore, DISPATCH_TIME_FOREVER); + if (CMSimpleQueueGetCount(_audioQueue) > 0) { + sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(_audioQueue); + } + dispatch_semaphore_signal(_audioQueueSemaphore); + + // 缓冲队列没有数据,就同步加载一下试试。 + if (!sampleBuffer && self.demuxerStatus == KFMP4DemuxerStatusRunning) { + [self _syncLoadNextSampleBuffer]; + } + } + + // 异步加载一下,先缓冲到数据队列中,等下次取。 + [self _asyncLoadNextSampleBuffer]; + + return sampleBuffer; +} + +- (BOOL)hasVideoSampleBuffer { + // 是否还有视频数据。 + if (self.hasVideoTrack && self.demuxerStatus == KFMP4DemuxerStatusRunning && !self.videoEOF) { + int32_t videoCount = 0; + dispatch_semaphore_wait(_videoQueueSemaphore, DISPATCH_TIME_FOREVER); + if (CMSimpleQueueGetCount(_videoQueue) > 0) { + videoCount = CMSimpleQueueGetCount(_videoQueue); + } + dispatch_semaphore_signal(_videoQueueSemaphore); + + return (videoCount == 0 && self.videoEOF) ? NO : YES; + } + + return NO; +} + +- (CMSampleBufferRef)copyNextVideoSampleBuffer CF_RETURNS_RETAINED { + // 拷贝下一份视频采样。 + CMSampleBufferRef sampleBuffer = NULL; + while (!sampleBuffer && self.demuxerStatus == KFMP4DemuxerStatusRunning && !self.videoEOF) { + // 先从缓冲队列取数据。 + dispatch_semaphore_wait(_videoQueueSemaphore, DISPATCH_TIME_FOREVER); + if (CMSimpleQueueGetCount(_videoQueue) > 0) { + sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(_videoQueue); + } + dispatch_semaphore_signal(_videoQueueSemaphore); + + // 缓冲队列没有数据,就同步加载一下试试。 + if (!sampleBuffer && self.demuxerStatus == KFMP4DemuxerStatusRunning) { + [self _syncLoadNextSampleBuffer]; + } + } + + // 异步加载一下,先缓冲到数据队列中,等下次取。 + [self _asyncLoadNextSampleBuffer]; + + return sampleBuffer; +} + +#pragma mark - Utility +- (void)fetchAndSaveDemuxedData { + // 异步地从 Demuxer 获取解封装后的 H.264/H.265 编码数据。 + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + while (self.hasVideoSampleBuffer) { + CMSampleBufferRef videoBuffer = [self copyNextVideoSampleBuffer]; + if (videoBuffer) { + [self saveSampleBuffer:videoBuffer]; + CFRelease(videoBuffer); + } + } + if (self.demuxerStatus == KFMP4DemuxerStatusCompleted) { + NSLog(@"KFMP4Demuxer complete"); + } + }); +} + +- (KFVideoPacketExtraData *)getPacketExtraData:(CMSampleBufferRef)sampleBuffer { + // 从 CMSampleBuffer 中获取 extra data。 + if (!sampleBuffer) { + return nil; + } + + // 获取编码类型。 + CMVideoCodecType codecType = CMVideoFormatDescriptionGetCodecType(CMSampleBufferGetFormatDescription(sampleBuffer)); + + KFVideoPacketExtraData *extraData = nil; + if (codecType == kCMVideoCodecType_H264) { + // 获取 H.264 的 extra data:sps、pps。 + CMFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer); + size_t sparameterSetSize, sparameterSetCount; + const uint8_t *sparameterSet; + OSStatus statusCode = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 0, &sparameterSet, &sparameterSetSize, &sparameterSetCount, 0); + if (statusCode == noErr) { + size_t pparameterSetSize, pparameterSetCount; + const uint8_t *pparameterSet; + OSStatus statusCode = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 1, &pparameterSet, &pparameterSetSize, &pparameterSetCount, 0); + if (statusCode == noErr) { + extraData = [[KFVideoPacketExtraData alloc] init]; + extraData.sps = [NSData dataWithBytes:sparameterSet length:sparameterSetSize]; + extraData.pps = [NSData dataWithBytes:pparameterSet length:pparameterSetSize]; + } + } + } else if (codecType == kCMVideoCodecType_HEVC) { + // 获取 H.265 的 extra data:vps、sps、pps。 + CMFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer); + size_t vparameterSetSize, vparameterSetCount; + const uint8_t *vparameterSet; + if (@available(iOS 11.0, *)) { + OSStatus statusCode = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, 0, &vparameterSet, &vparameterSetSize, &vparameterSetCount, 0); + if (statusCode == noErr) { + size_t sparameterSetSize, sparameterSetCount; + const uint8_t *sparameterSet; + OSStatus statusCode = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, 1, &sparameterSet, &sparameterSetSize, &sparameterSetCount, 0); + if (statusCode == noErr) { + size_t pparameterSetSize, pparameterSetCount; + const uint8_t *pparameterSet; + OSStatus statusCode = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, 2, &pparameterSet, &pparameterSetSize, &pparameterSetCount, 0); + if (statusCode == noErr) { + extraData = [[KFVideoPacketExtraData alloc] init]; + extraData.vps = [NSData dataWithBytes:vparameterSet length:vparameterSetSize]; + extraData.sps = [NSData dataWithBytes:sparameterSet length:sparameterSetSize]; + extraData.pps = [NSData dataWithBytes:pparameterSet length:pparameterSetSize]; + } + } + } + } else { + // 其他编码格式。 + } + } + + return extraData; +} + +- (BOOL)isKeyFrame:(CMSampleBufferRef)sampleBuffer { + CFArrayRef array = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, true); + if (!array) { + return NO; + } + + CFDictionaryRef dic = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 0); + if (!dic) { + return NO; + } + + // 检测 sampleBuffer 是否是关键帧。 + BOOL keyframe = !CFDictionaryContainsKey(dic, kCMSampleAttachmentKey_NotSync); + + return keyframe; +} + +- (void)saveSampleBuffer:(CMSampleBufferRef)sampleBuffer { + // 将编码数据存储为文件。 + // iOS 的 VideoToolbox 编码和解码只支持 AVCC/HVCC 的码流格式。但是 Android 的 MediaCodec 只支持 AnnexB 的码流格式。这里我们做一下两种格式的转换示范,将 AVCC/HVCC 格式的码流转换为 AnnexB 再存储。 + // 1、AVCC/HVCC 码流格式:[extradata]|[length][NALU]|[length][NALU]|... + // VPS、SPS、PPS 不用 NALU 来存储,而是存储在 extradata 中;每个 NALU 前有个 length 字段表示这个 NALU 的长度(不包含 length 字段),length 字段通常是 4 字节。 + // 2、AnnexB 码流格式:[startcode][NALU]|[startcode][NALU]|... + // 每个 NAL 前要添加起始码:0x00000001;VPS、SPS、PPS 也都用这样的 NALU 来存储,一般在码流最前面。 + if (sampleBuffer) { + NSMutableData *resultData = [NSMutableData new]; + uint8_t nalPartition[] = {0x00, 0x00, 0x00, 0x01}; + + // 关键帧前添加 vps(H.265)、sps、pps。这里要注意顺序别乱了。 + if ([self isKeyFrame:sampleBuffer]) { + KFVideoPacketExtraData *extraData = [self getPacketExtraData:sampleBuffer]; + if (extraData.vps) { + [resultData appendBytes:nalPartition length:4]; + [resultData appendData:extraData.vps]; + } + [resultData appendBytes:nalPartition length:4]; + [resultData appendData:extraData.sps]; + [resultData appendBytes:nalPartition length:4]; + [resultData appendData:extraData.pps]; + } + + // 获取编码数据。这里的数据是 AVCC/HVCC 格式的。 + CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(sampleBuffer); + size_t length, totalLength; + char *dataPointer; + OSStatus statusCodeRet = CMBlockBufferGetDataPointer(dataBuffer, 0, &length, &totalLength, &dataPointer); + if (statusCodeRet == noErr) { + size_t bufferOffset = 0; + static const int NALULengthHeaderLength = 4; + // 拷贝编码数据。 + while (bufferOffset < totalLength - NALULengthHeaderLength) { + // 通过 length 字段获取当前这个 NALU 的长度。 + uint32_t NALUnitLength = 0; + memcpy(&NALUnitLength, dataPointer + bufferOffset, NALULengthHeaderLength); + NALUnitLength = CFSwapInt32BigToHost(NALUnitLength); + + // 拷贝 AnnexB 起始码字节。 + [resultData appendData:[NSData dataWithBytes:nalPartition length:4]]; + // 拷贝这个 NALU 的字节。 + [resultData appendData:[NSData dataWithBytes:(dataPointer + bufferOffset + NALULengthHeaderLength) length:NALUnitLength]]; + + // 步进。 + bufferOffset += NALULengthHeaderLength + NALUnitLength; + } + } + if (self.dataCallBack) { + self.dataCallBack(resultData.copy, sampleBuffer); + } + } +} + +#pragma mark - Private Method +- (void)_setupDemuxReader:(NSError**)error { + if (!self.config.asset) { + *error = [NSError errorWithDomain:NSStringFromClass([self class]) code:40003 userInfo:nil]; + return; + } + + // 1、创建解封装器实例。 + // 使用 AVAssetReader 作为解封装器。解封装的目标是 config 中的 AVAsset 资源。 + _demuxReader = [[AVAssetReader alloc] initWithAsset:self.config.asset error:error]; + if (!_demuxReader) { + return; + } + + // 2、获取时间信息。 + _duration = [self.config.asset duration]; + + // 3、处理待解封装的资源中的视频。 + if (self.config.demuxerType & KFMediaVideo) { + // 取出视频轨道。 + AVAssetTrack *videoTrack = [[self.config.asset tracksWithMediaType:AVMediaTypeVideo] firstObject]; + _hasVideoTrack = videoTrack ? YES : NO; + if (_hasVideoTrack) { + // 获取图像变换信息。 + _preferredTransform = videoTrack.preferredTransform; + + // 获取图像大小。要应用上图像变换信息。 + _videoSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, videoTrack.preferredTransform); + _videoSize = CGSizeMake(fabs(_videoSize.width), fabs(_videoSize.height)); + + // 获取编码格式。 + CMVideoFormatDescriptionRef formatDescription = (__bridge CMVideoFormatDescriptionRef)[[videoTrack formatDescriptions] firstObject]; + if (formatDescription) { + _codecType = CMVideoFormatDescriptionGetCodecType(formatDescription); + } + + // 基于轨道创建视频输出。 + _readerVideoOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:nil]; + _readerVideoOutput.alwaysCopiesSampleData = NO; // 避免总是做数据拷贝,影响性能。 + + // 给解封装器绑定视频输出。 + if ([_demuxReader canAddOutput:_readerVideoOutput]) { + [_demuxReader addOutput:_readerVideoOutput]; + } else { + *error = _demuxReader.error ? _demuxReader.error : [NSError errorWithDomain:NSStringFromClass([self class]) code:KFMP4DemuxerAddVideoOutputError userInfo:nil]; + return; + } + } + } + + // 4、处理待解封装的资源中的音频。 + if (self.config.demuxerType & KFMediaAudio) { + // 取出音频轨道。 + AVAssetTrack *audioTrack = [[self.config.asset tracksWithMediaType:AVMediaTypeAudio] firstObject]; + _hasAudioTrack = audioTrack ? YES : NO; + if (_hasAudioTrack) { + // 基于轨道创建音频输出。 + _readerAudioOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:audioTrack outputSettings:nil]; + _readerAudioOutput.alwaysCopiesSampleData = NO; // 避免总是做数据拷贝,影响性能。 + + // 给解封装器绑定音频输出。 + if ([_demuxReader canAddOutput:_readerAudioOutput]) { + [_demuxReader addOutput:_readerAudioOutput]; + } else { + *error = _demuxReader.error ? _demuxReader.error : [NSError errorWithDomain:NSStringFromClass([self class]) code:KFMP4DemuxerAddAudioOutputError userInfo:nil]; + return; + } + } + } + + // 5、音频和视频数据都没有,就报错。 + if (!_hasVideoTrack && !_hasAudioTrack) { + *error = [NSError errorWithDomain:NSStringFromClass([self class]) code:KFMP4DemuxerBadFileError userInfo:nil]; + return; + } + + // 6、启动解封装。 + BOOL startSuccess = [self.demuxReader startReading]; + if (!startSuccess) { + *error = self.demuxReader.error; + } +} + +- (void)_asyncLoadNextSampleBuffer { + // 异步加载下一份采样数据。 + __weak typeof(self) weakSelf = self; + dispatch_async(_demuxerQueue, ^{ + dispatch_semaphore_wait(weakSelf.demuxerSemaphore, DISPATCH_TIME_FOREVER); + [weakSelf _loadNextSampleBuffer]; + dispatch_semaphore_signal(weakSelf.demuxerSemaphore); + }); +} + +- (void)_syncLoadNextSampleBuffer { + // 同步加载下一份采样数据。 + dispatch_semaphore_wait(self.demuxerSemaphore, DISPATCH_TIME_FOREVER); + [self _loadNextSampleBuffer]; + dispatch_semaphore_signal(self.demuxerSemaphore); +} + +- (void)_loadNextSampleBuffer { + if (self.demuxerStatus != KFMP4DemuxerStatusRunning) { + return; + } + + // 1、根据解封装器的状态,处理异常情况。 + if (self.demuxReader.status == AVAssetWriterStatusCompleted) { + self.demuxerStatus = KFMP4DemuxerStatusCompleted; + return; + } else if (self.demuxReader.status == AVAssetWriterStatusFailed) { +#if TARGET_OS_IPHONE + if (self.demuxReader.error.code == AVErrorOperationInterrupted) { + // 如果当前解封装器的状态是被打断而失败,就尝试重新创建一下。 + NSError *error; + [self _setupDemuxReader:&error]; + if (!error) { + // 同时做一下恢复处理。 + [self _resumeLastTime]; + } + } +#else + if (self.demuxReader.error.code == AVErrorUnknown) { + // 如果当前解封装器的状态是被打断而失败,就尝试重新创建一下。 + NSError *error; + [self _setupDemuxReader:&error]; + if (!error) { + // 同时做一下恢复处理。 + [self _resumeLastTime]; + } + } +#endif + if (self.demuxReader.status == AVAssetWriterStatusFailed) { + // 如果状态依然是失败,就上报错误。 + self.demuxerStatus = KFMP4DemuxerStatusFailed; + if (self.errorCallBack) { + NSError *error = self.demuxReader.error; + dispatch_async(dispatch_get_main_queue(), ^{ + self.errorCallBack(error); + }); + } + return; + } + } else if (self.demuxReader.status == AVAssetWriterStatusCancelled) { + // 如果状态是取消,就直接 return。 + self.demuxerStatus = KFMP4DemuxerStatusCancelled; + return; + } + + // 2、解封装器状态正常,加载下一份采样数据。 + BOOL audioNeedLoad = (self.config.demuxerType & KFMediaAudio) && !self.audioEOF; + BOOL videoNeedLoad = (self.config.demuxerType & KFMediaVideo) && !self.videoEOF; + while (self.demuxReader && self.demuxReader.status == AVAssetReaderStatusReading && (audioNeedLoad || videoNeedLoad)) { + // 加载音频数据。 + if (audioNeedLoad) { + dispatch_semaphore_wait(_audioQueueSemaphore, DISPATCH_TIME_FOREVER); + int32_t audioCount = CMSimpleQueueGetCount(_audioQueue); + dispatch_semaphore_signal(_audioQueueSemaphore); + if (audioCount < KFMP4DemuxerQueueMaxCount) { + // 从音频输出源读取音频数据。 + CMSampleBufferRef next = [self.readerAudioOutput copyNextSampleBuffer]; + if (next) { + if (!CMSampleBufferGetDataBuffer(next)) { + CFRelease(next); + } else { + // 将数据从音频输出源 readerAudioOutput 拷贝到缓冲队列 _audioQueue 中。 + self.lastAudioCopyNextTime = CMSampleBufferGetPresentationTimeStamp(next); + dispatch_semaphore_wait(_audioQueueSemaphore, DISPATCH_TIME_FOREVER); + CMSimpleQueueEnqueue(_audioQueue, next); + audioCount = CMSimpleQueueGetCount(_audioQueue); + dispatch_semaphore_signal(_audioQueueSemaphore); + } + } else { + self.audioEOF = self.demuxReader.status == AVAssetReaderStatusReading || self.demuxReader.status == AVAssetWriterStatusCompleted; + audioNeedLoad = NO; + } + } else { + audioNeedLoad = NO; + } + } + + // 加载视频数据。 + if (videoNeedLoad) { + dispatch_semaphore_wait(_videoQueueSemaphore, DISPATCH_TIME_FOREVER); + int32_t videoCount = CMSimpleQueueGetCount(_videoQueue); + dispatch_semaphore_signal(_videoQueueSemaphore); + if (videoCount < KFMP4DemuxerQueueMaxCount) { + // 从视频输出源读取视频数据。 + CMSampleBufferRef next = [self.readerVideoOutput copyNextSampleBuffer]; + if (next) { + if (!CMSampleBufferGetDataBuffer(next)) { + CFRelease(next); + } else { + // 将数据从视频输出源 readerVideoOutput 拷贝到缓冲队列 _videoQueue 中。 + self.lastVideoCopyNextTime = CMSampleBufferGetDecodeTimeStamp(next); + dispatch_semaphore_wait(_videoQueueSemaphore, DISPATCH_TIME_FOREVER); + CMSimpleQueueEnqueue(_videoQueue, next); + videoCount = CMSimpleQueueGetCount(_videoQueue); + dispatch_semaphore_signal(_videoQueueSemaphore); + } + } else { + self.videoEOF = self.demuxReader.status == AVAssetReaderStatusReading || self.demuxReader.status == AVAssetWriterStatusCompleted; + videoNeedLoad = NO; + } + } else { + videoNeedLoad = NO; + } + } + } +} + +- (void)_resumeLastTime { + // 对于异常中断后的处理,需要根据记录的时间戳 _lastAudioCopyNextTime/_lastVideoCopyNextTime 做恢复操作。 + BOOL audioNeedLoad = (_lastAudioCopyNextTime.value > 0) && !self.audioEOF; + BOOL videoNeedLoad = (_lastVideoCopyNextTime.value > 0) && !self.videoEOF; + while (self.demuxReader && self.demuxReader.status == AVAssetReaderStatusReading && (audioNeedLoad || videoNeedLoad)) { + if (audioNeedLoad) { + // 从音频输出源读取音频数据。 + CMSampleBufferRef next = [self.readerAudioOutput copyNextSampleBuffer]; + if (next) { + if (CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(next)) <= CMTimeGetSeconds(_lastAudioCopyNextTime) || !CMSampleBufferGetDataBuffer(next)) { + // 从输出源取出的数据时间戳小于上次标记的时间,则表示这份采样数据已经处理过了。 + CFRelease(next); + } else { + dispatch_semaphore_wait(_audioQueueSemaphore, DISPATCH_TIME_FOREVER); + CMSimpleQueueEnqueue(_audioQueue, next); + dispatch_semaphore_signal(_audioQueueSemaphore); + audioNeedLoad = NO; + } + } else { + self.audioEOF = self.demuxReader.status == AVAssetReaderStatusReading || self.demuxReader.status == AVAssetWriterStatusCompleted; + audioNeedLoad = NO; + } + } + + if (videoNeedLoad) { + // 从视频输出源读取视频数据。 + CMSampleBufferRef next = [self.readerVideoOutput copyNextSampleBuffer]; + if (next) { + if (CMTimeGetSeconds(CMSampleBufferGetDecodeTimeStamp(next)) <= CMTimeGetSeconds(_lastVideoCopyNextTime) || !CMSampleBufferGetDataBuffer(next)) { + // 从输出源取出的数据时间戳小于上次标记的时间,则表示这份采样数据已经处理过了。 + CFRelease(next); + } else { + dispatch_semaphore_wait(_videoQueueSemaphore, DISPATCH_TIME_FOREVER); + CMSimpleQueueEnqueue(_videoQueue, next); + dispatch_semaphore_signal(_videoQueueSemaphore); + videoNeedLoad = NO; + } + } else { + self.videoEOF = self.demuxReader.status == AVAssetReaderStatusReading || self.demuxReader.status == AVAssetWriterStatusCompleted; + videoNeedLoad = NO; + } + } + } +} + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/LogUtil.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/LogUtil.swift new file mode 100644 index 000000000..d08709e15 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/LogUtil.swift @@ -0,0 +1,68 @@ +// +// LogUtil.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/22. +// + +import Foundation +enum LogLevel { + case info, warning, error + + var description: String { + switch self { + case .info: return "Info" + case .warning: return "Warning" + case .error: return "Error" + } + } +} + +struct LogItem { + var message: String + var level: LogLevel + var dateTime: Date +} + +class LogUtils { + static var logs: [LogItem] = [] + static var appLogPath: String = "\(logFolder())/app-\(Date().getFormattedDate(format: "yyyy-MM-dd")).log" + + static func log(message: String, level: LogLevel) { + LogUtils.logs.append(LogItem(message: message, level: level, dateTime: Date())) + print("\(level.description): \(message)") + } + + static func logFolder() -> String { + let folder = "\(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])/logs" + try? FileManager.default.createDirectory(atPath: folder, withIntermediateDirectories: true, attributes: nil) + return folder + } + static func sdkLogPath() -> String { + let logPath = "\(logFolder())/agorasdk.log" + return logPath + } + + static func removeAll() { + LogUtils.logs.removeAll() + } + + static func writeAppLogsToDisk() { + if let outputStream = OutputStream(url: URL(fileURLWithPath: LogUtils.appLogPath), append: true) { + outputStream.open() + for log in LogUtils.logs { + let msg = "\(log.level.description) \(log.dateTime.getFormattedDate(format: "yyyy-MM-dd HH:mm:ss")) \(log.message)\n" + let bytesWritten = outputStream.write(msg) + if bytesWritten < 0 { print("write failure") } + } + outputStream.close() + LogUtils.removeAll() + } else { + print("Unable to open file") + } + } + + static func cleanUp() { + try? FileManager.default.removeItem(at: URL(fileURLWithPath: LogUtils.logFolder(), isDirectory: true)) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/MediaUtils.h b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/MediaUtils.h new file mode 100644 index 000000000..05d294d33 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/MediaUtils.h @@ -0,0 +1,27 @@ +// +// MediaUtils.h +// APIExample +// +// Created by Arlin on 2022/4/12. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MediaUtils : NSObject + ++ (CVPixelBufferRef)i420ToPixelBuffer:(void *)srcY srcU:(void *)srcU srcV:(void *)srcV width:(int)width height:(int)height; + ++ (NSData *)dataFromPixelBuffer:(CVPixelBufferRef)pixelBuffer; + ++ (nullable UIImage *)i420ToImage:(nullable void *)srcY srcU:(nullable void *)srcU srcV:(nullable void *)srcV width:(int)width height:(int)height; ++ (nullable UIImage *)pixelBufferToImage:(CVPixelBufferRef)pixelBuffer; + ++ (CVPixelBufferRef)CVPixelBufferRefFromUiImage:(UIImage *)img; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/MediaUtils.m b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/MediaUtils.m new file mode 100644 index 000000000..3a078b7ff --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/MediaUtils.m @@ -0,0 +1,255 @@ +// +// MediaUtils.m +// APIExample +// +// Created by Arlin on 2022/4/12. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +#import "MediaUtils.h" +#import + +@implementation MediaUtils + ++ (CVPixelBufferRef)i420ToPixelBuffer:(void *)srcY srcU:(void *)srcU srcV:(void *)srcV width:(int)width height:(int)height { + int size = width * height * 3 / 2; + int yLength = width * height; + int uLength = yLength / 4; + if (srcY == NULL) { + return nil; + } + unsigned char *buf = (unsigned char *)malloc(size); + memcpy(buf, srcY, yLength); + memcpy(buf + yLength, srcU, uLength); + memcpy(buf + yLength + uLength, srcV, uLength); + + unsigned char * NV12buf = (unsigned char *)malloc(size); + [self yuv420p_to_nv12:buf nv12:NV12buf width:width height:height]; + + free(buf); + + int w = width; + int h = height; + NSDictionary *pixelAttributes = @{(NSString*)kCVPixelBufferIOSurfacePropertiesKey:@{}}; + CVPixelBufferRef pixelBuffer = NULL; + CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault, + w, + h, + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, + (__bridge CFDictionaryRef)(pixelAttributes), + &pixelBuffer); + if (result != kCVReturnSuccess) { + NSLog(@"Unable to create cvpixelbuffer %d", result); + free(NV12buf); + return nil; + } + + CVPixelBufferLockBaseAddress(pixelBuffer,0); + void *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); + + // Here y_ch0 is Y-Plane of YUV(NV12) data. + unsigned char *y_ch0 = NV12buf; + unsigned char *y_ch1 = NV12buf + w * h; + memcpy(yDestPlane, y_ch0, w * h); + void *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1); + + // Here y_ch1 is UV-Plane of YUV(NV12) data. + memcpy(uvDestPlane, y_ch1, w * h * 0.5); + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + + free(NV12buf); + return pixelBuffer; +} + + ++ (NSData *)dataFromPixelBuffer:(CVPixelBufferRef)pixelBuffer { + NSMutableData* YUVMutData; + CVPixelBufferLockBaseAddress(pixelBuffer, 0); + unsigned char* yBaseAddress = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); + int32_t yBytesPerRow = (int32_t)CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + int32_t width __unused = (int32_t)CVPixelBufferGetWidth(pixelBuffer); + int32_t height = (int32_t)CVPixelBufferGetHeight(pixelBuffer); + int32_t yLength = yBytesPerRow*height; + YUVMutData = [NSMutableData dataWithBytes: yBaseAddress length: yLength]; + + unsigned char* uvBaseAddress = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1); + int32_t uvBytesPerRow = (int32_t)CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1); + int32_t uvLength = uvBytesPerRow*height/2; + NSMutableData* UVData = [NSMutableData dataWithBytes: uvBaseAddress length: uvLength]; + [YUVMutData appendData:UVData]; + NSData* YUVData = [NSData dataWithData:YUVMutData]; + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + return YUVData; +} + ++ (UIImage *)i420ToImage:(void *)srcY srcU:(void *)srcU srcV:(void *)srcV width:(int)width height:(int)height { + int size = width * height * 3 / 2; + int yLength = width * height; + int uLength = yLength / 4; + + unsigned char *buf = (unsigned char *)malloc(size); + memcpy(buf, srcY, yLength); + memcpy(buf + yLength, srcU, uLength); + memcpy(buf + yLength + uLength, srcV, uLength); + + unsigned char * NV12buf = (unsigned char *)malloc(size); + [self yuv420p_to_nv12:buf nv12:NV12buf width:width height:height]; + + free(buf); + + int w = width; + int h = height; + NSDictionary *pixelAttributes = @{(NSString*)kCVPixelBufferIOSurfacePropertiesKey:@{}}; + CVPixelBufferRef pixelBuffer = NULL; + CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault, + w, + h, + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, + (__bridge CFDictionaryRef)(pixelAttributes), + &pixelBuffer); + if (result != kCVReturnSuccess) { + NSLog(@"Unable to create cvpixelbuffer %d", result); + free(NV12buf); + return nil; + } + + CVPixelBufferLockBaseAddress(pixelBuffer,0); + void *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); + + // Here y_ch0 is Y-Plane of YUV(NV12) data. + unsigned char *y_ch0 = NV12buf; + unsigned char *y_ch1 = NV12buf + w * h; + memcpy(yDestPlane, y_ch0, w * h); + void *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1); + + // Here y_ch1 is UV-Plane of YUV(NV12) data. + memcpy(uvDestPlane, y_ch1, w * h * 0.5); + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + + // CIImage Conversion + CIImage *coreImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; + CIContext *temporaryContext = [CIContext contextWithOptions:nil]; + CGImageRef videoImage = [temporaryContext createCGImage:coreImage + fromRect:CGRectMake(0, 0, w, h)]; + + UIImage *finalImage = [[UIImage alloc] initWithCGImage:videoImage]; + CVPixelBufferRelease(pixelBuffer); + CGImageRelease(videoImage); + + free(NV12buf); + return finalImage; +} + ++ (UIImage *)pixelBufferToImage: (CVPixelBufferRef)pixelBuffer { + size_t width = CVPixelBufferGetHeight(pixelBuffer); + size_t height = CVPixelBufferGetWidth(pixelBuffer); + + CIImage *coreImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; + CIContext *temporaryContext = [CIContext contextWithOptions:nil]; + CGImageRef videoImage = [temporaryContext createCGImage:coreImage + fromRect:CGRectMake(0, 0, height, width)]; + + UIImage *finalImage = [[UIImage alloc] initWithCGImage:videoImage + scale:1.0 + orientation:UIImageOrientationUp]; + // CVPixelBufferRelease(pixelBuffer); + CGImageRelease(videoImage); + return finalImage; +} + +static OSType inputPixelFormat(){ + return kCVPixelFormatType_32BGRA; +} + +static uint32_t bitmapInfoWithPixelFormatType(OSType inputPixelFormat, bool hasAlpha){ + + if (inputPixelFormat == kCVPixelFormatType_32BGRA) { + uint32_t bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + if (!hasAlpha) { + bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + } + return bitmapInfo; + }else if (inputPixelFormat == kCVPixelFormatType_32ARGB) { + uint32_t bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; + return bitmapInfo; + }else{ + NSLog(@"不支持此格式"); + return 0; + } +} + +// alpha的判断 +BOOL CGImageRefContainsAlpha(CGImageRef imageRef) { + if (!imageRef) { + return NO; + } + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); + BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || + alphaInfo == kCGImageAlphaNoneSkipFirst || + alphaInfo == kCGImageAlphaNoneSkipLast); + return hasAlpha; +} + ++ (CVPixelBufferRef)CVPixelBufferRefFromUiImage:(UIImage *)img { + CGSize size = img.size; + if (size.width <= 0 || size.height <= 0) { + return nil; + } + CGImageRef image = [img CGImage]; + + BOOL hasAlpha = CGImageRefContainsAlpha(image); + CFDictionaryRef empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, + [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, + empty, kCVPixelBufferIOSurfacePropertiesKey, + nil]; + CVPixelBufferRef pxbuffer = NULL; + CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, inputPixelFormat(), (__bridge CFDictionaryRef) options, &pxbuffer); + + NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); + + CVPixelBufferLockBaseAddress(pxbuffer, 0); + void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); + NSParameterAssert(pxdata != NULL); + + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + + uint32_t bitmapInfo = bitmapInfoWithPixelFormatType(inputPixelFormat(), (bool)hasAlpha); + + CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, CVPixelBufferGetBytesPerRow(pxbuffer), rgbColorSpace, bitmapInfo); + NSParameterAssert(context); + + CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); + CVPixelBufferUnlockBaseAddress(pxbuffer, 0); + + CGColorSpaceRelease(rgbColorSpace); + CGContextRelease(context); + + return pxbuffer; +} + + + ++ (void)yuv420p_to_nv12:(unsigned char*)yuv420p nv12:(unsigned char*)nv12 width:(int)width height:(int)height { + int i, j; + int y_size = width * height; + + unsigned char* y = yuv420p; + unsigned char* u = yuv420p + y_size; + unsigned char* v = yuv420p + y_size * 5 / 4; + + unsigned char* y_tmp = nv12; + unsigned char* uv_tmp = nv12 + y_size; + + memcpy(y_tmp, y, y_size); + + for (j = 0, i = 0; j < y_size * 0.5; j += 2, i++) { + uv_tmp[j] = u[i]; + uv_tmp[j+1] = v[i]; + } +} + + +@end diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/Util.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/Util.swift new file mode 100644 index 000000000..f43acbcf7 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/Utils/Util.swift @@ -0,0 +1,33 @@ +// +// Util.swift +// APIExample +// +// Created by zhaoyongqiang on 2022/10/14. +// Copyright © 2022 Agora Corp. All rights reserved. +// + +import UIKit +import AgoraRtcKit + +enum Util { + /// Configuring Privatization Parameters + static func configPrivatization(agoraKit: AgoraRtcEngineKit) { + if !GlobalSettings.shared.getCache(key: "ip").isEmpty { + let localAccessPointConfig = AgoraLocalAccessPointConfiguration() + localAccessPointConfig.ipList = ["\(GlobalSettings.shared.getCache(key: "ip"))"] + localAccessPointConfig.mode = .localOnly + if GlobalSettings.shared.getCache(key: "report") { + let advancedConfig = AdvancedConfigInfo() + let logUploadServer = LogUploadServerInfo() + logUploadServer.serverDomain = GlobalSettings.shared.getCache(key: "log_server_domain") + logUploadServer.serverPort = GlobalSettings.shared.getCache(key: "log_server_port") + logUploadServer.serverPath = GlobalSettings.shared.getCache(key: "log_server_path") + logUploadServer.serverHttps = GlobalSettings.shared.getCache(key: "log_server_https") + advancedConfig.logUploadServer = logUploadServer + localAccessPointConfig.advancedConfig = advancedConfig + } + // This api can only be used in the private media server scenario, otherwise some problems may occur. + agoraKit.setLocalAccessPoint(withConfig: localAccessPointConfig) + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/VideoUIView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/VideoUIView.swift new file mode 100644 index 000000000..66fccf774 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/VideoUIView.swift @@ -0,0 +1,337 @@ +// +// VideoUIView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import UIKit +import SwiftUI + +enum StreamType { + case local + case remote + + func isLocal() -> Bool { + switch self { + case .local: return true + case .remote: return false + } + } + + var value: String { + switch self { + case .local: "Local Host".localized + case .remote: "Remote Host".localized + } + } +} + +class VideoUIView: UIView, Identifiable { + let id = UUID() + lazy var videoView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + private lazy var placeHolderLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 14) + label.translatesAutoresizingMaskIntoConstraints = false + label.numberOfLines = 0 + return label + }() + private lazy var statsLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 10) + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = UIScreen.main.bounds.width * 0.5 * 0.7 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(placeHolderLabel) + placeHolderLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true + placeHolderLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + addSubview(videoView) + videoView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + videoView.topAnchor.constraint(equalTo: topAnchor).isActive = true + videoView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + videoView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + + addSubview(statsLabel) + statsLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 5).isActive = true + statsLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -5).isActive = true + } + + var audioOnly: Bool = false + var uid: UInt = 0 { + didSet { + switch type { + case .local: + statsInfo?.uid = uid + case .remote: + statsInfo?.remoteUid = uid + } + } + } + + var statsInfo: StatisticsInfo? { + didSet { + if Thread.isMainThread { + statsLabel.text = statsInfo?.description(audioOnly: audioOnly) ?? "" + } else { + DispatchQueue.main.async { + self.statsLabel.text = self.statsInfo?.description(audioOnly: self.audioOnly) ?? "" + } + } + } + } + var type: StreamType = .local { + didSet { + if type.isLocal() { + statsInfo = StatisticsInfo(type: .local(StatisticsInfo.LocalInfo())) + } else { + statsInfo = StatisticsInfo(type: .remote(StatisticsInfo.RemoteInfo())) + } + if audioOnly { + placeHolderLabel.text = getAudioLabel(isLocal: type.isLocal()) + } else { + placeHolderLabel.text = type.value + } + } + } + + func setPlaceholder(text: String?) { + placeHolderLabel.text = text + } + + func setInfo(text: String?) { + statsLabel.text = text + } + + private func getAudioLabel(isLocal: Bool) -> String { + return "AUDIO ONLY\n\(isLocal ? "Local" : "Remote")" + } +} + + +class SampleBufferDisplayView: UIView { + var videoView: AgoraSampleBufferRender = { + let view = AgoraSampleBufferRender(frame: .zero) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + private lazy var placeHolderLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 14) + label.translatesAutoresizingMaskIntoConstraints = false + label.numberOfLines = 0 + return label + }() + private lazy var statsLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 10) + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = UIScreen.main.bounds.width * 0.5 * 0.7 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(placeHolderLabel) + placeHolderLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true + placeHolderLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + addSubview(videoView) + videoView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + videoView.topAnchor.constraint(equalTo: topAnchor).isActive = true + videoView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + videoView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + + addSubview(statsLabel) + statsLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 5).isActive = true + statsLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -5).isActive = true + } + + var audioOnly: Bool = false + var uid: UInt = 0 { + didSet { + switch type { + case .local: + statsInfo?.uid = uid + case .remote: + statsInfo?.remoteUid = uid + } + } + } + + var statsInfo: StatisticsInfo? { + didSet { + if Thread.isMainThread { + statsLabel.text = statsInfo?.description(audioOnly: audioOnly) ?? "" + } else { + DispatchQueue.main.async { + self.statsLabel.text = self.statsInfo?.description(audioOnly: self.audioOnly) ?? "" + } + } + } + } + var type: StreamType = .local { + didSet { + if type.isLocal() { + statsInfo = StatisticsInfo(type: .local(StatisticsInfo.LocalInfo())) + } else { + statsInfo = StatisticsInfo(type: .remote(StatisticsInfo.RemoteInfo())) + } + if audioOnly { + placeHolderLabel.text = getAudioLabel(isLocal: type.isLocal()) + } else { + placeHolderLabel.text = type.value + } + } + } + + func setPlaceholder(text: String?) { + placeHolderLabel.text = text + } + + func setInfo(text: String?) { + statsLabel.text = text + } + + private func getAudioLabel(isLocal: Bool) -> String { + return "AUDIO ONLY\n\(isLocal ? "Local" : "Remote")" + } +} + + +class MetalVideoView: UIView { + lazy var videoView: AgoraMetalRender = { + let view = AgoraMetalRender(frame: .zero) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + private lazy var placeHolderLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 14) + label.translatesAutoresizingMaskIntoConstraints = false + label.numberOfLines = 0 + return label + }() + private lazy var statsLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 10) + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = UIScreen.main.bounds.width * 0.5 * 0.7 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(placeHolderLabel) + placeHolderLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true + placeHolderLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + addSubview(videoView) + videoView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + videoView.topAnchor.constraint(equalTo: topAnchor).isActive = true + videoView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + videoView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + + addSubview(statsLabel) + statsLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 5).isActive = true + statsLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -5).isActive = true + } + + var audioOnly: Bool = false + var uid: UInt = 0 { + didSet { + switch type { + case .local: + statsInfo?.uid = uid + case .remote: + statsInfo?.remoteUid = uid + } + } + } + + var statsInfo: StatisticsInfo? { + didSet { + if Thread.isMainThread { + statsLabel.text = statsInfo?.description(audioOnly: audioOnly) ?? "" + } else { + DispatchQueue.main.async { + self.statsLabel.text = self.statsInfo?.description(audioOnly: self.audioOnly) ?? "" + } + } + } + } + var type: StreamType = .local { + didSet { + if type.isLocal() { + statsInfo = StatisticsInfo(type: .local(StatisticsInfo.LocalInfo())) + } else { + statsInfo = StatisticsInfo(type: .remote(StatisticsInfo.RemoteInfo())) + } + if audioOnly { + placeHolderLabel.text = getAudioLabel(isLocal: type.isLocal()) + } else { + placeHolderLabel.text = type.value + } + } + } + + func setPlaceholder(text: String?) { + placeHolderLabel.text = text + } + + func setInfo(text: String?) { + statsLabel.text = text + } + + private func getAudioLabel(isLocal: Bool) -> String { + return "AUDIO ONLY\n\(isLocal ? "Local" : "Remote")" + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/VideoView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/VideoView.swift new file mode 100644 index 000000000..6468468d4 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/VideoView.swift @@ -0,0 +1,57 @@ +// +// VideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/18. +// + +import SwiftUI + +struct VideoView: UIViewRepresentable, Identifiable { + @State var type: StreamType = .local + @State var audioOnly: Bool = false + let videoView = VideoUIView() + let id = UUID() + + func makeUIView(context: Context) -> UIView { + return videoView + } + + func updateUIView(_ uiView: UIView, context: Context) { + let videoView = uiView as? VideoUIView + videoView?.audioOnly = audioOnly + videoView?.type = type + } +} + +struct SampleBufferView: UIViewRepresentable { + @State var type: StreamType = .local + @State var audioOnly: Bool = false + let videoView = SampleBufferDisplayView() + + func makeUIView(context: Context) -> UIView { + return videoView + } + + func updateUIView(_ uiView: UIView, context: Context) { + let videoView = uiView as? SampleBufferDisplayView + videoView?.audioOnly = audioOnly + videoView?.type = type + } +} + +struct MetalRenderView: UIViewRepresentable { + @State var type: StreamType = .local + @State var audioOnly: Bool = false + let videoView = MetalVideoView() + + func makeUIView(context: Context) -> UIView { + return videoView + } + + func updateUIView(_ uiView: UIView, context: Context) { + let videoView = uiView as? MetalVideoView + videoView?.audioOnly = audioOnly + videoView?.type = type + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/View/PickerSheetView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/View/PickerSheetView.swift new file mode 100644 index 000000000..6d2f09184 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Common/View/PickerSheetView.swift @@ -0,0 +1,45 @@ +// +// PickerSheetView.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/25. +// + +import SwiftUI + +struct PickerSheetView: View { + @Binding var selectedOption: String + var options: [String] + @Binding var isPresented: Bool + var onSave: (String) -> Void + + var body: some View { + NavigationView { + VStack { + Picker("请选择一个选项", selection: $selectedOption) { + ForEach(options, id: \.self) { option in + Text(option).tag(option) + } + } + .pickerStyle(WheelPickerStyle()) + .labelsHidden() + } + .navigationBarTitle("选择器", displayMode: .inline) + .navigationBarItems( + leading: Button("取消") { + isPresented = false + }, + trailing: Button("确定") { + onSave(selectedOption) + isPresented = false + } + ) + } + .onAppear { + if selectedOption.isEmpty, let firstOption = options.first { + selectedOption = firstOption + } + } + } +} + diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/ContentView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/ContentView.swift new file mode 100644 index 000000000..3669a9a17 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/ContentView.swift @@ -0,0 +1,131 @@ +// +// ContentView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/18. +// + +import SwiftUI + +struct MenuSection: Identifiable { + let id = UUID() + var name: String + var rows: [MenuItem] +} + +struct MenuItem: Identifiable { + let id = UUID() + var name: String + var view: AnyView + init(name: String, view: AnyView) { + self.name = name + self.view = view + } +} + +struct ContentView: View { + var menus: [MenuSection] = [ + MenuSection(name: "Basic", rows: [ + MenuItem(name: "Join a channel (Token)".localized, + view: AnyView(JoinChannelVideoTokenEntry())), + MenuItem(name: "Join a channel (Video)".localized, + view: AnyView(JoinChannelVideoEntry())), + MenuItem(name: "Join a channel (Audio)".localized, + view: AnyView(JoinChannelAudioEntry())), + MenuItem(name: "Local or remote recording".localized, + view: AnyView(JoinChannelVideoRecorderEntry())) + ]), + MenuSection(name: "Anvanced", rows: [ + MenuItem(name: "Live Streaming".localized, + view: AnyView(LiveStreamingEntry())), + MenuItem(name: "Video Metadata".localized, + view: AnyView(VideoMetadataEntry())), + MenuItem(name: "Custom Audio Source(PCM)".localized, + view: AnyView(CustomPCMAudioSourceEntry())), + MenuItem(name: "Raw Audio Data".localized, + view: AnyView(RawAudioDataEntry())), + MenuItem(name: "Raw Video Data".localized, + view: AnyView(RawVideoDataEntry())), + MenuItem(name: "Local Video Transcoding".localized, + view: AnyView(LocalVideoTranscodingEntry())), + MenuItem(name: "Voice Changer".localized, + view: AnyView(VoiceChangerEntry())), + MenuItem(name: "RTMP Streaming".localized, + view: AnyView(RTMPStreamEntry())), + MenuItem(name: "Custom Audio Render".localized, + view: AnyView(CustomAudioRenderEntry())), + MenuItem(name: "Picture In Picture".localized, + view: AnyView(PictureInPictureEntry())), + MenuItem(name: "Quick Switch Channel".localized, + view: AnyView(QuickSwitchChannelEntry())), + MenuItem(name: "Join Multiple Channels".localized, + view: AnyView(JoinMultiChannelEntry())), + MenuItem(name: "Stream Encryption".localized, + view: AnyView(StreamEncryptionEntry())), + MenuItem(name: "Audio Mixing".localized, + view: AnyView(AudioMixingEntry())), + MenuItem(name: "Precall Test".localized, + view: AnyView(PrecallTest())), + MenuItem(name: "Media Player".localized, + view: AnyView(MediaPlayerEntry())), + MenuItem(name: "Screen Share".localized, + view: AnyView(ScreenShareEntry())), + MenuItem(name: "Video Process".localized, + view: AnyView(VideoProcessEntry())), + MenuItem(name: "Rhythm Player".localized, + view: AnyView(RhythmPlayerEntry())), + MenuItem(name: "Create Data Stream".localized, + view: AnyView(CreateDataStreamEntry())), + MenuItem(name: "Media Channel Relay".localized, + view: AnyView(MediaChannelRelayEntry())), + MenuItem(name: "Spatial Audio".localized, + view: AnyView(SpatialAudioEntry())), + MenuItem(name: "Content Inspect".localized, + view: AnyView(ContentInspectEntry())), + MenuItem(name: "Mutli Camera(iOS13.0+)".localized, + view: AnyView(MutliCameraEntry())), + MenuItem(name: "Ktv copyright music".localized, + view: AnyView(KtvCopyrightMusic())), + MenuItem(name: "ARKit".localized, + view: AnyView(ARKitEntry())), + MenuItem(name: "Audio Waveform".localized, + view: AnyView(AudioWaveformEntry())), + MenuItem(name: "Face Capture".localized, + view: AnyView(FaceCaptureEntry())) + ]) + ] + + var body: some View { + NavigationView { + List { + ForEach(menus) { section in + Section(header: Text(section.name)) { + ForEach(section.rows) { item in + NavigationLink(destination: { + item.view.navigationTitle(item.name) + }) { + Text(item.name) + } + } + } + } + } + .listStyle(GroupedListStyle()) + .navigationTitle("Agora API Example") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + NavigationLink(destination: { + SettingsView() + }) { + Text("Settings").foregroundStyle(.black) + } + } + } + } + } +} + +#Preview { + ContentView() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ARKit/ARKit.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ARKit/ARKit.swift new file mode 100644 index 000000000..655e92f21 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ARKit/ARKit.swift @@ -0,0 +1,134 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI +import ARKit + +struct ARKitEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + @State private var isOn: Bool = false + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + HStack(spacing: 15, content: { + HStack(spacing: 10, content: { + Text("First Frame Optimization".localized) + Toggle("", isOn: $isOn).frame(width: 50) + }).padding(.leading, 25) + Spacer() + Button { + configs = ["channelName": channelName, + "isFirstFrame": isOn] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + }) + Spacer() + NavigationLink(destination: ARKit(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + ARKitEntry() +} + +struct ARViewWrapper: UIViewRepresentable { + let arView = ARSCNView() + var statsLabel: UILabel = { + let label = UILabel() + label.text = "" + label.textColor = .black + label.font = .systemFont(ofSize: 14) + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = 200 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + var infoLabel: UILabel = { + let label = UILabel() + label.text = "Move Camera to find a planar \n(Shown as Red Rectangle)".localized + label.textColor = .white + label.font = .systemFont(ofSize: 14) + label.numberOfLines = 0 + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + func makeUIView(context: Context) -> ARSCNView { + // Set up ARSCNView configuration here + arView.addSubview(infoLabel) + arView.addSubview(statsLabel) + infoLabel.leadingAnchor.constraint(equalTo: arView.leadingAnchor, constant: 35).isActive = true + infoLabel.trailingAnchor.constraint(equalTo: arView.trailingAnchor, constant: -35).isActive = true + infoLabel.centerYAnchor.constraint(equalTo: arView.centerYAnchor).isActive = true + + statsLabel.leadingAnchor.constraint(equalTo: arView.leadingAnchor, constant: 15).isActive = true + statsLabel.bottomAnchor.constraint(equalTo: arView.bottomAnchor, constant: -15).isActive = true + + return arView + } + + func updateUIView(_ uiView: ARSCNView, context: Context) { + // Update ARSCNView here if needed + } +} + +struct ARKit: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = ARKitRTC() + @GestureState private var tappedLocation: CGPoint = .zero + + let sceneView = ARViewWrapper() + + var body: some View { + VStack { + sceneView.background(ignoresSafeAreaEdges: .all).alert(isPresented: $agoraKit.isSupportedAR) { + let message = "This app requires world tracking, which is available only on iOS devices with the A9 processor or later.".localized + return Alert(title: Text("ARKit is not available on this device.".localized), message: Text(message), dismissButton: .cancel()) + }.onReceive(agoraKit.$planarDetected, perform: { _ in + if agoraKit.planarDetected { + sceneView.infoLabel.text = "Tap to place remote video canvas".localized + } else { + sceneView.infoLabel.text = "Move Camera to find a planar\n(Shown as Red Rectangle)".localized + } + }).onReceive(agoraKit.$isHiddenStatsLabel, perform: { _ in + sceneView.statsLabel.isHidden = agoraKit.isHiddenStatsLabel + sceneView.statsLabel.text = agoraKit.stats + }).onTapGesture { + agoraKit.doSceneViewTapped(tappedLocation) + }.gesture(DragGesture(minimumDistance: 0) + .updating($tappedLocation) { (value, state, _) in + state = value.startLocation + } + ) + + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + sceneView: sceneView.arView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + ARKit(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ARKit/ARKitRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ARKit/ARKitRTC.swift new file mode 100644 index 000000000..dd69d1252 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ARKit/ARKitRTC.swift @@ -0,0 +1,293 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI +import ARKit + +class ARKitRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var renderer: ARVideoRenderer! + + private var unusedScreenNodes = [SCNNode]() + private var undisplayedUsers = [UInt]() + private var activeScreens = [UInt: SCNNode]() + private var sceneView: ARSCNView? + + @Published var planarDetected: Bool = false + @Published var isSupportedAR: Bool = false + @Published var isHiddenStatsLabel: Bool = false + @Published var stats: String = "" + + + func setupRTC(configs: [String: Any], sceneView: ARSCNView) { + self.sceneView = sceneView + // set AR Scene delegate + sceneView.delegate = self + sceneView.session.delegate = self + sceneView.showsStatistics = true + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + + if let isFirstFrame = configs["isFirstFrame"] as? Bool, isFirstFrame == true { + agoraKit.enableInstantMediaRendering() + agoraKit.startMediaRenderingTracing() + } + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + renderer = ARVideoRenderer() + agoraKit.setVideoFrameDelegate(renderer) + // start AR Session + startARSession() + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + // start AR World tracking + func startARSession() { + guard ARWorldTrackingConfiguration.isSupported else { + isSupportedAR = false + return + } + + let configuration = ARWorldTrackingConfiguration() + configuration.planeDetection = .horizontal + // remember to set this to false, or ARKit may conflict with Agora SDK + configuration.providesAudioData = false + + // start session + sceneView?.session.run(configuration) + } + + // stop AR Tracking + func stopARSession() { + sceneView?.session.pause() + } + + func doSceneViewTapped(_ location: CGPoint) { + if !planarDetected { + LogUtils.log(message: "Planar not yet found", level: .warning) + return + } + + if let node = sceneView?.hitTest(location, options: nil).first?.node { + removeNode(node) + } else if let query = sceneView?.raycastQuery(from: location, allowing: .estimatedPlane, alignment: .any), let result = sceneView?.session.raycast(query).first { + addNode(withTransform: result.worldTransform) + } + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + stopARSession() + AgoraRtcEngineKit.destroy() + } +} + +private extension ARKitRTC { + func renderRemoteUser(uid: UInt, toNode node: SCNNode) { + renderer.renderNode = node + activeScreens[uid] = node + } + func addNode(withTransform transform: matrix_float4x4) { + guard let scene = SCNScene(named: "AR.scnassets/displayer.scn") else { return } + let rootNode = scene.rootNode + rootNode.position = SCNVector3( + transform.columns.3.x, + transform.columns.3.y, + transform.columns.3.z + ) + guard let currentFrame = sceneView?.session.currentFrame else { return } + rootNode.rotation = SCNVector4(0, 1, 0, currentFrame.camera.eulerAngles.y) + sceneView?.scene.rootNode.addChildNode(rootNode) + let displayer = rootNode.childNode(withName: "displayer", + recursively: false) + guard let screen = displayer?.childNode(withName: "screen", + recursively: false) else { return } + if let undisplayedUid = undisplayedUsers.first { + undisplayedUsers.removeFirst() + renderRemoteUser(uid: undisplayedUid, toNode: screen) + } else { + unusedScreenNodes.append(screen) + } + } + func removeNode(_ node: SCNNode) { + let rootNode: SCNNode + let screen: SCNNode + if node.name == "screen", let parent = node.parent?.parent { + rootNode = parent + screen = node + } else if node.name == "displayer", let parent = node.parent { + rootNode = parent + screen = parent.childNode(withName: "screen", recursively: false) ?? SCNNode() + } else { + rootNode = node + screen = node + } + rootNode.removeFromParentNode() + if let index = unusedScreenNodes.firstIndex(where: {$0 == screen}) { + unusedScreenNodes.remove(at: index) + } + if let (uid, _) = activeScreens.first(where: {$1 == screen}) { + activeScreens.removeValue(forKey: uid) + if let screenNode = unusedScreenNodes.first { + unusedScreenNodes.removeFirst() + renderRemoteUser(uid: uid, toNode: screenNode) + } else { + undisplayedUsers.insert(uid, at: 0) + } + } + } +} + +// agora rtc engine delegate events +extension ARKitRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + // Only one remote video view is available for this + // tutorial. Here we check if there exists a surface + // view tagged as this uid. + if let screenNode = unusedScreenNodes.first { + unusedScreenNodes.removeFirst() + renderRemoteUser(uid: uid, toNode: screenNode) + } else { + undisplayedUsers.append(uid) + } + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + if let screenNode = activeScreens[uid] { +// agoraKit.setRemoteVideoRenderer(nil, forUserId: uid) + unusedScreenNodes.insert(screenNode, at: 0) + activeScreens[uid] = nil + } else if let index = undisplayedUsers.firstIndex(of: uid) { + undisplayedUsers.remove(at: index) + } + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, + videoRenderingTracingResultOfUid uid: UInt, + currentEvent: AgoraMediaTraceEvent, + tracingInfo: AgoraVideoRenderingTracingInfo) { + isHiddenStatsLabel = tracingInfo.elapsedTime <= 0 + stats = "firstFrameTime: \(tracingInfo.elapsedTime)" + } +} + +extension ARKitRTC: ARSCNViewDelegate { + func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { + guard let planeAnchor = anchor as? ARPlaneAnchor else { + return + } + + let plane = SCNBox(width: CGFloat(planeAnchor.extent.x), + height: CGFloat(planeAnchor.extent.y), + length: CGFloat(planeAnchor.extent.z), + chamferRadius: 0) + plane.firstMaterial?.diffuse.contents = UIColor.red + + let planeNode = SCNNode(geometry: plane) + node.addChildNode(planeNode) + planeNode.runAction(SCNAction.fadeOut(duration: 3)) + + // found planar + if !planarDetected { + DispatchQueue.main.async {[weak self] in + guard let weakSelf = self else { + return + } + weakSelf.planarDetected = true + } + } + } +} + +extension ARKitRTC: ARSessionDelegate { + func session(_ session: ARSession, didUpdate frame: ARFrame) { + // send captured image to remote device + renderer.pixelBuffer = frame.capturedImage + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioMixing/AudioMixing.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioMixing/AudioMixing.swift new file mode 100644 index 000000000..e53d792d9 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioMixing/AudioMixing.swift @@ -0,0 +1,220 @@ +// +// JoinchannelVideoEnter.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI +import AgoraRtcKit + +struct AudioMixingEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var isShowAudioScence: Bool = false + @State private var isShowAudioProfile: Bool = false + @State private var profile: AgoraAudioProfile = .default + @State private var scenario: AgoraAudioScenario = .default + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + HStack { + Text("Audio Scenario".localized) + Spacer() + Button { + self.isShowAudioProfile = true + } label: { + Text(scenario.description()) + }.confirmationDialog("Set Audio Scenario".localized, isPresented: $isShowAudioProfile, titleVisibility: .visible) { + ForEach(AgoraAudioScenario.allValues(), id: \.self) { item in + getAudioScenarioAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 15, trailing: 35)) + HStack { + Text("Audio Profile".localized) + Spacer() + Button(profile.description()) { + self.isShowAudioScence = true + }.confirmationDialog("Set Audio Profile".localized, isPresented: $isShowAudioScence, titleVisibility: .visible) { + ForEach(AgoraAudioProfile.allValues(), id: \.self) { item in + getAudioProfileAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 0, trailing: 35)) + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName, + "audioProfile": profile, + "audioScenario": scenario] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: AudioMixing(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } + + private func getAudioProfileAction(_ profile: AgoraAudioProfile) -> some View { + Button(profile.description()){ + self.profile = profile + } + } + + private func getAudioScenarioAction(_ scenario: AgoraAudioScenario) -> some View { + Button(scenario.description()){ + self.scenario = scenario + } + } +} + +#Preview { + AudioMixingEntry() +} + +struct AudioMixing: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = AudioMixingRTC() + @State private var audioMixingVolumeSlider: Double = 50 + + var localView = VideoView(type: .local, + audioOnly: true) + var remoteView = VideoView(type: .remote, + audioOnly: true) + + @State private var isStartAudioMix: Bool = false + @State private var isPauseAudioMix: Bool = false + @State private var isStartEffect: Bool = false + @State private var isPauseEffect: Bool = false + + var body: some View { + VStack { + ScrollView { + HStack{ + localView + remoteView + }.frame(height: 200) + HStack { + Text("Audio Mixing Controls".localized) + .font(.title) + .padding(15) + Spacer() + } + HStack { + ProgressView(value: agoraKit.progress, + total: 1.0) + Text(agoraKit.audioMixingDuration).padding(.horizontal, 10) + }.padding(.horizontal, 15) + + HStack { + Button("Start".localized) { + agoraKit.onStartAudioMixing() + isStartAudioMix = true + }.disabled(isStartAudioMix) + Spacer() + Button("Resume".localized) { + agoraKit.onResumeAudioMixing() + isPauseAudioMix = false + }.disabled(!isPauseAudioMix) + Spacer() + Button("Pause".localized) { + agoraKit.onPauseAudioMixing() + isPauseAudioMix = true + }.disabled(!isStartAudioMix || isPauseAudioMix) + Spacer() + Button("Stop".localized) { + agoraKit.onStopAudioMixing() + isStartAudioMix = false + isPauseAudioMix = false + }.disabled(!isStartAudioMix) + } + .padding(.horizontal, 15) + .padding(.vertical, 10) + + HStack { + Text("MixingVolume".localized) + Spacer() + Slider(value: $audioMixingVolumeSlider, in: 0...100, step: 1).onChange(of: audioMixingVolumeSlider) { value in + agoraKit.onChangeAudioMixingVolume(value) + }.frame(maxWidth: 150) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + + HStack { + Text("MixingPlaybackVolume".localized) + Spacer() + Slider(value: $agoraKit.audioMixingPlaybackVolumeSlider, in: 0...100, step: 1).onChange(of: agoraKit.audioMixingPlaybackVolumeSlider) { value in + agoraKit.onChangeAudioMixingPlaybackVolume(value) + }.frame(maxWidth: 150) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + + HStack { + Text("MixingPublishVolume".localized) + Spacer() + Slider(value: $agoraKit.audioMixingPublishVolumeSlider, in: 0...100, step: 1).onChange(of: agoraKit.audioMixingPublishVolumeSlider) { value in + agoraKit.onChangeAudioMixingPublishVolume(value) + }.frame(maxWidth: 150) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + + HStack { + Text("Audio Effect Controls".localized) + .font(.title) + .padding(15) + Spacer() + } + HStack { + Button("Play".localized) { + agoraKit.onPlayEffect() + isStartEffect = true + }.disabled(isStartEffect) + Spacer() + Button("Resume".localized) { + agoraKit.onResumeEffect() + isPauseEffect = false + }.disabled(!isPauseEffect) + Spacer() + Button("Pause".localized) { + agoraKit.onPauseEffect() + isPauseEffect = true + }.disabled(!isStartEffect || isPauseEffect) + Spacer() + Button("Stop".localized) { + agoraKit.onStopEffect() + isStartEffect = false + isPauseEffect = false + }.disabled(!isStartEffect) + } + .padding(.horizontal, 15) + .padding(.vertical, 10) + HStack { + Text("EffectVolume".localized) + Spacer() + Slider(value: $agoraKit.audioEffectVolumeSlider, in: 0...100, step: 1).onChange(of: agoraKit.audioEffectVolumeSlider) { value in + agoraKit.onChangeAudioEffectVolume(value) + }.frame(maxWidth: 150) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 40, trailing: 15)) + } + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + AudioMixing(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioMixing/AudioMixingRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioMixing/AudioMixingRTC.swift new file mode 100644 index 000000000..2d6c5a108 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioMixing/AudioMixingRTC.swift @@ -0,0 +1,354 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +let EFFECT_ID: Int32 = 1 +class AudioMixingRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var timer: Timer? + + @Published var audioMixingPlaybackVolumeSlider: Double = 50 + @Published var audioMixingPublishVolumeSlider: Double = 50 + @Published var audioEffectVolumeSlider: Double = 50 + @Published var progress: Double = 0 + @Published var audioMixingDuration: String = "00:00" + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + guard let channelName = configs["channelName"] as? String, + let audioProfile = configs["audioProfile"] as? AgoraAudioProfile, + let audioScenario = configs["audioScenario"] as? AgoraAudioScenario + else { return } + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + // set audio scenario + config.audioScenario = audioScenario + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + audioMixingPlaybackVolumeSlider = Double(agoraKit.getAudioMixingPlayoutVolume()) + audioMixingPublishVolumeSlider = Double(agoraKit.getAudioMixingPublishVolume()) + audioEffectVolumeSlider = Double(agoraKit.getEffectsVolume()) + + // disable video module + agoraKit.disableVideo() + + agoraKit.enableAudio() + + // set audio profile + agoraKit.setAudioProfile(audioProfile) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // enable volume indicator + agoraKit.enableAudioVolumeIndication(200, smooth: 3, reportVad: true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = true + option.autoSubscribeAudio = true + option.autoSubscribeVideo = false + option.clientRoleType = GlobalSettings.shared.getUserRole() + + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func onChangeAudioMixingVolume(_ value: Double) { + let value = Int(value) + print("adjustAudioMixingVolume \(value)") + agoraKit.adjustAudioMixingVolume(value) + } + + func onChangeAudioMixingPlaybackVolume(_ value: Double) { + let value = Int(value) + print("adjustAudioMixingPlayoutVolume \(value)") + agoraKit.adjustAudioMixingPlayoutVolume(value) + } + + func onChangeAudioMixingPublishVolume(_ value: Double) { + let value = Int(value) + print("adjustAudioMixingPublishVolume \(value)") + agoraKit.adjustAudioMixingPublishVolume(value) + } + + func onChangeAudioEffectVolume(_ value: Double) { + let value = Int(value) + print("setEffectsVolume \(value)") + agoraKit.setEffectsVolume(value) + } + + func onStartAudioMixing() { + if let filepath = Bundle.main.path(forResource: "audiomixing", ofType: "mp3") { + let result = agoraKit.startAudioMixing(filepath, loopback: false, cycle: -1) + if result != 0 { + LogUtils.log(message: "startAudioMixing call failed: \(result), please check your params", level: .error) + } + } + } + + func onStopAudioMixing() { + let result = agoraKit.stopAudioMixing() + if result != 0 { + LogUtils.log(message: "stopAudioMixing call failed: \(result), please check your params", level: .error) + } else { + stopProgressTimer() + updateTotalDuration(reset: true) + } + } + + func onPauseAudioMixing() { + let result = agoraKit.pauseAudioMixing() + if result != 0 { + LogUtils.log(message: "pauseAudioMixing call failed: \(result), please check your params", level: .error) + } else { + stopProgressTimer() + } + } + + func onResumeAudioMixing() { + let result = agoraKit.resumeAudioMixing() + if result != 0 { + LogUtils.log(message: "resumeAudioMixing call failed: \(result), please check your params", level: .error) + } else { + startProgressTimer() + } + } + + func startProgressTimer() { + // begin timer to update progress + if timer == nil { + timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { [weak self] _ in + guard let weakself = self else {return} + let progress = Float(weakself.agoraKit.getAudioMixingCurrentPosition()) / Float(weakself.agoraKit.getAudioMixingDuration()) + weakself.progress = Double(progress) + }) + } + } + + func stopProgressTimer() { + // stop timer + if timer != nil { + timer?.invalidate() + timer = nil + } + } + + func updateTotalDuration(reset: Bool) { + if reset { + audioMixingDuration = "00 : 00" + } else { + let duration = agoraKit.getAudioMixingDuration() + let seconds = duration / 1000 + audioMixingDuration = "\(String(format: "%02d", seconds / 60)) : \(String(format: "%02d", seconds % 60))" + } + } + + func onPlayEffect() { + if let filepath = Bundle.main.path(forResource: "audioeffect", ofType: "mp3") { + let result = agoraKit.playEffect(EFFECT_ID, + filePath: + filepath, + loopCount: -1, + pitch: 1, pan: 0, + gain: 100, + publish: true) + if result != 0 { + LogUtils.log(message: "playEffect call failed: \(result), please check your params", level: .error) + } + } + } + + func onStopEffect() { + let result = agoraKit.stopEffect(EFFECT_ID) + if result != 0 { + LogUtils.log(message: "stopEffect call failed: \(result), please check your params", level: .error) + } + } + + func onPauseEffect() { + let result = agoraKit.pauseEffect(EFFECT_ID) + if result != 0 { + LogUtils.log(message: "pauseEffect call failed: \(result), please check your params", level: .error) + } + } + + func onResumeEffect() { + let result = agoraKit.resumeEffect(EFFECT_ID) + if result != 0 { + LogUtils.log(message: "resumeEffect call failed: \(result), please check your params", level: .error) + } + } + + func onDestory() { + agoraKit.enable(inEarMonitoring: false) + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func setAudioScenario(scenario: AgoraAudioScenario) { + agoraKit.setAudioScenario(scenario) + } + + func onChangeRecordingVolume(_ value: Double) { + let value: Int = Int(value) + print("adjustRecordingSignalVolume \(value)") + agoraKit.adjustRecordingSignalVolume(value) + } + + func onChangePlaybackVolume(_ value: Double) { + let value: Int = Int(value) + print("adjustPlaybackSignalVolume \(value)") + agoraKit.adjustPlaybackSignalVolume(value) + } + + func toggleInEarMonitoring(_ isOn: Bool) { + agoraKit.enable(inEarMonitoring: isOn) + } + + func onChangeInEarMonitoringVolume(_ value: Double) { + let value: Int = Int(value) + print("setInEarMonitoringVolume \(value)") + agoraKit.setInEarMonitoringVolume(value) + } +} + +// agora rtc engine delegate events +extension AudioMixingRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// Reports which users are speaking, the speakers' volumes, and whether the local user is speaking. + /// @params speakers volume info for all speakers + /// @params totalVolume Total volume after audio mixing. The value range is [0,255]. + func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) { +// for speaker in speakers { +// if let audioView = audioViews[speaker.uid] { +// audioView.setInfo(text: "Volume:\(speaker.volume)") +// } +// } + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } + func rtcEngine(_ engine: AgoraRtcEngineKit, + audioMixingStateChanged state: AgoraAudioMixingStateType, + reasonCode: AgoraAudioMixingReasonCode) { + LogUtils.log(message: "audioMixingStateChanged \(state.rawValue), code: \(reasonCode.rawValue)", level: .info) + if state == .playing { + startProgressTimer() + updateTotalDuration(reset: false) + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioWaveform/AudioWaveform.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioWaveform/AudioWaveform.swift new file mode 100644 index 000000000..390f34e76 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioWaveform/AudioWaveform.swift @@ -0,0 +1,132 @@ +// +// JoinchannelVideoEnter.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI +import AgoraRtcKit + +struct AudioWaveformEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var isShowAudioScence: Bool = false + @State private var isShowAudioProfile: Bool = false + @State private var profile: AgoraAudioProfile = .default + @State private var scenario: AgoraAudioScenario = .default + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + HStack { + Text("Audio Scenario".localized) + Spacer() + Button { + self.isShowAudioProfile = true + } label: { + Text(scenario.description()) + }.confirmationDialog("Set Audio Scenario".localized, isPresented: $isShowAudioProfile, titleVisibility: .visible) { + ForEach(AgoraAudioScenario.allValues(), id: \.self) { item in + getAudioScenarioAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 15, trailing: 35)) + HStack { + Text("Audio Profile".localized) + Spacer() + Button(profile.description()) { + self.isShowAudioScence = true + }.confirmationDialog("Set Audio Profile".localized, isPresented: $isShowAudioScence, titleVisibility: .visible) { + ForEach(AgoraAudioProfile.allValues(), id: \.self) { item in + getAudioProfileAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 0, trailing: 35)) + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName, + "audioProfile": profile, + "audioScenario": scenario] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: AudioWaveform(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } + + private func getAudioProfileAction(_ profile: AgoraAudioProfile) -> some View { + Button(profile.description()){ + self.profile = profile + } + } + + private func getAudioScenarioAction(_ scenario: AgoraAudioScenario) -> some View { + Button(scenario.description()){ + self.scenario = scenario + } + } +} + +#Preview { + AudioWaveformEntry() +} + +struct BoxingViewWrapper: UIViewRepresentable { + let boxingview = ZSNBoxingView() + + func makeUIView(context: Context) -> UIView { + boxingview.middleInterval = -10 + return boxingview + } + + func updateUIView(_ uiView: UIView, context: Context) { + } +} + +struct AudioWaveform: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = AudioWaveformRTC() + + var localView = VideoView(type: .local, + audioOnly: true) + var remoteView = VideoView(type: .remote, + audioOnly: true) + var viewWrapper = BoxingViewWrapper() + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer(minLength: 200) + viewWrapper.onReceive(agoraKit.$volume, perform: { _ in + viewWrapper.boxingview.level = agoraKit.volume + }) + Text("\(agoraKit.volume)") + + }.onAppear(perform: { + viewWrapper.boxingview.start() + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + viewWrapper.boxingview.stop() + agoraKit.onDestory() + }) + } +} + +#Preview { + AudioWaveform(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioWaveform/AudioWaveformRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioWaveform/AudioWaveformRTC.swift new file mode 100644 index 000000000..3cefc89e1 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/AudioWaveform/AudioWaveformRTC.swift @@ -0,0 +1,235 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class AudioWaveformRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + @Published var volume: CGFloat = 0 + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + guard let channelName = configs["channelName"] as? String, + let audioProfile = configs["audioProfile"] as? AgoraAudioProfile, + let audioScenario = configs["audioScenario"] as? AgoraAudioScenario + else { return } + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + // set audio scenario + config.audioScenario = audioScenario + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // disable video module + agoraKit.disableVideo() + + agoraKit.enableAudio() + + let resolution = (GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize) ?? .zero + let fps = (GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate) ?? .fps15 + let orientation = (GlobalSettings.shared.getSetting(key: "orientation")? + .selectedOption().value as? AgoraVideoOutputOrientationMode) ?? .fixedPortrait + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, + mirrorMode: .auto)) + + // set audio profile + agoraKit.setAudioProfile(audioProfile) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // enable volume indicator + agoraKit.enableAudioVolumeIndication(200, smooth: 3, reportVad: true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = true + option.autoSubscribeAudio = true + option.autoSubscribeVideo = false + option.clientRoleType = GlobalSettings.shared.getUserRole() + + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func onDestory() { + agoraKit.enable(inEarMonitoring: false) + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func setAudioScenario(scenario: AgoraAudioScenario) { + agoraKit.setAudioScenario(scenario) + } + + func onChangeRecordingVolume(_ value: Double) { + let value: Int = Int(value) + print("adjustRecordingSignalVolume \(value)") + agoraKit.adjustRecordingSignalVolume(value) + } + + func onChangePlaybackVolume(_ value: Double) { + let value: Int = Int(value) + print("adjustPlaybackSignalVolume \(value)") + agoraKit.adjustPlaybackSignalVolume(value) + } + + func toggleInEarMonitoring(_ isOn: Bool) { + agoraKit.enable(inEarMonitoring: isOn) + } + + func onChangeInEarMonitoringVolume(_ value: Double) { + let value: Int = Int(value) + print("setInEarMonitoringVolume \(value)") + agoraKit.setInEarMonitoringVolume(value) + } +} + +// agora rtc engine delegate events +extension AudioWaveformRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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 = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// Reports which users are speaking, the speakers' volumes, and whether the local user is speaking. + /// @params speakers volume info for all speakers + /// @params totalVolume Total volume after audio mixing. The value range is [0,255]. + func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) { + for speaker in speakers { + volume = CGFloat(speaker.volume) + } + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ContentInspect/ContentInspect.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ContentInspect/ContentInspect.swift new file mode 100644 index 000000000..038c516c9 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ContentInspect/ContentInspect.swift @@ -0,0 +1,73 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct ContentInspectEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: ContentInspect(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + ContentInspectEntry() +} + +struct ContentInspect: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = ContentInspectRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + + var body: some View { + ZStack(alignment: .top) { + localView + ZStack(alignment: .center) { + Color.black.opacity(0.5).frame(height: 55) + Text("Please obtain the pornographic identification results through the console webhook.".localized).foregroundStyle(.white) + } + } + .onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }).toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button("SwitchCamera".localized) { + agoraKit.switchCamera() + } + } + } + } +} + +#Preview { + ContentInspect(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ContentInspect/ContentInspectRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ContentInspect/ContentInspectRTC.swift new file mode 100644 index 000000000..cdcb80e58 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ContentInspect/ContentInspectRTC.swift @@ -0,0 +1,170 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class ContentInspectRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView) { + self.localView = localView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Enable content inspect with local video view + let moderateModule = AgoraContentInspectModule() + moderateModule.type = .imageModeration + moderateModule.interval = 1 + + let inspectConfig = AgoraContentInspectConfig() + inspectConfig.modules = [moderateModule] + agoraKit.enableContentInspect(true, config: inspectConfig) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func switchCamera() { + agoraKit.switchCamera() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension ContentInspectRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CreateDataStream/CreateDataStream.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CreateDataStream/CreateDataStream.swift new file mode 100644 index 000000000..bf1425394 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CreateDataStream/CreateDataStream.swift @@ -0,0 +1,87 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct CreateDataStreamEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: CreateDataStream(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + CreateDataStreamEntry() +} + +struct CreateDataStream: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = CreateDataStreamRTC() + @State private var textfield: String = "" + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Text("Send Message".localized) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.leading, 20) + .padding(.top, 20) + HStack(spacing: 20) { + TextField("Input message".localized, text: $textfield).textFieldStyle(.roundedBorder) + Button("Send".localized) { + agoraKit.onSendPress(message: textfield) + textfield = "" + }.disabled(textfield.isEmpty) + } + .padding(.horizontal, 20) + .alert(isPresented: $agoraKit.isShowAlert) { + Alert(title: Text(agoraKit.alertMessage), + message: nil, + dismissButton: .default(Text("OK"))) + } + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + CreateDataStream(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CreateDataStream/CreateDataStreamRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CreateDataStream/CreateDataStreamRTC.swift new file mode 100644 index 000000000..bbcd25b62 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CreateDataStream/CreateDataStreamRTC.swift @@ -0,0 +1,238 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class CreateDataStreamRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + @Published var alertMessage: String = "" + @Published var isShowAlert: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onSendPress(message: String) { + // indicate if stream has created + var streamId: Int = 0 + // create the data stream + // Each user can create up to five data streams during the lifecycle of the agoraKit + let config = AgoraDataStreamConfig() + let result = agoraKit.createDataStream(&streamId, config: config) + if result != 0 { + let message = "createDataStream call failed: \(result), please check your params" + LogUtils.log(message: message, level: .error) + alertMessage = message + isShowAlert = true + } + let sendResult = agoraKit.sendStreamMessage(streamId, + data: Data(message.utf8)) + if sendResult != 0 { + let message = "sendStreamMessage call failed: \(sendResult), please check your params" + LogUtils.log(message: message, level: .error) + alertMessage = message + isShowAlert = true + } + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension CreateDataStreamRTC: AgoraRtcEngineDelegate { + func rtcEngine(_ engine: AgoraRtcEngineKit, receiveStreamMessageFromUid uid: UInt, streamId: Int, data: Data) { + let message = String.init(data: data, encoding: .utf8) ?? "" + LogUtils.log(message: "receiveStreamMessageFromUid: \(uid) \(message)", level: .info) + alertMessage = "from: \(uid) message: \(message)" + isShowAlert = true + } + + // swiftlint:disable function_parameter_count + func rtcEngine(_ engine: AgoraRtcEngineKit, + didOccurStreamMessageErrorFromUid uid: UInt, + streamId: Int, + error: Int, + missed: Int, + cached: Int) { + // swiftlint:enable function_parameter_count + let message = "streamMessageErrorFromUid: \(uid), error \(error)," + let message1 = "missed \(missed), cached \(cached)" + LogUtils.log(message: message + message1, level: .info) + alertMessage = "didOccurStreamMessageErrorFromUid: \(uid)" + isShowAlert = true + } + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift new file mode 100644 index 000000000..a75115efa --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift @@ -0,0 +1,68 @@ +// +// CustomAudioRender.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/10/9. +// + +import SwiftUI + +struct CustomAudioRenderEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: CustomAudioRender(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct CustomAudioRender: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = CustomAudioRenderRTC() + + var body: some View { + VStack { + GeometryReader { geometry in + ScrollView { + LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]) { + ForEach(agoraKit.audioInfos, id: \.self) { info in + VStack { + Text(info.content) + .font(.system(size: 12)) + .foregroundColor(.gray) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.gray.opacity(0.5)) + } + .frame(width: geometry.size.width / 3, height: 200) + } + } + } + } + } + .onAppear(perform: { + agoraKit.setupRTC(configs: configs) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + CustomAudioRender() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRenderRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRenderRTC.swift new file mode 100644 index 000000000..ef03afdfc --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRenderRTC.swift @@ -0,0 +1,143 @@ +// +// CustomAudioRenderRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/10/9. +// + +import Foundation +import AgoraRtcKit + +struct CustomAudioRenderViewInfo: Hashable { + var uid: UInt + var content: String +} + +class CustomAudioRenderRTC: NSObject, ObservableObject { + @Published var isJoined: Bool = false + @Published var audioInfos: [CustomAudioRenderViewInfo] = [] + private var agoraKit: AgoraRtcEngineKit! + private var exAudio: ExternalAudio = ExternalAudio.shared() + + func setupRTC(configs: [String: Any]) { + let sampleRate: UInt = 44100, channel: UInt = 1 + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + guard let channelName = configs["channelName"] as? String else {return} + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // disable video module + agoraKit.disableVideo() + agoraKit.enableAudio() + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + exAudio.setupExternalAudio(withAgoraKit: agoraKit, + sampleRate: UInt32(sampleRate), + channels: UInt32(channel), + trackId: 1, + audioCRMode: .sdkCaptureExterRender, + ioType: .remoteIO) + agoraKit.setParameters("{\"che.audio.external_render\": true}") + agoraKit.setParameters("{\"che.audio.keep.audiosession\": true}") + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = true + option.clientRoleType = GlobalSettings.shared.getUserRole() + + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + ToastView.show(text: "joinChannel call failed: \(result), please check your params") + } + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + private func getAudioLabel(uid: UInt, isLocal: Bool) -> String { + return "AUDIO ONLY\n\(isLocal ? "Local" : "Remote")\n\(uid)" + } +} + +extension CustomAudioRenderRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en:https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + ToastView.show(text: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + audioInfos.append(CustomAudioRenderViewInfo(uid: uid, content: self.getAudioLabel(uid: uid, isLocal: true))) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + audioInfos.append(CustomAudioRenderViewInfo(uid: uid, content: self.getAudioLabel(uid: uid, isLocal: false))) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + + // remove remote audio view + audioInfos.removeAll { info in + return info.uid == uid + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomPCMAudioSource/CustomPCMAudioSource.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomPCMAudioSource/CustomPCMAudioSource.swift new file mode 100644 index 000000000..a1c7b23d8 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomPCMAudioSource/CustomPCMAudioSource.swift @@ -0,0 +1,87 @@ +// +// CustomPCMAudioSource.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import SwiftUI + +struct CustomPCMAudioSourceEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: CustomPCMAudioSource(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct CustomPCMAudioSource: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = CustomPCMAudioSourceRTC() + @State private var displayPcm = false + + var body: some View { + VStack { + DynamicGridView( + items: agoraKit.audioViews + ) + .frame(height: 200) + .padding() + + Spacer() + + Toggle("Push PCM".localized, isOn: $displayPcm) + .onChange(of: displayPcm) { newValue in + agoraKit.pushPCM(state: newValue) + } + .disabled(!agoraKit.isJoined) + .padding(.bottom, 300) + } + .onAppear(perform: { + agoraKit.setupRTC(configs: configs) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +struct DynamicGridView: View { + let items: [AudioStreamInfo] + + var body: some View { + GeometryReader { geometry in + let columns = 3 + let itemWidth = geometry.size.width / CGFloat(columns) + + LazyVGrid(columns: Array(repeating: GridItem(.fixed(itemWidth)), count: columns)) { + ForEach(items, id: \.self) { item in + VideoView(type: item.local ? .local : .remote, audioOnly: true) + .background(.gray) + .frame(width: itemWidth, height: 200) + .padding(4) + } + } + } + } +} + +#Preview { + CustomPCMAudioSource() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomPCMAudioSource/CustomPCMAudioSourceRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomPCMAudioSource/CustomPCMAudioSourceRTC.swift new file mode 100644 index 000000000..3e1120526 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomPCMAudioSource/CustomPCMAudioSourceRTC.swift @@ -0,0 +1,175 @@ +// +// CustomPCMAudioSourceRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import Foundation +import AgoraRtcKit + +struct AudioStreamInfo: Identifiable, Hashable { + var id: UInt { uid } + var uid: UInt + var info: String + var local: Bool = false +} + +class CustomPCMAudioSourceRTC: NSObject, ObservableObject { + @Published var audioViews: [AudioStreamInfo] = [] + @Published var isJoined: Bool = false + + private var agoraKit: AgoraRtcEngineKit! + private var trackId: Int32 = 0 + private var pcmSourcePush: AgoraPcmSourcePush? + + var sampleRate = 48000, channel = 1, bitPerSample = 16 + let bufferSize = 6 + lazy var samples: Int = { + return (self.sampleRate / 100) * bufferSize + }() + + func setupRTC(configs: [String: Any]) { + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + guard let channelName = configs["channelName"] as? String, + let filepath = Bundle.main.path(forResource: "output", ofType: "pcm") else { + return + } + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // disable video module + agoraKit.disableVideo() + // enable audio module + agoraKit.enableAudio() + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // setup external audio source + pcmSourcePush = AgoraPcmSourcePush(delegate: self, filePath: filepath, sampleRate: Int(sampleRate), + channelsPerFrame: Int(channel), bitPerSample: bitPerSample, samples: samples) + + let trackConfig = AgoraAudioTrackConfig() + trackConfig.enableLocalPlayback = true + trackId = agoraKit.createCustomAudioTrack(.mixable, config: trackConfig) + agoraKit.enableCustomAudioLocalPlayback(1, enabled: true) + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishCustomAudioTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishCustomAudioTrackId = Int(trackId) + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + } + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func pushPCM(state: Bool) { + if state { + pcmSourcePush?.start() + } else { + pcmSourcePush?.stop() + } + let mediaOption = AgoraRtcChannelMediaOptions() + mediaOption.publishCustomAudioTrack = state + agoraKit.updateChannel(with: mediaOption) + } + + func getAudioLabel(uid: UInt, isLocal: Bool) -> String { + return "AUDIO ONLY\n\(isLocal ? "Local" : "Remote")\n\(uid)" + } +} + +extension CustomPCMAudioSourceRTC: AgoraPcmSourcePushDelegate { + func onAudioFrame(data: UnsafeMutablePointer) { + agoraKit.pushExternalAudioFrameRawData(data, + samples: samples, + sampleRate: Int(sampleRate), + channels: Int(channel), + trackId: Int(trackId), + timestamp: 0) + } +} + +/// agora rtc engine delegate events +extension CustomPCMAudioSourceRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + // set up local audio view, this view will not show video but just a placeholder + self.audioViews.append(AudioStreamInfo(uid: uid, info: self.getAudioLabel(uid: uid, isLocal: true), local: true)) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + // set up remote audio view, this view will not show video but just a placeholder + self.audioViews.append(AudioStreamInfo(uid: uid, info: self.getAudioLabel(uid: uid, isLocal: false))) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + + // remove remote audio view + self.audioViews.removeAll { $0.uid == uid } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/FaceCapture/FaceCapture.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/FaceCapture/FaceCapture.swift new file mode 100644 index 000000000..d8b47455c --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/FaceCapture/FaceCapture.swift @@ -0,0 +1,67 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct FaceCaptureEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: FaceCapture(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + FaceCaptureEntry() +} + +struct FaceCapture: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = FaceCaptureRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + } + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }).alert(isPresented: $agoraKit.isFaceLicenseEmpty, content: { + Alert(title: Text("Please contact Agora customer service to obtain a face capture certificate".localized)) + }) + } +} + +#Preview { + FaceCapture(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/FaceCapture/FaceCaptureRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/FaceCapture/FaceCaptureRTC.swift new file mode 100644 index 000000000..efb1bc400 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/FaceCapture/FaceCaptureRTC.swift @@ -0,0 +1,207 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class FaceCaptureRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var localView: VideoUIView? + + @Published var isFaceLicenseEmpty: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView) { + self.localView = localView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + isFaceLicenseEmpty = (KeyCenter.FaceCaptureLicense ?? "").isEmpty + guard !isFaceLicenseEmpty else { return } + // enable face capture + agoraKit.enableExtension(withVendor: "agora_video_filters_face_capture", + extension: "face_capture", + enabled: true, + sourceType: .primaryCamera) + + agoraKit.setExtensionPropertyWithVendor("agora_video_filters_face_capture", + extension: "face_capture", + key: "authentication_information", + value: "{\"company_id\":\"agoraTest\"," + + "\"license\":\"" + (KeyCenter.FaceCaptureLicense ?? "") + "\"}", + sourceType: .primaryCamera) + + agoraKit.enableExtension(withVendor: "agora_filters_lip_sync", + extension: "lip_sync", + enabled: true, + sourceType: .speechDriven) + agoraKit.setExtensionPropertyWithVendor("agora_filters_lip_sync", + extension: "lip_sync", + key: "parameters", + value: "{\"company_id\":\"agoraTest\", \"license\":\"abc\", \"open_agc\":true}", + sourceType: .speechDriven) + + agoraKit.setVideoFrameDelegate(self) + agoraKit.setFaceInfoDelegate(self) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +extension FaceCaptureRTC: AgoraFaceInfoDelegate { + func onFaceInfo(_ outFaceInfo: String) -> Bool { + localView?.statsInfo?.updateMetaInfo(data: outFaceInfo) + return true + } +} + +extension FaceCaptureRTC: AgoraVideoFrameDelegate { + func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { + let info = videoFrame.metaInfo["KEY_FACE_CAPTURE"] as? String + LogUtils.log(message: info ?? "", level: .info) + return true + } + func getVideoFrameProcessMode() -> AgoraVideoFrameProcessMode { + .readWrite + } + func getObservedFramePosition() -> AgoraVideoFramePosition { + .postCapture + } +} + +// agora rtc engine delegate events +extension FaceCaptureRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift new file mode 100644 index 000000000..552392e53 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift @@ -0,0 +1,106 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct JoinMultiChannelEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: JoinMultiChannel(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + JoinMultiChannelEntry() +} + +struct JoinMultiChannel: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = JoinMultiChannelRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + var remote2View = VideoView(type: .remote, + audioOnly: false) + @State private var isShowLeaveAlert: Bool = false + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + remote2View.frame(height: 200) + HStack { + Button("LeaveChannelEx") { + isShowLeaveAlert.toggle() + } + .disabled(!agoraKit.joinEx) + .colorMultiply(agoraKit.joinEx ? .white : .gray) + .padding(5) + .background(.blue) + .foregroundStyle(.white) + .clipShape(.rect(cornerRadius: 5)) + .alert(isPresented: $isShowLeaveAlert) { + Alert(title: Text("stopMicrophoneRecording".localized), primaryButton: .default(Text("Stop".localized), action: { + agoraKit.onTapLeaveChannelEx(isStop: true) + }), secondaryButton: .cancel(Text("Cancel".localized), action: { + agoraKit.onTapLeaveChannelEx(isStop: false) + })) + } + + Spacer() + Button("take Snapshot Ex") { + agoraKit.onTapTakeSnapshotEx() + } + .disabled(!agoraKit.joinEx) + .colorMultiply(agoraKit.joinEx ? .white : .gray) + .padding(5) + .background(.blue) + .foregroundStyle(.white) + .clipShape(.rect(cornerRadius: 5)) + .alert(isPresented: $agoraKit.isShowAlert) { + Alert(title: Text(agoraKit.snapshotPath), dismissButton: .default(Text("Sure".localized))) + } + }.padding() + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView, + remote2View: remote2View.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + JoinMultiChannel(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/JoinMultiChannel/JoinMultiChannelRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/JoinMultiChannel/JoinMultiChannelRTC.swift new file mode 100644 index 000000000..41244b987 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/JoinMultiChannel/JoinMultiChannelRTC.swift @@ -0,0 +1,311 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + + +let CONNECTION_1_UID = UInt.random(in: 1001...2000) +let CONNECTION_2_UID = UInt.random(in: 2001...3000) +class JoinMultiChannelRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var remote2View: VideoUIView? + + private var channel1: Channel1Delegate = Channel1Delegate() + private var channel2: Channel2Delegate = Channel2Delegate() + private var channelName1 = "" + private var channelName2 = "" + + @Published var snapshotPath: String = "" + @Published var isShowAlert: Bool = false + @Published var joinEx: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView, + remote2View: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + self.remote2View = remote2View + + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + channelName1 = "\(channelName)" + channelName2 = "\(channelName)-2" + channel1.channelId = channelName1 + channel2.channelId = channelName2 + channel1.view = remoteView.videoView + channel2.view = remote2View.videoView + remote2View.setPlaceholder(text: "\(channelName2 )\nRemote Host") + channel2.userJoinExClosure = { [weak self] isJoin in + self?.joinEx = isJoin + } + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: channel1) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + joinChannel1() + joinChannel2() + localView.setInfo(text: "") + remoteView.setInfo(text: "") + remote2View.setInfo(text: "") + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = CONNECTION_1_UID + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + private func joinChannel1() { + // join channel1 + let mediaOptions = AgoraRtcChannelMediaOptions() + // publish audio and camera track for channel 1 + mediaOptions.publishCameraTrack = false + mediaOptions.publishMicrophoneTrack = false + mediaOptions.autoSubscribeVideo = true + mediaOptions.autoSubscribeAudio = true + mediaOptions.clientRoleType = .audience + NetworkManager.shared.generateToken(channelName: channelName1, uid: CONNECTION_1_UID) { token in + let result = self.agoraKit.joinChannel(byToken: token, + channelId: self.channelName1, + uid: CONNECTION_1_UID, + mediaOptions: mediaOptions, + joinSuccess: nil) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel1 call failed: \(result), please check your params", level: .error) + } + } + } + + private func joinChannel2() { + // join channel2 + let mediaOptions = AgoraRtcChannelMediaOptions() + mediaOptions.publishMicrophoneTrack = true + mediaOptions.publishCameraTrack = true + mediaOptions.autoSubscribeVideo = true + mediaOptions.autoSubscribeAudio = true + mediaOptions.clientRoleType = .broadcaster + let connection2 = AgoraRtcConnection() + connection2.channelId = channelName2 + connection2.localUid = CONNECTION_2_UID + NetworkManager.shared.generateToken(channelName: channelName2, uid: CONNECTION_2_UID) { token in + let result = self.agoraKit.joinChannelEx(byToken: token, + connection: connection2, + delegate: self.channel2, + mediaOptions: mediaOptions, + joinSuccess: nil) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel2 call failed: \(result), please check your params", level: .error) + } + } + } + + func onTapTakeSnapshotEx() { + guard channel2.remoteUid != 0 else { return } + let path = NSTemporaryDirectory().appending("1.png") + let connection = AgoraRtcConnection(channelId: channelName2, localUid: Int(CONNECTION_2_UID)) + agoraKit.takeSnapshotEx(connection, uid: Int(channel2.remoteUid), filePath: path) + snapshotPath = path + isShowAlert = true + } + + func onTapLeaveChannelEx(isStop: Bool) { + let connection2 = AgoraRtcConnection() + connection2.channelId = channelName2 + connection2.localUid = CONNECTION_2_UID + let channelOptions = AgoraLeaveChannelOptions() + if isStop { + channelOptions.stopMicrophoneRecording = true + } + agoraKit.leaveChannelEx(connection2, options: channelOptions, leaveChannelBlock: nil) + channel2.remoteUid = 0 + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + let channel2 = AgoraRtcConnection() + channel2.channelId = channelName2 + channel2.localUid = CONNECTION_2_UID + agoraKit.leaveChannelEx(channel2, leaveChannelBlock: nil) + } + AgoraRtcEngineKit.destroy() + } +} + +class Channel1Delegate: NSObject, AgoraRtcEngineDelegate { + var channelId: String? + var view: UIView? + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + + LogUtils.log(message: "local user join room channel \(channelId ?? ""): \(uid) \(elapsed)ms", level: .info) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + guard let channelId = channelId, let channel1RemoteVideo = view else { + return + } + LogUtils.log(message: "remote user join room channel \(channelId): \(uid) \(elapsed)ms", level: .info) + + // 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 = channel1RemoteVideo + videoCanvas.renderMode = .hidden + let connection = AgoraRtcConnection() + connection.channelId = channelId + connection.localUid = CONNECTION_1_UID + engine.setupRemoteVideoEx(videoCanvas, connection: connection) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + guard let channelId = channelId else { + return + } + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + let connection = AgoraRtcConnection() + connection.channelId = channelId + connection.localUid = CONNECTION_2_UID + engine.setupRemoteVideoEx(videoCanvas, connection: connection) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, localAudioStateChanged state: AgoraAudioLocalState, reason: AgoraAudioLocalReason) { + print("localAudioStateChanged == \(state.rawValue)") + } +} + +/// agora rtc engine delegate events +class Channel2Delegate: NSObject, AgoraRtcEngineDelegate { + var channelId: String? + var view: UIView? + var remoteUid: UInt = 0 + var userJoinExClosure: ((Bool) -> Void)? + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode.description)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + guard let channelId = channelId, let channel2RemoteVideo = view else { + return + } + LogUtils.log(message: "remote user join room channel \(channelId): \(uid) \(elapsed)ms", level: .info) + + // 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 = channel2RemoteVideo + videoCanvas.renderMode = .hidden + let connection = AgoraRtcConnection() + connection.channelId = channelId + connection.localUid = CONNECTION_2_UID + engine.setupRemoteVideoEx(videoCanvas, connection: connection) + remoteUid = uid + userJoinExClosure?(true) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + guard let channelId = channelId else { + return + } + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + let connection = AgoraRtcConnection() + connection.channelId = channelId + connection.localUid = CONNECTION_2_UID + engine.setupRemoteVideoEx(videoCanvas, connection: connection) + remoteUid = 0 + userJoinExClosure?(false) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, localAudioStateChanged state: AgoraAudioLocalState, reason: AgoraAudioLocalReason) { + print("localAudioStateChanged == \(state.rawValue)") + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/KtvCopyrightMusic/KtvCopyrightMusic.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/KtvCopyrightMusic/KtvCopyrightMusic.swift new file mode 100644 index 000000000..f0ef253db --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/KtvCopyrightMusic/KtvCopyrightMusic.swift @@ -0,0 +1,25 @@ +// +// KtvCopyrightMusic.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/25. +// + +import SwiftUI + +struct KtvCopyrightMusic: View { + var body: some View { + ZStack { + Button("Ktv copyright music".localized) { + let urlString = "https://doc.shengwang.cn/doc/online-ktv/ios/implementation/ktv-scenario/integrate-ktvapi" + if let url = URL(string: urlString) { + UIApplication.shared.open(url) + } + }.buttonStyle(.borderedProminent) + } + } +} + +#Preview { + KtvCopyrightMusic() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LiveStreaming/LiveStreaming.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LiveStreaming/LiveStreaming.swift new file mode 100644 index 000000000..128057f48 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LiveStreaming/LiveStreaming.swift @@ -0,0 +1,522 @@ +// +// LiveStreaming.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/25. +// + +import SwiftUI +import Combine + +struct LiveStreamingEntry: View { + @State private var channelName: String = "" + @State private var channelButtonIsActive = false + @State private var selectedCamertOption = "" + @State private var firstFrameToggleIsOn = false + @State private var preloadIsOn = false + @State private var roleSheetIsShow = false + @State private var cameraSheetIsShow = false + @State private var role: AgoraClientRole = .broadcaster + + @State private var cameraOptions: [AgoraFocalLengthInfo] = [] + @State private var configs: [String: Any] = [:] + @State var selectedColor: BackgroundColors = .Red + @ObservedObject private var liveStreamRTCKit = LiveStreamingRTC() + @Environment(\.presentationMode) var presentationMode + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName) + .textFieldStyle(.roundedBorder) + .padding() + .padding(.bottom, 10) + + //默认背景色 + HStack { + Text("Default background Color".localized) + Picker("", selection: $selectedColor) { + ForEach(BackgroundColors.allCases) { e in + Text(e.suggestedColor).tag(e) + } + } + } + + //首帧出图 + Toggle("First Frame Optimization", isOn: $firstFrameToggleIsOn) + .padding(.bottom, 10) + .alert(isPresented: $firstFrameToggleIsOn) { + Alert(title: Text("After this function is enabled, it cannot be disabled and takes effect only when both the primary and secondary ends are enabled".localized), + primaryButton: .default(Text("Sure".localized), action: { + firstFrameToggleIsOn = true + }), + secondaryButton: .cancel(Text("Cancel".localized))) + } + .fixedSize() + + //预加载 + Button(preloadIsOn ? "cancel preload".localized : "preload Channel".localized) { + preloadIsOn.toggle() + } + .padding(.bottom, 10) + + //相机 + HStack { + Text("Camera Selected".localized) + Button(selectedCamertOption) { + self.cameraSheetIsShow = true + } + .sheet(isPresented: $cameraSheetIsShow, content: { + let params = cameraOptions.flatMap({ $0.value }) + let keys = params.map({ $0.key }) + + PickerSheetView(selectedOption: $selectedCamertOption, options: keys, isPresented: $cameraSheetIsShow) { selectedOption in + self.selectedCamertOption = selectedOption + for camera in params { + if camera.key == self.selectedCamertOption { + let config = AgoraCameraCapturerConfiguration() + config.cameraFocalLengthType = camera.value + config.cameraDirection = camera.key.contains("Front camera".localized) ? .front : .rear + liveStreamRTCKit.agoraKit.setCameraCapturerConfiguration(config) + break + } + } + } + }) + } + .padding(.bottom, 10) + + Button { + self.roleSheetIsShow = true + } label: { + Text("Join".localized) + } + .confirmationDialog("Pick Role".localized, isPresented: $roleSheetIsShow, actions: { + Button("Broadcaster".localized) { + self.role = .broadcaster + prepareConfig() + self.channelButtonIsActive = true + } + Button("Audience".localized) { + self.role = .audience + prepareConfig() + self.channelButtonIsActive = true + } + Button("Cancel".localized, role: .cancel) {} + }) + .disabled(channelName.isEmpty) + + Spacer() + NavigationLink(destination: LiveStreaming(liveStreamRTCKit: liveStreamRTCKit, configs: configs) + .navigationTitle(channelName) + .navigationBarTitleDisplayMode(.inline), + isActive: $channelButtonIsActive) { + EmptyView() + } + Spacer() + } + .onDisappear(perform: { + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + }) + .onAppear(perform: { + guard let infos = liveStreamRTCKit.agoraKit.queryCameraFocalLengthCapability() else { return } + let params = infos.flatMap({ $0.value }) + let keys = params.map({ $0.key }) + cameraOptions = infos + + selectedCamertOption = keys.first ?? "" + }) + .navigationBarBackButtonHidden(true) + .navigationBarItems(leading: Button(action: { + liveStreamRTCKit.onDestory() + presentationMode.wrappedValue.dismiss() + }) { + HStack { + Image(systemName: "chevron.left") // 自定义返回按钮图标 + } + }) + .navigationBarTitleDisplayMode(.inline) + } + + func prepareConfig() { + configs["role"] = self.role + configs["isFirstFrame"] = firstFrameToggleIsOn + configs["channelName"] = channelName + configs["isPreloadChannel"] = preloadIsOn + configs["cameraKey"] = selectedCamertOption + configs["backgroundColor"] = selectedColor.value + print("") + } +} + +struct LiveStreaming: View { + var liveStreamRTCKit: LiveStreamingRTC + @State var configs: [String: Any] = [:] + @State var selectStabilizationMode: AntiShakeLevel = .off + @State var selectEncodingType: CodeType = .auto + @State var centerStage: Bool = false + @State var bFpsState: Bool = false + @State var waterMarkState: Bool = false + @State var gasketPushFlow: Bool = false + @State var showCenterStageAlert: Bool = false + @State var simulcastStreamState: Bool = false + @State private var selectedCamertOption = "" + @State private var cameraOptions: [AgoraFocalLengthInfo] = [] + @State private var cameraSheetIsShow = false + @State private var showSnapshot: Bool = false + @State private var showSnapShotTitle: String = "" + @State private var showSnapShotMessage: String = "" + @State private var fastLiveState: Bool = false + @State private var linkStreamState: Bool = false + @State var cameraDirection: AgoraCameraDirection = .front + + var backgroundView = VideoView(type: .local, + audioOnly: false) + var foregroundView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + ZStack { + backgroundView + VStack { + if liveStreamRTCKit.remoteUid != nil { + HStack { + Spacer() + foregroundView + .frame(width: 136, height: 182) + .offset(x: -20) + .onTapGesture { + liveStreamRTCKit.onTapForegroundVideo() + } + } + } else { + Rectangle() + .frame(width: 136, height: 182) + .foregroundStyle(.clear) + } + + //防抖 + HStack { + Text("anti shake".localized) + .foregroundStyle(.white) + Picker("", selection: $selectStabilizationMode) { + ForEach(AntiShakeLevel.allCases) { e in + Text(e.suggestedLevel).tag(e) + } + } + .onChange(of: selectStabilizationMode) { newValue in + liveStreamRTCKit.agoraKit.setCameraStabilizationMode(newValue.value) + } + } + .background(.gray.opacity(0.3)) + .padding(.top, 30) + + if liveStreamRTCKit.role == .broadcaster { + //centerStage, 相机对焦 + HStack { + Toggle("CenterStage", isOn: $centerStage) + .foregroundStyle(.white) + .onChange(of: centerStage) { newValue in + let centerStageNotSupported = liveStreamRTCKit.agoraKit.isCameraCenterStageSupported() + if newValue && !centerStageNotSupported { + showCenterStageAlert = true + return + } + + if newValue { + liveStreamRTCKit.agoraKit.enableCameraCenterStage(newValue) + } + } + .frame(height: 30) + .alert(isPresented: $showCenterStageAlert, content: { + Alert( + title: Text("This device does not support Center Stage".localized), + dismissButton: .destructive(Text("ok"), action: { + centerStage = false + }) + ) + }) + + Text("Camera Selected".localized) + .foregroundStyle(.white) + Button(selectedCamertOption) { + self.cameraSheetIsShow = true + } + .sheet(isPresented: $cameraSheetIsShow, content: { + let params = cameraOptions.flatMap({ $0.value }) + let keys = params.map({ $0.key }) + + PickerSheetView(selectedOption: $selectedCamertOption, options: keys, isPresented: $cameraSheetIsShow) { selectedOption in + self.selectedCamertOption = selectedOption + for camera in params { + if camera.key == self.selectedCamertOption { + let config = AgoraCameraCapturerConfiguration() + config.cameraFocalLengthType = camera.value + config.cameraDirection = camera.key.contains("Front camera".localized) ? .front : .rear + if (config.cameraDirection != self.cameraDirection) { + liveStreamRTCKit.agoraKit.switchCamera() + } + liveStreamRTCKit.agoraKit.setCameraCapturerConfiguration(config) + self.cameraDirection = config.cameraDirection + break + } + } + } + }) + } + .fixedSize() + .background(.gray.opacity(0.3)) + + //B帧,编码方式 + HStack { + Toggle("B Fps".localized, isOn: $bFpsState) + .foregroundStyle(.white) + .onChange(of: bFpsState) { newValue in + let encoderConfig = AgoraVideoEncoderConfiguration() + let videoOptions = AgoraAdvancedVideoOptions() + videoOptions.compressionPreference = newValue ? .quality : .lowLatency + encoderConfig.advancedVideoOptions = videoOptions + + liveStreamRTCKit.agoraKit.setVideoEncoderConfiguration(encoderConfig) + } + Text("Code Type".localized) + .foregroundStyle(.white) + Picker("", selection: $selectEncodingType) { + ForEach(CodeType.allCases) { e in + Text(e.suggestedType) + .tag(e) + } + } + .onChange(of: selectEncodingType) { newValue in + let encoderConfig = AgoraVideoEncoderConfiguration() + let advancedOptions = AgoraAdvancedVideoOptions() + advancedOptions.encodingPreference = newValue.value + encoderConfig.advancedVideoOptions = advancedOptions + + liveStreamRTCKit.agoraKit.setVideoEncoderConfiguration(encoderConfig) + } + .pickerStyle(SegmentedPickerStyle()) + + } + .fixedSize() + .background(.gray.opacity(0.3)) + + //水印, 垫片推流 + HStack { + Toggle("Water Mark".localized, isOn: $waterMarkState) + .foregroundStyle(.white) + .onChange(of: waterMarkState) { newValue in + if newValue { + if let filepath = Bundle.main.path(forResource: "agora-logo", ofType: "png") { + if let url = URL.init(string: filepath) { + let waterMark = WatermarkOptions() + waterMark.visibleInPreview = true + waterMark.positionInPortraitMode = CGRect(x: 10, y: 80, width: 60, height: 60) + waterMark.positionInLandscapeMode = CGRect(x: 10, y: 80, width: 60, height: 60) + liveStreamRTCKit.agoraKit.addVideoWatermark(url, options: waterMark) + } + } + } else { + liveStreamRTCKit.agoraKit.clearVideoWatermarks() + } + + } + + Toggle("Gasket push flow".localized, isOn: $gasketPushFlow) + .foregroundStyle(.white) + .onChange(of: gasketPushFlow) { newValue in + let options = AgoraImageTrackOptions() + let imgPath = Bundle.main.path(forResource: "agora-logo", ofType: "png") + options.imageUrl = imgPath + + liveStreamRTCKit.agoraKit.enableVideoImageSource(newValue, options: options) + } + + } + .fixedSize() + .background(.gray.opacity(0.3)) + } + + //截图,大小流 + HStack { + Button("screenshot".localized) { + showSnapshot = true + + guard let remoteUid = liveStreamRTCKit.remoteUid else { + showSnapShotTitle = "remote user has not joined, and cannot take a screenshot".localized; + showSnapShotMessage = "" + return + } + + let path = NSTemporaryDirectory().appending("1.png") + liveStreamRTCKit.agoraKit.takeSnapshot(Int(remoteUid), filePath: path) + showSnapShotTitle = "Screenshot successful".localized + showSnapShotMessage = path + } + .alert(isPresented: $showSnapshot, content: { + Alert(title: Text(showSnapShotTitle), message: Text(showSnapShotMessage)) + }) + .padding(.trailing, 20) + + Toggle(isOn: $simulcastStreamState, label: { + VStack { + Text("Simulcast Stream Title".localized) + Text(simulcastStreamState ? "Opened State".localized : "Default State".localized) + .font(.system(size: 11)) + } + .foregroundStyle(.white) + }) + .onChange(of: simulcastStreamState) { newValue in + simulcastStreamState = newValue + liveStreamRTCKit.agoraKit.setDualStreamMode(newValue ? .enableSimulcastStream : .disableSimulcastStream) + } + } + .fixedSize() + .background(.gray.opacity(0.3)) + + //极速直播, 连麦 + HStack { + if liveStreamRTCKit.showUltraLowEntry { + Toggle("Fast Live".localized, isOn: $fastLiveState) + .onChange(of: fastLiveState) { newValue in + liveStreamRTCKit.onToggleUltraLowLatency(enabled: newValue) + } + .disabled(linkStreamState) + } + + + if liveStreamRTCKit.showLinkStreamEntry { + Toggle("Link Stream".localized, isOn: $linkStreamState) + .onChange(of: linkStreamState) { newValue in + liveStreamRTCKit.onToggleClientRole(state: newValue) + } + } + } + .fixedSize() + .background(.gray.opacity(0.3)) + + Spacer() + } + } + .onAppear { + liveStreamRTCKit.setupRTC(configs: configs, localView: backgroundView.videoView, remoteView: foregroundView.videoView) + guard let infos = liveStreamRTCKit.agoraKit.queryCameraFocalLengthCapability() else { return } + + cameraOptions = infos + + if let cameraKey = configs["cameraKey"] as? String { + selectedCamertOption = cameraKey + cameraDirection = cameraKey.contains("Front camera".localized) ? .front : .rear + } + + + }.onDisappear { + liveStreamRTCKit.leaveChannel() + } + } +} + +extension AgoraFocalLengthInfo { + var value: [String: AgoraFocalLength] { + let title = cameraDirection == 1 ? "Front camera".localized + " - " : "Rear camera".localized + " - " + switch focalLengthType { + case .default: return [title + "Default".localized: focalLengthType] + case .wide: return [title + "Wide".localized: focalLengthType] + case .ultraWide: return [title + "Length Wide".localized: focalLengthType] + case .telephoto: return [title + "Telephoto".localized: focalLengthType] + @unknown default: return [title + "Default".localized: focalLengthType] + } + } +} + +enum BackgroundColors: String, CaseIterable, Identifiable { + case Red + case Blue + case Pink + case Purple + case Yellow + + var id: String { self.rawValue } + + var value: UInt32 { + switch self { + case .Red: + return UInt32(0xff0d00ff) + case .Blue: + return UInt32(0x0400ffff) + case .Pink: + return UInt32(0xff006aff) + case .Purple: + return UInt32(0xff00d9ff) + case .Yellow: + return UInt32(0xeaff00ff) + } + } + + var suggestedColor: String { + switch self { + case .Red: return "Red".localized + case .Blue: return "Blue".localized + case .Pink: return "Pink".localized + case .Purple: return "Purple".localized + case .Yellow: return "Yellow".localized + } + } +} + +enum AntiShakeLevel: String, CaseIterable, Identifiable { + case off + case auto + case level1 + case level2 + case level3 + + var id: String { self.rawValue } + + var value: AgoraCameraStabilizationMode { + switch self { + case .off: + return .off + case .auto: + return .auto + case .level1: + return .level1 + case .level2: + return .level2 + case .level3: + return .level3 + } + } + + var suggestedLevel: String { + return self.rawValue + } +} + +enum CodeType: String, CaseIterable, Identifiable { + case auto + case software + case hardware + + var id: String { self.rawValue } + + var value: AgoraEncodingPreference { + switch self { + case .auto: + return .preferAuto + case .software: + return .prefersoftware + case .hardware: + return .preferhardware + } + } + + var suggestedType: String { + switch self { + case .auto: return "auto".localized + case .software: return "software".localized + case .hardware: return "hardware".localized + } + } +} + diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LiveStreaming/LiveStreamingRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LiveStreaming/LiveStreamingRTC.swift new file mode 100644 index 000000000..3f83a0152 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LiveStreaming/LiveStreamingRTC.swift @@ -0,0 +1,344 @@ +// +// LiveStreamingRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/25. +// + +import Foundation +import Combine +import AgoraRtcKit + +class LiveStreamingRTC: NSObject, ObservableObject { + @Published var role: AgoraClientRole = .broadcaster + @Published var showUltraLowEntry: Bool = false + @Published var showLinkStreamEntry: Bool = false + var agoraKit: AgoraRtcEngineKit! + + private var isJoined: Bool = false + private var foregroundView: VideoUIView? + private var backgroundView: VideoUIView? + private var configs: [String: Any]! + var isUltraLowLatencyOn: Bool = false + var isLocalVideoForeground = false { + didSet { + if isLocalVideoForeground { + backgroundView?.setPlaceholder(text: "Local Host".localized) + foregroundView?.setPlaceholder(text: "Remote Host".localized) + } else { + backgroundView?.setPlaceholder(text: "Remote Host".localized) + foregroundView?.setPlaceholder(text: "Local Host".localized) + } + } + } + + deinit { + print("sss") + } + + @Published var remoteUid: UInt? { + didSet { + foregroundView?.isHidden = !(role == .broadcaster && remoteUid != nil) + } + } + + override init() { + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.channelProfile = .liveBroadcasting + let kit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: nil) + Util.configPrivatization(agoraKit: kit) + kit.setLogFile(LogUtils.sdkLogPath()) + agoraKit = kit + } + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.configs = configs + self.backgroundView = localView + self.foregroundView = remoteView + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + if let isFirstFrame = configs["isFirstFrame"] as? Bool, isFirstFrame == true { + agoraKit.enableInstantMediaRendering() + agoraKit.startMediaRenderingTracing() + } + + guard let channelName = configs["channelName"] as? String, let clientRole = configs["role"] as? AgoraClientRole else {return} + role = clientRole + isLocalVideoForeground = role == .audience + showUltraLowEntry = role == .audience + showLinkStreamEntry = role == .audience + + updateClientRole(role) + + // enable video module and set up video encoding configs + agoraKit.enableVideo() + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = role == .broadcaster + option.publishMicrophoneTrack = role == .broadcaster + option.clientRoleType = role + NetworkManager.shared.generateToken(channelName: channelName, success: { [weak self] token in + guard let self = self else { return } + let preloadChannel = configs["isPreloadChannel"] as? Bool + if preloadChannel == true { + self.agoraKit.preloadChannel(byToken: token, + channelId: channelName, + uid: 0) + } + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func updateClientRole(_ role: AgoraClientRole) { + self.role = role + if role == .broadcaster { + becomeBroadcaster() + } else { + becomeAudience() + } + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = role == .broadcaster + option.publishMicrophoneTrack = role == .broadcaster + agoraKit.updateChannel(with: option) + } + + func onToggleClientRole(state: Bool) { + let role: AgoraClientRole = state ? .broadcaster : .audience + updateClientRole(role) + } + + func onToggleUltraLowLatency(enabled: Bool) { + updateUltraLowLatency(enabled) + } + + fileprivate func updateUltraLowLatency(_ enabled: Bool) { + if self.role == .audience { + self.isUltraLowLatencyOn = enabled + updateClientRole(.audience) + } + } + + func becomeBroadcaster() { + guard let resolution = GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize, + let fps = GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate, + let orientation = GlobalSettings.shared.getSetting(key: "orientation")?.selectedOption().value as? AgoraVideoOutputOrientationMode else { + LogUtils.log(message: "invalid video configurations, failed to become broadcaster", level: .error) + return + } + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = localVideoCanvas() + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + agoraKit.enableAudio() + + agoraKit.setClientRole(.broadcaster, options: nil) + } + + /// make myself an audience + func becomeAudience() { + // unbind view + agoraKit.setupLocalVideo(nil) + // You have to provide client role options if set to audience + let options = AgoraClientRoleOptions() + options.audienceLatencyLevel = isUltraLowLatencyOn ? .ultraLowLatency : .lowLatency + agoraKit.setClientRole(.audience, options: options) + } + + func localVideoCanvas() -> UIView? { + return isLocalVideoForeground ? foregroundView?.videoView : backgroundView?.videoView + } + + func remoteVideoCanvas() -> UIView? { + return isLocalVideoForeground ? backgroundView?.videoView : foregroundView?.videoView + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func leaveChannel() { + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + } + + func onTapForegroundVideo() { + isLocalVideoForeground.toggle() + + let localVideoCanvas = AgoraRtcVideoCanvas() + localVideoCanvas.uid = 0 + localVideoCanvas.renderMode = .hidden + localVideoCanvas.view = self.localVideoCanvas() + + let remoteVideoCanvas = AgoraRtcVideoCanvas() + remoteVideoCanvas.renderMode = .hidden + remoteVideoCanvas.view = self.remoteVideoCanvas() + + agoraKit.setupLocalVideo(localVideoCanvas) + if let uid = remoteUid { + remoteVideoCanvas.uid = uid + agoraKit.setupRemoteVideo(remoteVideoCanvas) + } + } +} + +extension LiveStreamingRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, cameraFocusDidChangedTo rect: CGRect) { + LogUtils.log(message: "The camera has changed".localized + " \(rect)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + } + + /// callback when the local user joins a specified channel. + /// @param channel + /// @param uid uid of local user + /// @param elapsed time elapse since current sdk instance join the channel in ms + /// + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + isJoined = true + foregroundView?.statsInfo?.updateUid(uid: uid) + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + backgroundView?.statsInfo?.updateRemoteUid(remoteUid: uid) + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + + // record remote uid + remoteUid = uid + // Only one remote video view is available for this + // tutorial. Here we check if there exists a surface + // view tagged as this uid. + let backgroundColor = (configs["backgroundColor"] as? UInt32) ?? 0x000000 + // 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() + // the view to be binded + videoCanvas.uid = uid + videoCanvas.view = remoteVideoCanvas() + videoCanvas.backgroundColor = backgroundColor + videoCanvas.renderMode = .fit + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + // clear remote uid + if remoteUid == uid { + remoteUid = nil + } + + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + foregroundView?.statsInfo?.updateChannelStats(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) { + foregroundView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + backgroundView?.statsInfo?.updateVideoStats(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) { + backgroundView?.statsInfo?.updateAudioStats(stats) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, + videoRenderingTracingResultOfUid uid: UInt, + currentEvent: AgoraMediaTraceEvent, + tracingInfo: AgoraVideoRenderingTracingInfo) { + backgroundView?.statsInfo?.updateFirstFrameInfo(tracingInfo) + } +} + diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LocalVideoTranscoding/LocalVideoTranscoding.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LocalVideoTranscoding/LocalVideoTranscoding.swift new file mode 100644 index 000000000..b4f20e05e --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LocalVideoTranscoding/LocalVideoTranscoding.swift @@ -0,0 +1,61 @@ +// +// LocalVideoTranscoding.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/29. +// + +import SwiftUI + +struct LocalVideoTranscodingEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: LocalVideoTranscoding(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct LocalVideoTranscoding: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = LocalVideoTranscodingRTC() + + var localView = SampleBufferView() + var remoteView = VideoView(type: .remote) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + LocalVideoTranscoding() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LocalVideoTranscoding/LocalVideoTranscodingRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LocalVideoTranscoding/LocalVideoTranscodingRTC.swift new file mode 100644 index 000000000..f41b2071d --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/LocalVideoTranscoding/LocalVideoTranscodingRTC.swift @@ -0,0 +1,207 @@ +// +// LocalVideoTranscodingRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/29. +// + +import Foundation +import AgoraRtcKit + +class LocalVideoTranscodingRTC: NSObject, ObservableObject { + @Published var isJoined: Bool = false + private var agoraKit: AgoraRtcEngineKit! + private var localView: SampleBufferDisplayView? + private var remoteView: VideoUIView? + private var mediaPlayerKit: AgoraRtcMediaPlayerProtocol! + + func setupRTC(configs: [String: Any], + localView: SampleBufferDisplayView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setVideoFrameDelegate(self) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + mediaPlayerKit = agoraKit.createMediaPlayer(with: self) + + let streamingUrl = "https://agora-adc-artifacts.s3.cn-north-1.amazonaws.com.cn/resources/sample.mp4" + let mediaSource = AgoraMediaSource() + mediaSource.url = streamingUrl + mediaPlayerKit.open(with: mediaSource) + mediaPlayerKit.adjustPlayoutVolume(0) + + var streams: [AgoraTranscodingVideoStream] = [] + var playerStream = AgoraTranscodingVideoStream() + playerStream.sourceType = .mediaPlayer + playerStream.mediaPlayerId = UInt(mediaPlayerKit.getMediaPlayerId()) + playerStream.zOrder = 1 + playerStream.rect = CGRect(x: 0, y: 0, width: 200, height: 200) + streams.append(playerStream) + + var cameraStream = AgoraTranscodingVideoStream() + cameraStream.sourceType = .camera + cameraStream.zOrder = 2 + cameraStream.rect = CGRect(x: 0, y: 0, width: 100, height: 100) + cameraStream.mirror = true + streams.append(cameraStream) + + let cameraConfig = AgoraCameraCapturerConfiguration() + cameraConfig.cameraDirection = .rear + cameraConfig.dimensions = CGSize(width: 100, height: 100) + agoraKit.startCameraCapture(.camera, config: cameraConfig) + + let transcoderConfig = AgoraLocalTranscoderConfiguration() + transcoderConfig.videoInputStreams = streams + let outputConfig = AgoraVideoEncoderConfiguration() + outputConfig.dimensions = CGSize(width: 200, height: 200) + transcoderConfig.videoOutputConfiguration = outputConfig + + agoraKit.startLocalVideoTranscoder(transcoderConfig) + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// MARK: - AgoraRtcEngineDelegate +extension LocalVideoTranscodingRTC: AgoraRtcEngineDelegate { + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "Error occur: \(errorCode)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + LogUtils.log(message: "Remote user \(uid) joined elapsed \(elapsed)ms", level: .info) + + // Render remote user video frame at a UIView + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.view = remoteView?.videoView + videoCanvas.uid = uid + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + LogUtils.log(message: "Remote user \(uid) offline with reason \(reason)", level: .info) + + // Stop render remote user video frame + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.view = nil + videoCanvas.uid = uid + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} + +extension LocalVideoTranscodingRTC: AgoraVideoFrameDelegate { + func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { + return true + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { + return true + } + + func onTranscodedVideoFrame(_ videoFrame: AgoraOutputVideoFrame) -> Bool { + if videoFrame.pixelBuffer != nil { + localView?.videoView.renderVideoPixelBuffer(videoFrame) + } else { + localView?.videoView.renderVideoData(videoFrame) + } + return true + } + + func getVideoFormatPreference() -> AgoraVideoFormat { + .cvPixelBGRA + } +} + +extension LocalVideoTranscodingRTC: AgoraRtcMediaPlayerDelegate { + +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift new file mode 100644 index 000000000..d135b8241 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift @@ -0,0 +1,97 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct MediaChannelRelayEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: MediaChannelRelay(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + MediaChannelRelayEntry() +} + +struct MediaChannelRelay: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = MediaChannelRelayRTC() + @State private var relayChannelName: String = "" + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Text("Send stream to another channel".localized) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.top, 20) + .padding(.leading, 20) + TextField("Enter target relay channel name".localized, + text: $relayChannelName) + .textFieldStyle(.roundedBorder) + .padding(.horizontal, 15) + HStack { + Button("Relay".localized) { + agoraKit.doRelay(destinationChannelName: relayChannelName) + }.disabled(relayChannelName.isEmpty || agoraKit.isRelaying) + Spacer() + Button("Pause".localized) { + agoraKit.doPause() + }.opacity(agoraKit.isRelaying ? 1.0 : 0.0) + Spacer() + Button("Resume".localized) { + agoraKit.doResume() + }.opacity(agoraKit.isRelaying ? 1.0 : 0.0) + Spacer() + Button("Stop".localized) { + agoraKit.doStop() + }.opacity(agoraKit.isRelaying ? 1.0 : 0.0) + } + .padding(.top, 20) + .padding(.horizontal, 20) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + MediaChannelRelay(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaChannelRelay/MediaChannelRelayRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaChannelRelay/MediaChannelRelayRTC.swift new file mode 100644 index 000000000..27280f8eb --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaChannelRelay/MediaChannelRelayRTC.swift @@ -0,0 +1,247 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class MediaChannelRelayRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + @Published var isRelaying: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func doRelay(destinationChannelName: String) { + NetworkManager.shared.generateToken(channelName: destinationChannelName) { token in + // configure source info, channel name defaults to current, and uid defaults to local + let config = AgoraChannelMediaRelayConfiguration() + config.sourceInfo = AgoraChannelMediaRelayInfo(token: token) + + // configure target channel info + let destinationInfo = AgoraChannelMediaRelayInfo(token: token) + config.setDestinationInfo(destinationInfo, forChannelName: destinationChannelName) + self.agoraKit.startOrUpdateChannelMediaRelay(config) + } + } + + func doStop() { + agoraKit.stopChannelMediaRelay() + } + + func doPause() { + agoraKit.pauseAllChannelMediaRelay() + } + + func doResume() { + agoraKit.resumeAllChannelMediaRelay() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension MediaChannelRelayRTC: AgoraRtcEngineDelegate { + /// callback when a media relay process state changed + /// @param state state of media relay + /// @param error error details if media relay reaches failure state + func rtcEngine(_ engine: AgoraRtcEngineKit, + channelMediaRelayStateDidChange state: AgoraChannelMediaRelayState, + error: AgoraChannelMediaRelayError) { + LogUtils.log(message: "channelMediaRelayStateDidChange: \(state.rawValue) error \(error.rawValue)", level: .info) + + switch state { + case .running: + isRelaying = true + + case .failure: + LogUtils.log(message: "Media Relay Failed: \(error.rawValue)", level: .error) + isRelaying = false + + case .idle: + isRelaying = false + + default: break + } + } + + /// callback when a media relay event received + /// @param event event of media relay + func rtcEngine(_ engine: AgoraRtcEngineKit, didReceive event: AgoraChannelMediaRelayEvent) { + LogUtils.log(message: "didReceiveRelayEvent: \(event.rawValue)", level: .info) + } + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaPlayer/MediaPlayer.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaPlayer/MediaPlayer.swift new file mode 100644 index 000000000..45f153b56 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaPlayer/MediaPlayer.swift @@ -0,0 +1,169 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct MediaPlayerEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: MediaPlayer(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + MediaPlayerEntry() +} + +struct MediaPlayer: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = MediaPlayerRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + @State private var isShowPlayPickerView: Bool = false + @State private var isShowPublishPickerView: Bool = false + + var body: some View { + VStack { + VStack { + localView + remoteView + }.frame(height: 300) + ScrollView(.vertical) { + HStack { + TextField("", text: $agoraKit.url).textFieldStyle(.roundedBorder) + Button("Open".localized) { + agoraKit.doOpenMediaUrl() + }.padding(.leading, 10) + } + .padding(.horizontal, 20) + .padding(.top, 15) + HStack { + Slider(value: $agoraKit.playerProgressSlider).disabled(true) + Text(agoraKit.playerDurationLabel) + }.padding(.horizontal, 20) + HStack(alignment: .center, spacing: 10, content: { + Button("Play".localized) { + agoraKit.doPlay() + }.disabled(agoraKit.isPlaying) + Spacer() + Button("Stop".localized) { + agoraKit.doStop() + }.disabled(!agoraKit.isPlaying) + Spacer() + Button("Pause".localized) { + agoraKit.doPause() + }.disabled(!agoraKit.isPlaying) + Spacer() + Button("Publish".localized) { + agoraKit.doPublish() + }.disabled(!agoraKit.isPlaying || agoraKit.isPublished) + Spacer() + Button("stopPublish".localized) { + agoraKit.dloStopPublish() + }.disabled(!agoraKit.isPublished) + }) + .padding(.horizontal, 20) + .padding(.top, 20) + HStack { + Text("PlaybackVolume".localized).padding(.trailing, 15) + Slider(value: $agoraKit.playoutVolume, in: 0...400).onChange(of: agoraKit.playoutVolume) { value in + agoraKit.doAdjustPlayoutVolume(value: value) + } + }.padding(20) + HStack { + Text("Publish Volume".localized).padding(.trailing, 15) + Slider(value: $agoraKit.publishVolume, in: 0...100).onChange(of: agoraKit.publishVolume) { value in + agoraKit.doAdjustPublishVolume(value: value) + } + } + .padding(.horizontal, 20) + .padding(.bottom, 20) + + HStack { + Text("play Track:".localized).padding(.trailing, 5) + Button(agoraKit.codecName) { + withAnimation { + isShowPlayPickerView.toggle() + } + }.foregroundStyle(.gray) + Spacer() + Text("publish Track:".localized).padding(.trailing, 5) + Button(agoraKit.codecName) { + withAnimation { + isShowPublishPickerView.toggle() + } + }.foregroundStyle(.gray) + }.padding(20) + } + Spacer() + if isShowPlayPickerView { + let data = agoraKit.trackList?.compactMap({ $0.codecName }) + PickerView(dataArray: .constant(data ?? []), onTapCancel: { + withAnimation { + isShowPlayPickerView.toggle() + } + }, onTapSure: { value in + withAnimation { + isShowPlayPickerView.toggle() + } + agoraKit.onClickPlayAudioTrack(value: value) + }) + .transition(.move(edge: .bottom)) + .animation(.spring(), value: isShowPlayPickerView) + } + if isShowPublishPickerView { + let data = agoraKit.trackList?.compactMap({ $0.codecName }) + PickerView(dataArray: .constant(data ?? []), onTapCancel: { + withAnimation { + isShowPublishPickerView.toggle() + } + }, onTapSure: { value in + withAnimation { + isShowPublishPickerView.toggle() + } + agoraKit.onClickPublishAudioTrack(value: value) + }) + .transition(.move(edge: .bottom)) + .animation(.spring(), value: isShowPublishPickerView) + } + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + MediaPlayer(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaPlayer/MediaPlayerRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaPlayer/MediaPlayerRTC.swift new file mode 100644 index 000000000..86d92c364 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MediaPlayer/MediaPlayerRTC.swift @@ -0,0 +1,380 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +let CAMERA_UID = UInt.random(in: 1001...2000) +let PLAYER_UID = UInt.random(in: 2001...3000) +class MediaPlayerRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var mediaPlayerKit: AgoraRtcMediaPlayerProtocol! + private var playAudioTrackId: Int = 0 + private var publishTrackIndex: Int = 0 + private var channelName: String? + @Published var trackList: [AgoraRtcMediaStreamInfo]? + @Published var playoutVolume: CGFloat = 0 + @Published var publishVolume: CGFloat = 50 + @Published var url: String = "https://agora-adc-artifacts.s3.cn-north-1.amazonaws.com.cn/resources/sample.mp4" + @Published var playerDurationLabel: String = "00:00" + @Published var playerProgressSlider: Float = 0 + @Published var codecName: String = "aac" + @Published var isPlaying: Bool = false + @Published var isPublished: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + self.channelName = channelName + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + // prepare media player + mediaPlayerKit = agoraKit.createMediaPlayer(with: self) + mediaPlayerKit.setView(localView.videoView) + mediaPlayerKit.setRenderMode(.fit) + + playoutVolume = CGFloat(mediaPlayerKit.getPlayoutVolume()) + publishVolume = 50 + mediaPlayerKit.adjustPublishSignalVolume(50) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCustomAudioTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + option.autoSubscribeAudio = true + option.autoSubscribeVideo = true + NetworkManager.shared.generateToken(channelName: channelName, + uid: CAMERA_UID, + success: { token in + let result = self.agoraKit.joinChannel(byToken: token, + channelId: channelName, + uid: CAMERA_UID, + mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + agoraKit.muteRemoteAudioStream(PLAYER_UID, mute: true) + + setupChannel2(channelName: channelName) + } + + private func setupChannel2(channelName: String) { + let option1 = AgoraRtcChannelMediaOptions() + option1.autoSubscribeAudio = false + option1.autoSubscribeVideo = false + option1.clientRoleType = GlobalSettings.shared.getUserRole() + option1.enableAudioRecordingOrPlayout = false + let connection = AgoraRtcConnection() + connection.channelId = channelName + connection.localUid = PLAYER_UID + NetworkManager.shared.generateToken(channelName: channelName, uid: PLAYER_UID) { token in + let result1 = self.agoraKit.joinChannelEx(byToken: token, + connection: connection, + delegate: self, + mediaOptions: option1, + joinSuccess: nil) + if result1 != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result1), please check your params", level: .error) + } + self.doOpenMediaUrl() + } + localView?.setInfo(text: "") + } + + func doOpenMediaUrl() { + // resign text field + let mediaSource = AgoraMediaSource() + mediaSource.url = url + mediaSource.autoPlay = false + mediaSource.enableMultiAudioTrack = true + mediaPlayerKit.open(with: mediaSource) + } + + func doPlay() { + mediaPlayerKit.play() + isPlaying = true + } + + func doStop() { + mediaPlayerKit.stop() + doOpenMediaUrl() + isPlaying = false + } + + func doPause() { + mediaPlayerKit.pause() + isPlaying = false + } + + func doPublish() { + guard let channelName = channelName else { return } + let option = AgoraRtcChannelMediaOptions() + option.publishMediaPlayerVideoTrack = true + option.publishMediaPlayerAudioTrack = true + option.publishMediaPlayerId = Int(mediaPlayerKit.getMediaPlayerId()) + option.publishCameraTrack = false + let connection = AgoraRtcConnection() + connection.channelId = channelName + connection.localUid = PLAYER_UID + agoraKit.updateChannelEx(with: option, connection: connection) + isPublished = true + } + + func dloStopPublish() { + guard let channelName = channelName else { return } + let option = AgoraRtcChannelMediaOptions() + option.publishMediaPlayerVideoTrack = false + option.publishMediaPlayerAudioTrack = false + option.publishMediaPlayerId = Int(mediaPlayerKit.getMediaPlayerId()) + option.publishCameraTrack = false + let connection = AgoraRtcConnection() + connection.channelId = channelName + connection.localUid = PLAYER_UID + agoraKit.updateChannelEx(with: option, connection: connection) + isPublished = false + } + + func doAdjustPlayoutVolume(value: CGFloat) { + mediaPlayerKit.adjustPlayoutVolume(Int32(Int(value))) + } + + func doAdjustPublishVolume(value: CGFloat) { + mediaPlayerKit.adjustPublishSignalVolume(Int32(Int(value))) + } + + func onClickPlayAudioTrack(value: String) { + guard let track = trackList?.filter({ $0.codecName == value }).first else { return } + playAudioTrackId = track.streamIndex + mediaPlayerKit.selectMultiAudioTrack(track.streamIndex, + publishTrackIndex: publishTrackIndex) + } + + func onClickPublishAudioTrack(value: String) { + guard let track = trackList?.filter({ $0.codecName == value }).first else { return } + publishTrackIndex = track.streamIndex + mediaPlayerKit.selectMultiAudioTrack(playAudioTrackId, + publishTrackIndex: track.streamIndex) + } + + private func setupCanvasView(view: UIView?) { + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.view = view + videoCanvas.renderMode = .hidden + videoCanvas.sourceType = .mediaPlayer + videoCanvas.mediaPlayerId = mediaPlayerKit.getMediaPlayerId() + agoraKit.setupLocalVideo(videoCanvas) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + agoraKit.destroyMediaPlayer(mediaPlayerKit) + mediaPlayerKit = nil + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension MediaPlayerRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + // self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + if uid == CAMERA_UID || uid == PLAYER_UID { + return + } + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} +extension MediaPlayerRTC: AgoraRtcMediaPlayerDelegate { + + func AgoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, + didChangedTo state: AgoraMediaPlayerState, + reason: AgoraMediaPlayerReason) { + LogUtils.log(message: "player rtc channel publish helper state changed to: \(state.rawValue), error: \(reason.rawValue)", level: .info) + DispatchQueue.main.async {[weak self] in + guard let weakself = self else { return } + switch state.rawValue { + case 100: // failed + LogUtils.log(message: "media player error: \(reason.rawValue)", level: .error) + weakself.isPlaying = false + + case 2: // openCompleted + let duration = weakself.mediaPlayerKit.getDuration() + let format = "\(String(format: "%02d", duration / 60000)) : \(String(format: "%02d", duration % 60000 / 1000))" + weakself.playerDurationLabel = format + weakself.playerProgressSlider = 0 + + if weakself.mediaPlayerKit.getStreamCount() > 0 { + weakself.trackList = (0...weakself.mediaPlayerKit.getStreamCount()).filter({ + weakself.mediaPlayerKit.getStreamBy(Int32($0))?.streamType == .audio + }).compactMap({ weakself.mediaPlayerKit.getStreamBy(Int32($0)) }) + weakself.playAudioTrackId = weakself.trackList?.first?.streamIndex ?? 0 + weakself.publishTrackIndex = weakself.trackList?.first?.streamIndex ?? 0 + weakself.codecName = weakself.trackList?.first?.codecName ?? "" + } + + case 7: // stopped + weakself.playerProgressSlider = 0 + weakself.playerDurationLabel = "00 : 00" + guard let channelName = self?.channelName else { return } + let option = AgoraRtcChannelMediaOptions() + option.publishMediaPlayerVideoTrack = false + option.publishMediaPlayerAudioTrack = false + let connection = AgoraRtcConnection() + connection.channelId = channelName + connection.localUid = PLAYER_UID + weakself.agoraKit.updateChannelEx(with: option, connection: connection) + weakself.isPlaying = false + + default: break + } + } + } + + func AgoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, didChangedTo positionMs: Int, atTimestamp timestampMs: TimeInterval) { + let duration = Float(mediaPlayerKit.getDuration()) + var progress: Float = 0 + var left: Int = 0 + if duration > 0 { + progress = Float(positionMs) / duration + left = Int((mediaPlayerKit.getDuration() - positionMs)) / 1000 + } + DispatchQueue.main.async {[weak self] in + guard let weakself = self else { return } + weakself.playerDurationLabel = "\(String(format: "%02d", left / 60)) : \(String(format: "%02d", left % 60))" + weakself.playerProgressSlider = progress + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MutliCamera/MutliCamera.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MutliCamera/MutliCamera.swift new file mode 100644 index 000000000..876109c7b --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MutliCamera/MutliCamera.swift @@ -0,0 +1,79 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct MutliCameraEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: MutliCamera(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + MutliCameraEntry() +} + +struct MutliCamera: View { + @State var configs: [String: Any] = [:] + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = MutliCameraRTC() + @State private var isOpenCamera: Bool = false + @State private var title: String = "Open Rear Camera".localized + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + + }).toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button(title) { + isOpenCamera.toggle() + title = isOpenCamera ? "Close Rear Camera".localized : "Open Rear Camera".localized + agoraKit.onTapBackCameraButton(isOpenCamera) + } + } + } + } +} + +#Preview { + MutliCamera(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MutliCamera/MutliCameraRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MutliCamera/MutliCameraRTC.swift new file mode 100644 index 000000000..7d6ed0807 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/MutliCamera/MutliCameraRTC.swift @@ -0,0 +1,235 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class MutliCameraRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var channelName: String? + private lazy var uid: UInt = UInt.random(in: 1...9999) + private lazy var mutliCameraUid: UInt = UInt.random(in: 10000...9999999) + private var isOpenCamera: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + remoteView.setPlaceholder(text: "Second camera".localized) + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + self.channelName = channelName + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + // open Multi Camera + let capturerConfig = AgoraCameraCapturerConfiguration() + capturerConfig.cameraDirection = .rear + agoraKit.enableMultiCamera(true, config: capturerConfig) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, uid: uid, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: self.uid, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func onTapBackCameraButton(_ isOpenCamera: Bool) { + self.isOpenCamera = isOpenCamera + guard let channelName = self.channelName else {return} + let connection = AgoraRtcConnection() + connection.channelId = channelName + connection.localUid = mutliCameraUid + if isOpenCamera { + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = mutliCameraUid + videoCanvas.view = remoteView?.videoView + videoCanvas.renderMode = .hidden + videoCanvas.sourceType = .cameraSecondary + videoCanvas.mirrorMode = .disabled + agoraKit.setupLocalVideo(videoCanvas) + + let cameraConfig = AgoraCameraCapturerConfiguration() + cameraConfig.cameraDirection = .rear + cameraConfig.dimensions = remoteView?.videoView.frame.size ?? .zero + agoraKit.enableMultiCamera(true, config: cameraConfig) + agoraKit.startCameraCapture(.cameraSecondary, config: cameraConfig) + + let option = AgoraRtcChannelMediaOptions() + option.publishSecondaryCameraTrack = true + option.publishMicrophoneTrack = true + option.clientRoleType = .broadcaster + option.autoSubscribeAudio = false + option.autoSubscribeVideo = false + NetworkManager.shared.generateToken(channelName: channelName, uid: mutliCameraUid) { token in + self.agoraKit.joinChannelEx(byToken: token, connection: connection, delegate: self, mediaOptions: option, joinSuccess: nil) + self.agoraKit.muteRemoteAudioStream(self.mutliCameraUid, mute: true) + self.agoraKit.muteRemoteVideoStream(self.mutliCameraUid, mute: true) + } + } else { + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = mutliCameraUid + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + videoCanvas.sourceType = .cameraSecondary + agoraKit.setupLocalVideo(videoCanvas) + agoraKit.stopCameraCapture(.cameraSecondary) + agoraKit.leaveChannelEx(connection, leaveChannelBlock: nil) + } + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + if isOpenCamera { + guard let channelName = channelName else {return} + let connection = AgoraRtcConnection() + connection.channelId = channelName + connection.localUid = mutliCameraUid + agoraKit.stopCameraCapture(.cameraSecondary) + agoraKit.leaveChannelEx(connection, leaveChannelBlock: nil) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension MutliCameraRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + // self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/CustomRender/CustomRenderExample.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/CustomRender/CustomRenderExample.swift new file mode 100644 index 000000000..7e81291eb --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/CustomRender/CustomRenderExample.swift @@ -0,0 +1,86 @@ +// +// CustomRenderView.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/8/12. +// + +import SwiftUI + +struct CustomRenderMockContainerView: View { + @ObservedObject var viewModel: CustomRenderViewModel + + var localView = PixelBufferCustomRenderView() + + var body: some View { + HStack { + localView + ForEach(viewModel.remoteRenderViews) { view in + view + } + } + } +} + +struct CustomRenderExample: View { + @State var configs: [String: Any] + + //mock data + @StateObject private var customRenderViewModel: CustomRenderViewModel + + //pip controller + @StateObject private var pipViewModel: PIPViewModel + + let myContainerView: CustomRenderMockContainerView + + init(configs: [String: Any]) { + _configs = State(initialValue: configs) + + let viewModel = CustomRenderViewModel(configs: configs) + _customRenderViewModel = StateObject(wrappedValue: viewModel) + + myContainerView = CustomRenderMockContainerView(viewModel: viewModel) + let pipSourceView = UIHostingController(rootView: myContainerView).view! + _pipViewModel = StateObject(wrappedValue: PIPViewModel(pipSourceView: pipSourceView)) + } + + var body: some View { + VStack(spacing: 30) { + PIPDisplayView(viewModel: pipViewModel) + .frame(maxWidth: .infinity, maxHeight: 200) + + Button { + pipViewModel.togglePiP() + } label: { + Text("PIP") + } + + Button { + pipViewModel.changePIPSize { + let pipSizes = [ + CGSize(width: 150, height: 300), + CGSize(width: 300, height: 150) + ] + let i = Int.random(in: 0..(options: .weakMemory) + return table + }() + + func setLocalView(localView: PixelBufferRenderView) { + self.localView = localView + } + + func setupRtcEngine(rtcEngine: AgoraRtcEngineKit) { + rtcEngine.setVideoFrameDelegate(self) + } + + func addRemoteRenderView(renderView: PixelBufferRenderView) { + remoteRenderViews.add(renderView) + } + + func removeRemoteRenderView(renderView: PixelBufferRenderView) { + renderView.clean() + + remoteRenderViews.remove(renderView) + } +} + +extension CustomRenderRTC: AgoraVideoFrameDelegate { + func onCapture(_ videoFrame: AgoraOutputVideoFrame, sourceType: AgoraVideoSourceType) -> Bool { + if let localView = localView, let pixelBuffer = videoFrame.pixelBuffer { + localView.renderVideoPixelBuffer(pixelBuffer: pixelBuffer, width: videoFrame.width, height: videoFrame.height) + } + + return self.videoFrameDelegte?.onCapture?(videoFrame, sourceType: sourceType) ?? true + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, uid: UInt, channelId: String) -> Bool { + if let view = remoteRenderViews.allObjects.first(where: { $0.uid == uid }) { + view.renderFromVideoFrameData(videoData: videoFrame) + } + + return self.videoFrameDelegte?.onRenderVideoFrame?(videoFrame, uid: uid, channelId: channelId) ?? true + } + +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/CustomRender/CustomRenderViewModel.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/CustomRender/CustomRenderViewModel.swift new file mode 100644 index 000000000..9d18dd720 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/CustomRender/CustomRenderViewModel.swift @@ -0,0 +1,107 @@ +// +// CustomRenderExampleViewModel.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/8/13. +// + +import Foundation + +/** + @class CustomRenderViewModel( + @abstract This type has nothing to do with PIP and only simulates the implementation of rtc services for service reference and can be modified according to the service + */ +class CustomRenderViewModel: NSObject, ObservableObject { + @Published var remoteRenderViews: [PixelBufferCustomRenderView] = [] + private var isJoined = false + var customRenderRtc: CustomRenderRTC + var configs: [String: Any] + + 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: .fixedPortrait, + mirrorMode: .auto)) + + return engine + }() + + init(configs: [String: Any]) { + self.customRenderRtc = CustomRenderRTC() + self.configs = configs + super.init() + } + + func setupRtcEngine(localView: PixelBufferRenderView) { + guard let channelName = configs["channelName"] as? String else { return } + let uid = UInt.random(in: 1..<100000) + self.rtcEngine.setDefaultAudioRouteToSpeakerphone(true) + + self.customRenderRtc.setupRtcEngine(rtcEngine: self.rtcEngine) + self.customRenderRtc.setLocalView(localView: localView) + + NetworkManager.shared.generateToken(channelName: channelName, success: { [weak self] token in + guard let self = self else { return } + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = true + option.publishMicrophoneTrack = true + option.clientRoleType = .broadcaster + + self.rtcEngine.joinChannel(byToken: token, channelId: channelName, uid: uid, mediaOptions: option) + }) + } + + func cleanRtc() { + rtcEngine.disableAudio() + rtcEngine.disableVideo() + if isJoined { + rtcEngine.stopPreview() + rtcEngine.leaveChannel(nil) + } + } + + func addRenderView(renderView: PixelBufferCustomRenderView) { + remoteRenderViews.append(renderView) + + customRenderRtc.addRemoteRenderView(renderView: renderView.videoView) + } + + func removeRenderView(renderView: PixelBufferCustomRenderView) { + if let index = remoteRenderViews.firstIndex(where: { $0.videoView.uid == renderView.videoView.uid }) { + remoteRenderViews.remove(at: index) + } + + customRenderRtc.removeRemoteRenderView(renderView: renderView.videoView) + } +} + +extension CustomRenderViewModel: AgoraRtcEngineDelegate { + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + let renderView = PixelBufferCustomRenderView() + renderView.videoView.uid = uid + self.addRenderView(renderView: renderView) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + if let view = remoteRenderViews.first(where: { $0.videoView.uid == uid }) { + self.removeRenderView(renderView: view) + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/PIPCommon/PIPDisplayView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/PIPCommon/PIPDisplayView.swift new file mode 100644 index 000000000..36b92b4fe --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/PIPCommon/PIPDisplayView.swift @@ -0,0 +1,136 @@ +// +// RTCContainerView.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/8/12. +// +import SwiftUI +import Combine + +protocol PIPController { + + /** + Initializes the picture-in-picture controller + pipSourceView: The view that needs to be displayed in the picture-in-picture window + */ + init(pipSourceView: UIView) + + /** + Change the picture-in-picture window size + */ + func changePIPSize(size: () -> CGSize) + + /** + Open and close picture-in-picture + result: Picture-in-picture: true: on, flase: off + */ + @discardableResult func togglePiP() -> Bool +} + +/** + @class PIPDisplayView,SwiftUI Picture-in-picture view wrapper class + @abstract The picture-in-picture view is a UIKit-related API that allows you to bridge SwiftUI's controls to the PIP view (view with UIKit layout, class). + */ +struct PIPDisplayView: UIViewRepresentable { + ///PIP controller, used to control picture-in-picture + @ObservedObject var viewModel: PIPViewModel + + func makeUIView(context: Context) -> PIPBackgroundView { + return viewModel.backgroundView + } + + func updateUIView(_ uiView: PIPBackgroundView, context: Context) { } +} + +/** + @class PIPViewModel,Picture-in-picture view control class + @abstract Provide the view that needs to be displayed in picture to PIPViewModel to quickly realize the picture-in-picture function (picture-in-picture window open or close, window size switch) + */ +class PIPViewModel:NSObject, ObservableObject, PIPController { + var backgroundView: PIPBackgroundView + private var videoCallController: AVPictureInPictureVideoCallViewController? + private var pipController: AVPictureInPictureController? + + required init(pipSourceView: UIView) { + backgroundView = PIPBackgroundView(pipSourceView: pipSourceView) + videoCallController = AVPictureInPictureVideoCallViewController() + videoCallController?.preferredContentSize = UIScreen.main.bounds.size + videoCallController?.view.backgroundColor = .clear + videoCallController?.modalPresentationStyle = .overFullScreen + + super.init() + self.setupPIP() + } + + func setupPIP() { + guard let videoCallController = videoCallController else { return } + pipController = AVPictureInPictureController(contentSource: .init(activeVideoCallSourceView: backgroundView, contentViewController: videoCallController)) + pipController?.canStartPictureInPictureAutomaticallyFromInline = true + pipController?.delegate = self + pipController?.setValue(1, forKey: "controlsStyle") + } + + func changePIPSize(size: () -> CGSize) { + guard let vc = videoCallController else { return } + vc.preferredContentSize = size() + } + + @discardableResult func togglePiP() -> Bool { + guard let pipController = pipController else { return false } + + if pipController.isPictureInPictureActive { + pipController.stopPictureInPicture() + } else { + pipController.startPictureInPicture() + } + + return true + } +} + +/** + @class (inner class) PIPViewModel extension to handle draw-in-picture agent callbacks + @abstract Add or delete views through draw-in-picture proxy callbacks + */ +extension PIPViewModel: AVPictureInPictureControllerDelegate { + func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { + guard let vc = pictureInPictureController.contentSource?.activeVideoCallContentViewController, let pipSourceView = backgroundView.pipSourceView else { return } + + vc.view.addSubview(pipSourceView) + pipSourceView.frame = vc.view.bounds + } + + func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { + guard let pipSourceView = backgroundView.pipSourceView else { return } + + pipSourceView.removeFromSuperview() + backgroundView.addSubview(pipSourceView) + } +} + +/** + @class (Inner class) PIPBackgroundView + @abstract Picture-in-picture view wrapping class + */ +final class PIPBackgroundView: UIView { + weak var pipSourceView: UIView? + + init(pipSourceView: UIView, frame: CGRect = .zero) { + self.pipSourceView = pipSourceView + super.init(frame: frame) + if let view = self.pipSourceView { + self.addSubview(view) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + if let view = pipSourceView { + view.frame = bounds + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/PIPCommon/PixelBufferRenderView.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/PIPCommon/PixelBufferRenderView.swift new file mode 100644 index 000000000..ac118a6b1 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/PIPCommon/PixelBufferRenderView.swift @@ -0,0 +1,169 @@ +// +// PixelBufferRenderView.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/8/13. +// + +import Foundation +import SwiftUI + +/** + @struct PixelBufferCustomRenderView + @abstract SwiftUI bridge view, rendering view + */ +struct PixelBufferCustomRenderView: UIViewRepresentable, Identifiable { + let id = UUID() + let videoView = PixelBufferRenderView() + + func makeUIView(context: Context) -> UIView { + videoView.backgroundColor = .black + return videoView + } + + func updateUIView(_ uiView: UIView, context: Context) { + + } +} + +/** + @class PixelBufferRenderView + @abstract Render view, support PixelBuffer, YUV + */ +class PixelBufferRenderView: UIView { + var uid: UInt = 0 + private var videoWidth: Int32 = 0 + private var videoHeight: Int32 = 0 + + lazy var displayLayer: AVSampleBufferDisplayLayer = { + let layer = AVSampleBufferDisplayLayer() + layer.videoGravity = .resizeAspectFill + + return layer + }() + + override init(frame: CGRect) { + super.init(frame: frame) + configLayers() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configLayers() { + self.layer.addSublayer(displayLayer) + displayLayer.frame = self.bounds + } + + func createLayer() -> AVSampleBufferDisplayLayer { + let layer = AVSampleBufferDisplayLayer() + return layer + } + + func clean() { + uid = 0 + self.displayLayer.removeFromSuperlayer() + self.displayLayer = createLayer() + self.layer.addSublayer(displayLayer) + } + + func renderFromVideoFrameData(videoData: AgoraOutputVideoFrame) { + let width = videoData.width + let height = videoData.height + let yStride = videoData.yStride + let uStride = videoData.uStride + let vStride = videoData.vStride + + let yBuffer = videoData.yBuffer + let uBuffer = videoData.uBuffer + let vBuffer = videoData.vBuffer + + autoreleasepool { + var pixelBuffer: CVPixelBuffer? + let pixelAttributes: [String: Any] = [kCVPixelBufferIOSurfacePropertiesKey as String: [:]] + + let result = CVPixelBufferCreate(kCFAllocatorDefault, + Int(width), + Int(height), + kCVPixelFormatType_420YpCbCr8Planar, + pixelAttributes as CFDictionary, + &pixelBuffer) + + guard result == kCVReturnSuccess, let pixelBuffer = pixelBuffer else { + print("Unable to create CVPixelBuffer: \(result)") + return + } + + CVPixelBufferLockBaseAddress(pixelBuffer, .init(rawValue: 0)) + let yPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0) + let pixelBufferYBytes = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0) + + for i in 0.. CustomRenderExample { + return CustomRenderExample(configs: configs) + } + + private func sdkRenderView() -> SDKRenderExample{ + return SDKRenderExample(configs: configs) + } + +} + +#Preview { + PictureInPictureJoinEntry(pipType: .customRender) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/SDKRender/SDKRenderExample.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/SDKRender/SDKRenderExample.swift new file mode 100644 index 000000000..e45c5bd74 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/SDKRender/SDKRenderExample.swift @@ -0,0 +1,85 @@ +// +// SDKRenderExample.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/8/13. +// + +import SwiftUI + +struct SDKRenderMockContainerView: View { + @ObservedObject var viewModel: SDKRenderViewModel + let localView = VideoView() + + var body: some View { + HStack { + localView.frame(maxWidth: 200) + ForEach(viewModel.remoteRenderViews) { view in + view + } + } + } +} + +struct SDKRenderExample: View { + @State var configs: [String: Any] + + //mock data + @StateObject private var sdkRenderViewModel: SDKRenderViewModel + + //pip controller + @StateObject private var pipViewModel: PIPViewModel + + let myContainerView: SDKRenderMockContainerView + + init(configs: [String: Any]) { + _configs = State(initialValue: configs) + + let viewModel = SDKRenderViewModel(configs: configs) + _sdkRenderViewModel = StateObject(wrappedValue: viewModel) + + myContainerView = SDKRenderMockContainerView(viewModel: viewModel) + let pipSourceView = UIHostingController(rootView: myContainerView).view! + _pipViewModel = StateObject(wrappedValue: PIPViewModel(pipSourceView: pipSourceView)) + } + + var body: some View { + VStack(spacing: 30) { + PIPDisplayView(viewModel: pipViewModel) + .frame(maxWidth: .infinity, maxHeight: 200) + + Button { + pipViewModel.togglePiP() + } label: { + Text("PIP") + } + + Button { + pipViewModel.changePIPSize { + let pipSizes = [ + CGSize(width: 150, height: 300), + CGSize(width: 300, height: 150) + ] + let i = Int.random(in: 0..(options: .weakMemory) + return table + }() + + func setupRtcEngine(rtcEngine: AgoraRtcEngineKit) { + self.rtcEngine = rtcEngine + } + + func setLocalView(localView: VideoUIView) { + guard let rtcEngine = rtcEngine else { return } + self.localView = localView + + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = localView.uid + // the view to be binded + videoCanvas.view = localView.videoView + videoCanvas.renderMode = .hidden + + rtcEngine.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + rtcEngine.startPreview() + } + + func addRemoteRenderView(renderView: VideoUIView) { + guard let rtcEngine = rtcEngine else { return } + if renderView.uid == 0 { return } + // 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 = renderView.uid + // the view to be binded + videoCanvas.view = renderView.videoView + videoCanvas.renderMode = .hidden + rtcEngine.setupRemoteVideo(videoCanvas) + + remoteRenderViews.add(renderView) + } + + func removeRemoteRenderView(renderView: VideoUIView) { + guard let rtcEngine = rtcEngine else { return } + + renderView.uid = 0 + + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + rtcEngine.setupRemoteVideo(videoCanvas) + + remoteRenderViews.remove(renderView) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/SDKRender/SDKRenderViewModel.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/SDKRender/SDKRenderViewModel.swift new file mode 100644 index 000000000..c6ccf7c82 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PictureInPicture/SDKRender/SDKRenderViewModel.swift @@ -0,0 +1,109 @@ +// +// SDKRenderViewModel.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/8/14. +// + +import Foundation + +/** + @class SDKRenderViewModel( + @abstract This type has nothing to do with PIP and only simulates the implementation of rtc services for service reference and can be modified according to the service + */ +class SDKRenderViewModel: NSObject, ObservableObject { + private var isJoined = false + var sdkRenderRtc: SDKRenderRTC + var configs: [String: Any] + + @Published var remoteRenderViews: [VideoView] = [] + + 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: .fixedPortrait, + mirrorMode: .auto)) + + return engine + }() + + init(configs: [String: Any]) { + self.sdkRenderRtc = SDKRenderRTC() + self.configs = configs + super.init() + } + + func setupRtcEngine(localView: VideoUIView) { + guard let channelName = configs["channelName"] as? String else { return } + let uid = UInt.random(in: 1..<100000) + rtcEngine.setDefaultAudioRouteToSpeakerphone(true) + + sdkRenderRtc.setupRtcEngine(rtcEngine: rtcEngine) + sdkRenderRtc.setLocalView(localView: localView) + + NetworkManager.shared.generateToken(channelName: channelName, success: { [weak self] token in + guard let self = self else { return } + + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = true + option.publishMicrophoneTrack = true + option.clientRoleType = .broadcaster + self.rtcEngine.joinChannel(byToken: token, channelId: channelName, uid: uid, mediaOptions: option) + }) + } + + func cleanRtc() { + rtcEngine.disableAudio() + rtcEngine.disableVideo() + if isJoined { + rtcEngine.stopPreview() + rtcEngine.leaveChannel(nil) + } + AgoraRtcEngineKit.destroy() + } + + func addRenderView(renderView: VideoView) { + remoteRenderViews.append(renderView) + + sdkRenderRtc.addRemoteRenderView(renderView: renderView.videoView) + } + + func removeRenderView(renderView: VideoView) { + if let index = remoteRenderViews.firstIndex(where: { $0.videoView.uid == renderView.videoView.uid }) { + remoteRenderViews.remove(at: index) + } + + sdkRenderRtc.removeRemoteRenderView(renderView: renderView.videoView) + } +} + +extension SDKRenderViewModel: AgoraRtcEngineDelegate { + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + let renderView = VideoView() + renderView.videoView.uid = uid + self.addRenderView(renderView: renderView) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + if let view = remoteRenderViews.first(where: { $0.videoView.uid == uid }) { + self.removeRenderView(renderView: view) + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PrecallTest/PrecallTest.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PrecallTest/PrecallTest.swift new file mode 100644 index 000000000..fce6c87e9 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PrecallTest/PrecallTest.swift @@ -0,0 +1,93 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct PrecallTest: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = PrecallTestRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + + var body: some View { + GeometryReader { geo in + ZStack { + VStack { + ActivityIndicator(isAnimating: $agoraKit.startActivityView, + style: .large).opacity(agoraKit.isStartLastmileTest ? 1.0 : 0.0) + Text("Echo Pretest") + .frame(width: 300, alignment: .leading) + .padding(.top, 50) + .font(.title) + + Button("Start Audio Device Loopback Test") { + agoraKit.doEchoTest() + } + .frame(width: 300, alignment: .leading) + .padding(.vertical, 10) + + Button("Start Lastmile Test") { + agoraKit.doLastmileTest() + } + .frame(width: 300, alignment: .leading) + .padding(.vertical, 10) + + Button(agoraKit.isStartCameraTest ? "Stop Camera Test" : "Start Camera Test") { + agoraKit.doCameraTest() + } + .frame(width: 300, alignment: .leading) + .padding(.vertical, 10) + + ZStack { + Text(agoraKit.lastmileResultLabel) + .frame(width: 300, alignment: .leading) + .padding(.vertical, 10) + .opacity(agoraKit.isStartLastmileTest ? 1.0 : 0.0) + + localView.opacity(agoraKit.isStartCameraTest ? 1.0 : 0.0) + } + + Spacer() + } + VStack { + Text("\(agoraKit.countDown)").font(.title) + Text(agoraKit.isRecordEnd ? "Now you should hear what you said..." : "Please say something...") + } + .frame(width: geo.size.width, + height: geo.size.height) + .background(.black.opacity(0.3)) + .opacity(agoraKit.isEchoTestEnd ? 0.0 : 1.0) + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }).navigationBarTitleDisplayMode(.inline) + } + } +} + +#Preview { + PrecallTest(configs: [:]) +} + + +struct ActivityIndicator: UIViewRepresentable { + @Binding var isAnimating: Bool + let style: UIActivityIndicatorView.Style + + func makeUIView(context: UIViewRepresentableContext) -> UIActivityIndicatorView { + return UIActivityIndicatorView(style: style) + } + + func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext) { + isAnimating ? uiView.startAnimating() : uiView.stopAnimating() + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PrecallTest/PrecallTestRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PrecallTest/PrecallTestRTC.swift new file mode 100644 index 000000000..a16cd08ce --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/PrecallTest/PrecallTestRTC.swift @@ -0,0 +1,169 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class PrecallTestRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var timer: Timer? + private var localView: VideoUIView? + + @Published var startActivityView: Bool = false + @Published var isStartCameraTest: Bool = false + @Published var countDown: Int = 10 + @Published var isRecordEnd: Bool = false + @Published var isEchoTestEnd: Bool = true + @Published var lastmileResultLabel: String = "" + @Published var isStartLastmileTest: Bool = false + + func setupRTC(configs: [String: Any], localView: VideoUIView) { + self.localView = localView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // have to be a broadcaster for doing echo test + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + } + + func doLastmileTest() { + agoraKit.stopEchoTest() + if isStartCameraTest { + doCameraTest() + } + startActivityView = true + let config = AgoraLastmileProbeConfig() + // do uplink testing + config.probeUplink = true + // do downlink testing + config.probeDownlink = true + // expected uplink bitrate, range: [100000, 5000000] + config.expectedUplinkBitrate = 100000 + // expected downlink bitrate, range: [100000, 5000000] + config.expectedDownlinkBitrate = 100000 + agoraKit.startLastmileProbeTest(config) + isStartLastmileTest = true + } + + func doEchoTest() { + isStartLastmileTest = false + agoraKit.stopLastmileProbeTest() + if isStartCameraTest { + doCameraTest() + } + let testConfig = AgoraEchoTestConfiguration() + testConfig.intervalInSeconds = 10 + testConfig.enableAudio = true + testConfig.enableVideo = false + testConfig.channelId = "AudioEchoTest" + "\(Int.random(in: 1...1000))" + let ret = agoraKit.startEchoTest(withConfig: testConfig) + if ret != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "startEchoTest call failed: \(ret), please check your params", level: .error) + } + isRecordEnd = false + isEchoTestEnd = false + showPopover(seconds: 10) { [weak self] in + self?.isRecordEnd = true + self?.showPopover(seconds: 10) { [weak self] in + self?.agoraKit.stopEchoTest() + self?.isEchoTestEnd = true + } + } + } + + func doCameraTest() { + isStartCameraTest.toggle() + isStartLastmileTest = false + agoraKit.stopEchoTest() + if isStartCameraTest { + let testConfig = AgoraEchoTestConfiguration() + testConfig.intervalInSeconds = 2 + testConfig.enableAudio = true + testConfig.enableVideo = true + testConfig.channelId = "VideoEchoTest" + "\(Int.random(in: 1...1000))" + testConfig.view = localView?.videoView + let ret = agoraKit.startEchoTest(withConfig: testConfig) + if ret != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "startEchoTest call failed: \(ret), please check your params", level: .error) + } + } else { + agoraKit.stopEchoTest() + } + } + + // show popover and hide after seconds + func showPopover(seconds: Int, callback: @escaping (() -> Void)) { + countDown = seconds + timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in + guard let self = self else { return } + self.countDown -= 1 + // swiftlint:disable empty_count + if countDown == 0 { + // swiftlint:enable empty_count + self.timer?.invalidate() + callback() + } + } + } + + func onDestory() { + timer?.invalidate() + timer = nil + agoraKit.stopEchoTest() + agoraKit.stopLastmileProbeTest() + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension PrecallTestRTC: AgoraRtcEngineDelegate { + /// callback to get lastmile quality 2seconds after startLastmileProbeTest + func rtcEngine(_ engine: AgoraRtcEngineKit, lastmileQuality quality: AgoraNetworkQuality) { + lastmileResultLabel = "Quality: \(quality.description())" + } + + /// callback to get more detail lastmile quality after startLastmileProbeTest + func rtcEngine(_ engine: AgoraRtcEngineKit, lastmileProbeTest result: AgoraLastmileProbeResult) { + let rtt = "Rtt: \(result.rtt)ms" + let downlinkBandwidth = "DownlinkAvailableBandwidth: \(result.downlinkReport.availableBandwidth)Kbps" + let downlinkJitter = "DownlinkJitter: \(result.downlinkReport.jitter)ms" + let downlinkLoss = "DownlinkLoss: \(result.downlinkReport.packetLossRate)%" + + let uplinkBandwidth = "UplinkAvailableBandwidth: \(result.uplinkReport.availableBandwidth)Kbps" + let uplinkJitter = "UplinkJitter: \(result.uplinkReport.jitter)ms" + let uplinkLoss = "UplinkLoss: \(result.uplinkReport.packetLossRate)%" + + let result = [rtt, + downlinkBandwidth, + downlinkJitter, + downlinkLoss, + uplinkBandwidth, + uplinkJitter, + uplinkLoss].joined(separator: "\n") + lastmileResultLabel += "\n" + result + // stop testing after get last mile detail result + engine.stopLastmileProbeTest() + startActivityView = false + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/QuickSwitchChannel/QuickSwitchChannel.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/QuickSwitchChannel/QuickSwitchChannel.swift new file mode 100644 index 000000000..f5f39d944 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/QuickSwitchChannel/QuickSwitchChannel.swift @@ -0,0 +1,87 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct QuickSwitchChannelEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: QuickSwitchChannel(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + QuickSwitchChannelEntry() +} + +struct QuickSwitchChannel: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = QuickSwitchChannelRTC() + var remoteView = VideoView(type: .remote, + audioOnly: false) + + @State private var currentIndex: Int = 0 + + var body: some View { + VStack { + ZStack { + remoteView.zIndex(0) + TabView(selection: $currentIndex) { + ForEach(1...20, id: \.self) { index in + let channelName = configs["channelName"] as? String + Text("channelName: \(channelName ?? "")\(index)") + .frame(width: 375, + height: 667, + alignment: .topLeading) + } + } + .zIndex(1) + .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) + .onChange(of: currentIndex) { value in + joinChannel(index: value) + } + } + }.onAppear(perform: { + currentIndex = 1 + agoraKit.setupRTC(configs: configs, + remoteView: remoteView.videoView) + joinChannel(index: currentIndex) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } + + private func joinChannel(index: Int) { + let channelName = configs["channelName"] as? String + let channel = "\(channelName ?? "")\(index)" + agoraKit.joinChannel(channelName: channel) + } +} + +#Preview { + QuickSwitchChannel(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/QuickSwitchChannel/QuickSwitchChannelRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/QuickSwitchChannel/QuickSwitchChannelRTC.swift new file mode 100644 index 000000000..e1118ab1f --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/QuickSwitchChannel/QuickSwitchChannelRTC.swift @@ -0,0 +1,160 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class QuickSwitchChannelRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], remoteView: VideoUIView) { + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(.audience) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + } + + func joinChannel(channelName: String) { + agoraKit.leaveChannel() + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = false + option.autoSubscribeAudio = true + option.autoSubscribeVideo = true + option.clientRoleType = .audience + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + self.remoteView?.setPlaceholder(text: "channel: \(channelName)") + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension QuickSwitchChannelRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RTMPStream/RTMPStream.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RTMPStream/RTMPStream.swift new file mode 100644 index 000000000..a3b55c6a2 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RTMPStream/RTMPStream.swift @@ -0,0 +1,86 @@ +// +// RTMStream.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/10/8. +// + +import SwiftUI + +struct RTMPStreamEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + Text("Ensure that you enable the RTMP Converter service at Agora Dashboard before using this function.") + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: RTMPStream(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .padding(.horizontal, 40) + .navigationBarTitleDisplayMode(.inline) + } +} + +struct RTMPStream: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = RTMPStreamRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + + if agoraKit.isJoined { + VStack { + HStack { + TextField("", text: $agoraKit.rtmpUrl) + .disabled(agoraKit.isPublished) + + Button(agoraKit.isPublished ? "stopPublish".localized : "Publish".localized) { + agoraKit.onPublish() + } + } + HStack { + Spacer() + Toggle("Transcoding".localized, isOn: $agoraKit.transcodingState) + .disabled(agoraKit.isPublished) + .frame(width: 100) + } + } + .padding(.horizontal, 40) + } + + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + RTMPStream() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RTMPStream/RTMPStreamRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RTMPStream/RTMPStreamRTC.swift new file mode 100644 index 000000000..20dda0e59 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RTMPStream/RTMPStreamRTC.swift @@ -0,0 +1,277 @@ +// +// RTMStreamRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/10/8. +// + +import Foundation +import AgoraRtcKit + +class RTMPStreamRTC: NSObject, ObservableObject { + @Published var transcodingState = true + @Published var isJoined = false + @Published var isPublished: Bool = false + @Published var rtmpUrl: String = "rtmp://push.webdemo.agoraio.cn/lbhd/test" + + var agoraKit: AgoraRtcEngineKit! + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var remoteUid: UInt? + private var transcoding = AgoraLiveTranscoding.default() + private let CANVAS_WIDTH = 640 + private let CANVAS_HEIGHT = 480 + + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + guard let channelName = configs["channelName"] as? String else {return} + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + let resolution = (GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize) ?? .zero + let fps = (GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate) ?? .fps15 + let orientation = (GlobalSettings.shared.getSetting(key: "orientation")? + .selectedOption().value as? AgoraVideoOutputOrientationMode) ?? .fixedPortrait + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, + mirrorMode: .auto)) + + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = localView.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + } + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + if isPublished { + agoraKit.stopRtmpStream(rtmpUrl) + } + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func onPublish() { + if rtmpUrl.isEmpty { + return + } + + if isPublished { + // stop rtmp streaming + agoraKit.stopRtmpStream(rtmpUrl) + } else { + // check whether we need to enable transcoding + let transcodingEnabled = transcodingState + if transcodingEnabled { + // we will use transcoding to composite multiple hosts' video + // therefore we have to create a livetranscoding object and call before addPublishStreamUrl + transcoding.size = CGSize(width: CANVAS_WIDTH, height: CANVAS_HEIGHT) + agoraKit.startRtmpStream(withTranscoding: rtmpUrl, transcoding: transcoding) + + if let remoteUid = remoteUid { + // add new user onto the canvas + let user = AgoraLiveTranscodingUser() + user.rect = CGRect(x: CANVAS_WIDTH / 2, y: 0, width: CANVAS_WIDTH / 2, height: CANVAS_HEIGHT) + user.uid = remoteUid + self.transcoding.add(user) + // remember you need to call setLiveTranscoding again if you changed the layout + agoraKit.updateRtmpTranscoding(transcoding) + } + + } else { + agoraKit.startRtmpStreamWithoutTranscoding(rtmpUrl) + } + } + } +} + +extension RTMPStreamRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode.description)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + + // add transcoding user so the video stream will be involved + // in future RTMP Stream + let user = AgoraLiveTranscodingUser() + user.rect = CGRect(x: 0, y: 0, width: CANVAS_WIDTH / 2, height: CANVAS_HEIGHT) + user.uid = uid + self.transcoding.add(user) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + + // remove preivous user from the canvas + if let existingUid = remoteUid { + transcoding.removeUser(existingUid) + } + remoteUid = uid + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason.rawValue)", level: .info) + + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + + // check whether we have enabled transcoding + let transcodingEnabled = transcodingState + if transcodingEnabled { + // remove user from canvas if current cohost left channel + if let existingUid = remoteUid { + transcoding.removeUser(existingUid) + } + remoteUid = nil + agoraKit.updateRtmpTranscoding(transcoding) + } + } + + /// callback for state of rtmp streaming, for both good and bad state + /// @param url rtmp streaming url + /// @param state state of rtmp streaming + /// @param reason + func rtcEngine(_ engine: AgoraRtcEngineKit, + rtmpStreamingChangedToState url: String, + state: AgoraRtmpStreamingState, + reason: AgoraRtmpStreamingReason) { + LogUtils.log(message: "streamStateChanged: \(url) state \(state.rawValue) error \(reason.rawValue)", level: .info) + if state == .running { + isPublished = true + ToastView.show(text: "RTMP Publish Success") + } else if state == .failure { + ToastView.show(text: "RTMP Publish Failed: \(reason.rawValue)") + } else if state == .idle { + isPublished = false + ToastView.show(text: "RTMP Publish Stopped") + } + } + + /// callback when live transcoding is properly updated + func rtcEngineTranscodingUpdated(_ engine: AgoraRtcEngineKit) { + LogUtils.log(message: "live transcoding updated", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawAudioData/RawAudioData.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawAudioData/RawAudioData.swift new file mode 100644 index 000000000..1ac82b95e --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawAudioData/RawAudioData.swift @@ -0,0 +1,80 @@ +// +// RawAudioData.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import SwiftUI + +struct RawAudioDataEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: RawAudioData(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct RawAudioData: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = RawAudioDataRTC() + + var localView = VideoView(type: .local, + audioOnly: true) + var remoteView = VideoView(type: .remote, + audioOnly: true) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + + HStack { + TextField("Please Enter Data".localized, text: $agoraKit.audioData) + .frame(height: 35) + .border(Color(UIColor.separator)) + .padding(.leading, 40) + + Button("Send".localized) { + agoraKit.sendData() + } + .padding(.trailing, 20) + .disabled(agoraKit.audioData.count == 0) + Spacer() + } + .padding(.top, 50) + + Spacer() + } + .onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + RawAudioData() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawAudioData/RawAudioDataRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawAudioData/RawAudioDataRTC.swift new file mode 100644 index 000000000..843e4d4eb --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawAudioData/RawAudioDataRTC.swift @@ -0,0 +1,142 @@ +// +// RawAudioDataRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import Foundation +import AgoraRtcKit + +class RawAudioDataRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + @Published var isJoined: Bool = false + @Published var audioData: String = "" + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + guard let channelId = configs["channelName"] as? String else {return} + + self.localView = localView + self.remoteView = remoteView + + agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: KeyCenter.AppId, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // Audio4 is required to send Audio Meta Data. + agoraKit.setParameters("{\"rtc.use_audio4\":true}") + + // Setup raw auido data frame observer + agoraKit.setAudioFrameDelegate(self) + agoraKit.enableAudio() + NetworkManager.shared.generateToken(channelName: channelId, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelId, info: nil, uid: 0) + if result != 0 { + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + } + }) + } + + func sendData() { + guard let data = audioData.data(using: .utf8) else { return } + agoraKit.sendAudioMetadata(data) + audioData = "" + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func getAudioLabel(uid: UInt, isLocal: Bool) -> String { + return "AUDIO ONLY\n\(isLocal ? "Local" : "Remote")\n\(uid)" + } +} + +extension RawAudioDataRTC: AgoraAudioFrameDelegate { + func onEarMonitoringAudioFrame(_ frame: AgoraAudioFrame) -> Bool { + true + } + + func getEarMonitoringAudioParams() -> AgoraAudioParams { + AgoraAudioParams() + } + + func getMixedAudioParams() -> AgoraAudioParams { + AgoraAudioParams() + } + + func getRecordAudioParams() -> AgoraAudioParams { + AgoraAudioParams() + } + + func getPlaybackAudioParams() -> AgoraAudioParams { + AgoraAudioParams() + } + + func onRecordAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool { + true + } + + func getObservedAudioFramePosition() -> AgoraAudioFramePosition { + .mixed + } + + func onRecord(_ frame: AgoraAudioFrame, channelId: String) -> Bool { + return true + } + + func onPlaybackAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool { + return true + } + + func onMixedAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool { + return true + } + + func onPlaybackAudioFrame(beforeMixing frame: AgoraAudioFrame, channelId: String, uid: UInt) -> Bool { + return true + } +} + +// MARK: - AgoraRtcEngineDelegate +extension RawAudioDataRTC: AgoraRtcEngineDelegate { + func rtcEngine(_ engine: AgoraRtcEngineKit, audioMetadataReceived uid: UInt, metadata: Data) { + let data = String(data: metadata, encoding: .utf8) ?? "" + ToastView.show(text: "uid: \(uid) data: \(data)") + } + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "Error occur: \(errorCode)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + localView?.setPlaceholder(text: self.getAudioLabel(uid: uid, isLocal: true)) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + LogUtils.log(message: "Remote user \(uid) joined elapsed \(elapsed)ms", level: .info) + remoteView?.setPlaceholder(text: self.getAudioLabel(uid: uid, isLocal: false)) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + LogUtils.log(message: "Remote user \(uid) offline with reason \(reason)", level: .info) + remoteView?.setPlaceholder(text: self.getAudioLabel(uid: 0, isLocal: false)) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawVideoData/RawVideoData.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawVideoData/RawVideoData.swift new file mode 100644 index 000000000..d3b79bbd7 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawVideoData/RawVideoData.swift @@ -0,0 +1,78 @@ +// +// RawVideoData.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import SwiftUI + +struct RawVideoDataEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: RawVideoData(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct RawVideoData: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = RawVideoDataRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + var body: some View { + VStack { + HStack{ + localView + remoteView + } + .frame(maxHeight: 200) + .padding(.bottom, 50) + + Button("screenshot".localized) { + agoraKit.isSnapShoting = true + } + .disabled(!agoraKit.isJoined) + .padding(.bottom, 10) + + if let image = agoraKit.screenshot { + Image(uiImage: image) + .resizable() + .scaledToFit() + .frame(height: 400) + } + Spacer() + } + .onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + RawVideoData() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawVideoData/RawVideoDataRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawVideoData/RawVideoDataRTC.swift new file mode 100644 index 000000000..46c3980db --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RawVideoData/RawVideoDataRTC.swift @@ -0,0 +1,164 @@ +// +// RawVideoDataRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import Foundation +import AgoraRtcKit + +class RawVideoDataRTC: NSObject, ObservableObject { + @Published var isJoined: Bool = false + @Published var isSnapShoting: Bool = false + @Published var screenshot: UIImage? + + private var agoraKit: AgoraRtcEngineKit! + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + guard let channelId = configs["channelName"] as? String, + let resolution = GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize, + let fps = GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate, + let orientation = GlobalSettings.shared.getSetting(key: "orientation")? + .selectedOption().value as? AgoraVideoOutputOrientationMode else { + return + } + + self.localView = localView + self.remoteView = remoteView + + agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: KeyCenter.AppId, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // Setup raw video data frame observer + agoraKit.setVideoFrameDelegate(self) + + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, + mirrorMode: .auto)) + + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.view = localView.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + + agoraKit.startPreview() + + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + + NetworkManager.shared.generateToken(channelName: channelId, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelId, uid: 0, mediaOptions: option, joinSuccess: nil) + if result != 0 { + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + } + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +extension RawVideoDataRTC: AgoraVideoFrameDelegate { + func onCapture(_ videoFrame: AgoraOutputVideoFrame, + sourceType: AgoraVideoSourceType) -> Bool { + true + } + + func onRenderVideoFrame(_ videoFrame: AgoraOutputVideoFrame, + uid: UInt, + channelId: String) -> Bool { + if isSnapShoting { + isSnapShoting = false + guard let pixelBuffer = videoFrame.pixelBuffer else { return true } + let image = MediaUtils.pixelBuffer(toImage: pixelBuffer) + DispatchQueue.main.async { + self.screenshot = image + } + } + return true + } + func getVideoFormatPreference() -> AgoraVideoFormat { + .cvPixelBGRA + } +} + +// MARK: - AgoraRtcEngineDelegate +extension RawVideoDataRTC: AgoraRtcEngineDelegate { + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "Error occur: \(errorCode)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) { + LogUtils.log(message: "Remote user \(uid) joined elapsed \(elapsed)ms", level: .info) + + // Render remote user video frame at a UIView + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.view = remoteView?.videoView + videoCanvas.uid = uid + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) { + LogUtils.log(message: "Remote user \(uid) offline with reason \(reason)", level: .info) + + // Stop render remote user video frame + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.view = nil + videoCanvas.uid = uid + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RhythmPlayer/RhythmPlayer.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RhythmPlayer/RhythmPlayer.swift new file mode 100644 index 000000000..b04ecfec8 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RhythmPlayer/RhythmPlayer.swift @@ -0,0 +1,149 @@ +// +// JoinchannelVideoEnter.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI +import AgoraRtcKit + +struct RhythmPlayerEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var isShowAudioScence: Bool = false + @State private var isShowAudioProfile: Bool = false + @State private var profile: AgoraAudioProfile = .default + @State private var scenario: AgoraAudioScenario = .default + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + HStack { + Text("Audio Scenario".localized) + Spacer() + Button { + self.isShowAudioProfile = true + } label: { + Text(scenario.description()) + }.confirmationDialog("Set Audio Scenario".localized, isPresented: $isShowAudioProfile, titleVisibility: .visible) { + ForEach(AgoraAudioScenario.allValues(), id: \.self) { item in + getAudioScenarioAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 15, trailing: 35)) + HStack { + Text("Audio Profile".localized) + Spacer() + Button(profile.description()) { + self.isShowAudioScence = true + }.confirmationDialog("Set Audio Profile".localized, isPresented: $isShowAudioScence, titleVisibility: .visible) { + ForEach(AgoraAudioProfile.allValues(), id: \.self) { item in + getAudioProfileAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 0, trailing: 35)) + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName, + "audioProfile": profile, + "audioScenario": scenario] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: RhythmPlayer(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } + + private func getAudioProfileAction(_ profile: AgoraAudioProfile) -> some View { + Button(profile.description()){ + self.profile = profile + } + } + + private func getAudioScenarioAction(_ scenario: AgoraAudioScenario) -> some View { + Button(scenario.description()){ + self.scenario = scenario + } + } +} + +#Preview { + RhythmPlayerEntry() +} + +struct RhythmPlayer: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = RhythmPlayerRTC() + @State private var beatsMinute: Float = 60 + @State private var beatsMeasure: Float = 4 + @State private var isPlaying: Bool = false + + var localView = VideoView(type: .local, + audioOnly: true) + var remoteView = VideoView(type: .remote, + audioOnly: true) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + HStack { + Text("Beats per Minute".localized) + Spacer() + Slider(value: $beatsMinute, in: 60...360).onChange(of: beatsMinute) { value in + agoraKit.onChangeBeatsMinute(value) + } + .frame(width: 150) + .disabled(agoraKit.isEnabelBeatsMinute) + }.padding(.horizontal, 20) + HStack { + Text("Beats per Measure".localized) + Spacer() + Slider(value: $beatsMeasure, in: 1...9).onChange(of: beatsMeasure) { value in + agoraKit.onChangeBeatsMeasure(value) + } + .frame(width: 150) + .disabled(agoraKit.isEnabelBeatsMeasure) + }.padding(.horizontal, 20) + HStack { + Button("Play".localized) { + agoraKit.onPlay() + isPlaying = true + }.disabled(isPlaying) + Spacer() + Button("Stop".localized) { + agoraKit.onStop() + isPlaying = false + }.disabled(!isPlaying) + } + .padding(.horizontal, 90) + .padding(.top, 30) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + RhythmPlayer(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RhythmPlayer/RhythmPlayerRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RhythmPlayer/RhythmPlayerRTC.swift new file mode 100644 index 000000000..33eae3a36 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/RhythmPlayer/RhythmPlayerRTC.swift @@ -0,0 +1,240 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + + +let DING = "https://webdemo.agora.io/ding.mp3" +let DANG = "https://webdemo.agora.io/dang.mp3" +class RhythmPlayerRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var config: AgoraRhythmPlayerConfig = AgoraRhythmPlayerConfig() + + @Published var isEnabelBeatsMinute: Bool = false + @Published var isEnabelBeatsMeasure: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + guard let channelName = configs["channelName"] as? String, + let audioProfile = configs["audioProfile"] as? AgoraAudioProfile, + let audioScenario = configs["audioScenario"] as? AgoraAudioScenario + else { return } + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + // set audio scenario + config.audioScenario = audioScenario + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // disable video module + agoraKit.disableVideo() + + agoraKit.enableAudio() + + let resolution = (GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize) ?? .zero + let fps = (GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate) ?? .fps15 + let orientation = (GlobalSettings.shared.getSetting(key: "orientation")? + .selectedOption().value as? AgoraVideoOutputOrientationMode) ?? .fixedPortrait + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, + mirrorMode: .auto)) + + // set audio profile + agoraKit.setAudioProfile(audioProfile) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // enable volume indicator + agoraKit.enableAudioVolumeIndication(200, smooth: 3, reportVad: true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = true + option.autoSubscribeAudio = true + option.autoSubscribeVideo = false + option.clientRoleType = GlobalSettings.shared.getUserRole() + + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func onPlay() { + agoraKit.startRhythmPlayer(DING, sound2: DANG, config: config) + isEnabelBeatsMinute = true + isEnabelBeatsMeasure = true + } + + func onStop() { + agoraKit.stopRhythmPlayer() + isEnabelBeatsMinute = false + isEnabelBeatsMeasure = false + } + + func onChangeBeatsMinute(_ value: Float) { + config.beatsPerMinute = Int32(value) + } + + func onChangeBeatsMeasure(_ value: Float) { + config.beatsPerMeasure = Int32(value) + } + + func onDestory() { + agoraKit.enable(inEarMonitoring: false) + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func setAudioScenario(scenario: AgoraAudioScenario) { + agoraKit.setAudioScenario(scenario) + } +} + +// agora rtc engine delegate events +extension RhythmPlayerRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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 = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// Reports which users are speaking, the speakers' volumes, and whether the local user is speaking. + /// @params speakers volume info for all speakers + /// @params totalVolume Total volume after audio mixing. The value range is [0,255]. + func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) { +// for speaker in speakers { +// if let audioView = audioViews[speaker.uid] { +// audioView.setInfo(text: "Volume:\(speaker.volume)") +// } +// } + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ScreenShare/ScreenShare.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ScreenShare/ScreenShare.swift new file mode 100644 index 000000000..c3c1026aa --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ScreenShare/ScreenShare.swift @@ -0,0 +1,177 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct ScreenShareEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: ScreenShare(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + ScreenShareEntry() +} + +struct ScreenShare: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = ScreenShareRTC() + @State private var isStart: Bool = false + @State private var isCaptureAudio: Bool = false + @State private var isCaptureVideo: Bool = false + @State private var signalVolumeValue: Float = 0.5 + @State private var isShowPickerView: Bool = false + @State private var fpsDataSources: [Int] = [15, 30, 60] + @State private var scenarioTypeDataSources: [String: Int] = ["document": 1, "gaming": 2, "video": 3, "RDC": 4] + @State private var scenarioType: String = "video" + @State private var isShowFps: Bool = false + @State private var fps: String = "60" + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + HStack { + Text("captureAudio") + Toggle("", isOn: $isCaptureAudio) + .frame(width: 50) + .onChange(of: isCaptureAudio) { value in + agoraKit.clickCaptureAudio(value) + } + Spacer() + Text("captureVideo") + Toggle("", isOn: $isCaptureVideo) + .frame(width: 50) + .onChange(of: isCaptureVideo) { value in + agoraKit.clickCaptureVideo(value) + } + } + .padding(.horizontal, 20) + .padding(.top, 20) + HStack { + Text("captureSignalVolume") + Slider(value: $signalVolumeValue) + .onChange(of: signalVolumeValue) { value in + agoraKit.captureSignalVolumeSlider(value) + } + }.padding(.horizontal, 20) + HStack { + Text("captureFrameRate") + Spacer() + Button(fps + "fps") { + withAnimation { + isShowFps.toggle() + } + } + } + .padding(.horizontal, 20) + .padding(.top, 15) + HStack { + Text("ScreenScenarioType") + Spacer() + Button(scenarioType) { + withAnimation { + isShowPickerView.toggle() + } + } + } + .padding(.horizontal, 20) + .padding(.top, 15) + + HStack { + Button("stopScreen") { + isStart.toggle() + agoraKit.stopScreenCapture() + }.disabled(!isStart) + Spacer() + Button("startScreen") { + isStart.toggle() + agoraKit.startScreenCapture() + }.disabled(isStart) + Spacer() + Button("updateScreen") { + agoraKit.updateScreenCapture() + }.disabled(!isStart) + } + .padding(.horizontal, 20) + .padding(.top, 25) + Spacer() + if isShowPickerView { + let data = scenarioTypeDataSources.map({ $0.key }) + PickerView(dataArray: .constant(data), onTapCancel: { + withAnimation { + isShowPickerView.toggle() + } + }, onTapSure: { value in + withAnimation { + isShowPickerView.toggle() + } + scenarioType = value + let type = scenarioTypeDataSources[value] ?? 3 + agoraKit.setScreenScenario(type: type) + }) + .transition(.move(edge: .bottom)) + .animation(.spring(), value: isShowPickerView) + } + if isShowFps { + let data = fpsDataSources.map({ "\($0)"}) + PickerView(dataArray: .constant(data), onTapCancel: { + withAnimation { + isShowFps.toggle() + } + }, onTapSure: { value in + withAnimation { + isShowFps.toggle() + } + fps = value + agoraKit.setFps(fps: value) + }) + .transition(.move(edge: .bottom)) + .animation(.spring(), value: isShowFps) + } + + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + ScreenShare(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ScreenShare/ScreenShareRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ScreenShare/ScreenShareRTC.swift new file mode 100644 index 000000000..c9331029e --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/ScreenShare/ScreenShareRTC.swift @@ -0,0 +1,308 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class ScreenShareRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + private lazy var screenParams: AgoraScreenCaptureParameters2 = { + let params = AgoraScreenCaptureParameters2() + params.captureVideo = true + params.captureAudio = true + let audioParams = AgoraScreenAudioParameters() + audioParams.captureSignalVolume = 50 + params.audioParams = audioParams + let videoParams = AgoraScreenVideoParameters() + videoParams.dimensions = screenShareVideoDimension() + videoParams.frameRate = .fps15 + videoParams.bitrate = AgoraVideoBitrateStandard + params.videoParams = videoParams + return params + }() + + private lazy var option: AgoraRtcChannelMediaOptions = { + let option = AgoraRtcChannelMediaOptions() + option.clientRoleType = GlobalSettings.shared.getUserRole() + option.publishCameraTrack = true + option.publishMicrophoneTrack = true + return option + }() + private var systemBroadcastPicker: RPSystemBroadcastPickerView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + self.agoraKit.muteRemoteAudioStream(UInt(SCREEN_SHARE_BROADCASTER_UID), mute: true) + self.agoraKit.muteRemoteVideoStream(UInt(SCREEN_SHARE_BROADCASTER_UID), mute: true) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func prepareSystemBroadcaster() { + let frame = CGRect(x: 0, y: 0, width: 60, height: 60) + systemBroadcastPicker = RPSystemBroadcastPickerView(frame: frame) + systemBroadcastPicker?.showsMicrophoneButton = false + systemBroadcastPicker?.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin] + let bundleId = Bundle.main.bundleIdentifier ?? "" + systemBroadcastPicker?.preferredExtension = "\(bundleId).Agora-ScreenShare-Extension" + } + + private func screenShareVideoDimension() -> CGSize { + let screenSize = UIScreen.main.bounds + var boundingSize = CGSize(width: 540, height: 960) + let mW: CGFloat = boundingSize.width / screenSize.width + let mH: CGFloat = boundingSize.height / screenSize.height + if mH < mW { + boundingSize.width = boundingSize.height / screenSize.height * screenSize.width + } else if mW < mH { + boundingSize.height = boundingSize.width / screenSize.width * screenSize.height + } + return boundingSize + } + + func clickCaptureAudio(_ isOn: Bool) { + screenParams.captureAudio = isOn + } + + func clickCaptureVideo(_ isOn: Bool) { + screenParams.captureVideo = isOn + } + + func captureSignalVolumeSlider(_ value: Float) { + screenParams.audioParams.captureSignalVolume = Int(value * 100) + } + + func isScreenShareUid(uid: UInt) -> Bool { + return uid >= SCREEN_SHARE_UID_MIN && uid <= SCREEN_SHARE_UID_MAX + } + + func stopScreenCapture() { + agoraKit.stopScreenCapture() + option.publishScreenCaptureVideo = false + option.publishScreenCaptureAudio = false + option.publishCameraTrack = true + agoraKit.updateChannel(with: option) + } + + func startScreenCapture() { + guard !UIScreen.main.isCaptured else { return } + agoraKit.startScreenCapture(screenParams) + prepareSystemBroadcaster() + guard let picker = systemBroadcastPicker else { return } + for view in picker.subviews where view is UIButton { + (view as? UIButton)?.sendActions(for: .allEvents) + break + } + } + + func updateScreenCapture() { + agoraKit.updateScreenCapture(screenParams) + } + + func setScreenScenario(type: Int) { + let scenarioType = AgoraScreenScenarioType(rawValue: type) ?? .video + agoraKit.setScreenCaptureScenario(scenarioType) + } + + func setFps(fps: String) { + screenParams.videoParams.frameRate = AgoraVideoFrameRate(rawValue: Int(fps) ?? 15) ?? .fps15 + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension ScreenShareRTC: AgoraRtcEngineDelegate { + func rtcEngine(_ engine: AgoraRtcEngineKit, + localVideoStateChangedOf state: AgoraVideoLocalState, + reason: AgoraLocalVideoStreamReason, + sourceType: AgoraVideoSourceType) { + switch (state, sourceType) { + case (.capturing, .screen): + option.publishScreenCaptureVideo = !UIScreen.main.isCaptured + option.publishScreenCaptureAudio = !UIScreen.main.isCaptured + option.publishCameraTrack = UIScreen.main.isCaptured + agoraKit.updateChannel(with: option) + + // 开始屏幕共享后, 如果想自动隐藏系统界面, 需要配置scheme, 使用scheme唤醒自身的方式关闭系统界面 + // If you want to hide the system interface automatically after you start screen sharing, + // you need to configure scheme and use scheme to wake up the system interface + UIApplication.shared.open(URL(string: "APIExample-SwiftUI://") ?? URL(fileURLWithPath: "APIExample-SwiftUI://")) + + default: break + } + } + + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/SpatialAudio/SpatialAudio.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/SpatialAudio/SpatialAudio.swift new file mode 100644 index 000000000..c638700b5 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/SpatialAudio/SpatialAudio.swift @@ -0,0 +1,264 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct SpatialAudioEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: SpatialAudio(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + SpatialAudioEntry() +} + +struct SpatialAudio: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = SpatialAudioRTC() + @State private var position = CGPoint(x: 0.0, y: 0.0) + @State private var isAttenuation: Bool = false + @State private var isMic: Bool = true + @State private var attenuationFrame: CGRect = .zero + @State private var selfFrame: CGRect = .zero + @State private var isShowVoice1: Bool = false + @State private var isShowVoice2: Bool = false + @State private var isVoice1Mute: Bool = false + @State private var isVoice1VoiceBlur: Bool = false + @State private var isVoice1Airborne: Bool = false + @State private var voice1AttenuationValue: Float = 0.5 + @State private var isVoice2Mute: Bool = false + @State private var isVoice2VoiceBlur: Bool = false + @State private var isVoice2Airborne: Bool = false + @State private var voice2AttenuationValue: Float = 0.5 + + var body: some View { + ZStack { + VStack { + Text("Move the red icon to experience the 3D audio effect".localized).padding(.vertical, 30) + HStack { + ZStack { + GeometryReader { g in + Color.yellow.onAppear(perform: { + attenuationFrame = g.frame(in: .named("OuterV")) + }).opacity(isAttenuation ? 1.0 : 0.0) + } + VStack { + GeometryReader { g in + Button(action: { + withAnimation { + isShowVoice1.toggle() + } + }, label: { + Image(.spatialSound2) + }).padding().onAppear { + agoraKit.setupVoice1Frame(frame: g.frame(in: .named("OuterV"))) + } + } + Spacer() + Text("Room".localized).padding(.bottom, 10).opacity(isAttenuation ? 1.0 : 0.0) + } + } + .frame(width: 76, height: 166) + .padding(.leading, 30) + + Spacer() + ZStack { + VStack { + GeometryReader { g in + Button(action: { + withAnimation { + isShowVoice2.toggle() + } + }, label: { + Image(.spatialSound2) + }).padding().onAppear { + agoraKit.setupVoice2Frame(frame: g.frame(in: .named("OuterV"))) + } + } + } + }.frame(width: 76, height: 166).padding(.trailing, 30) + } + Spacer() + GeometryReader { g in + Image(.spatialSelf) + .position(position) + .gesture( + DragGesture() + .onChanged { value in + let frame = g.frame(in: .named("OuterV")).origin + let point = CGPointMake(value.location.x + frame.x, value.location.y + frame.y) + + position = value.location + selfFrame = CGRect(origin: point, size: CGSize(width: 61, height: 47)) + agoraKit.updatePosition(frame: selfFrame) + } + ).onAppear { + let rect = g.frame(in: .named("OuterV")) + selfFrame = rect + }.zIndex(2.0) + }.frame(width: 61, height: 47) + + Spacer() + HStack { + HStack { + Image(.spatialRemote) + Text("\(agoraKit.remoteUser1)") + } + .opacity(agoraKit.remoteUser1 == 0 ? 0.0 : 1.0) + .background(GeometryReader { g -> Color in + let frame = g.frame(in: .named("OuterV")) + agoraKit.remoteUser1Frame = frame + return Color.clear + }) + Spacer() + HStack { + Image(.spatialRemote) + Text("\(agoraKit.remoteUser2)") + } + .opacity(agoraKit.remoteUser2 == 0 ? 0.0 : 1.0) + .background(GeometryReader { g -> Color in + let frame = g.frame(in: .named("OuterV")) + agoraKit.remoteUser2Frame = frame + return Color.clear + }) + }.padding(EdgeInsets(top: 0, leading: 50, bottom: 30, trailing: 50)) + + HStack { + Spacer() + Text("Sound barrier".localized) + Toggle("", isOn: $isAttenuation).onChange(of: isAttenuation) { value in + agoraKit.onTapAudioAttenuationSwitch(value, + frame: attenuationFrame, + selfFrame: selfFrame) + }.frame(width: 50).zIndex(1) + }.padding(.trailing, 30) + HStack { + Spacer() + Text("Microphone".localized) + Toggle("", isOn: $isMic).onChange(of: isMic) { value in + agoraKit.onTapMicSwitch(value) + }.frame(width: 50).zIndex(1) + }.padding(EdgeInsets(top: 0, leading: 0, bottom: 15, trailing: 30)) + } + if isShowVoice1 { + ActionSheetView(isShow: $isShowVoice1, + isMute: $isVoice1Mute, + isVoiceBlur: $isVoice1VoiceBlur, + isAirborne: $isVoice1Airborne, + attenuationValue: $voice1AttenuationValue, + isVoice1: .constant(true), + agoraKit: agoraKit) + .transition(.move(edge: .bottom)) + .animation(.spring(), value: isShowVoice1) + } + if isShowVoice2 { + ActionSheetView(isShow: $isShowVoice2, + isMute: $isVoice2Mute, + isVoiceBlur: $isVoice2VoiceBlur, + isAirborne: $isVoice2Airborne, + attenuationValue: $voice2AttenuationValue, + isVoice1: .constant(false), + agoraKit: agoraKit) + .transition(.move(edge: .bottom)) + .animation(.spring(), value: isShowVoice2) + } + + }.frame(minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: .infinity) + .onAppear(perform: { + agoraKit.setupRTC(configs: configs, + selfFrame: selfFrame) + }).onDisappear(perform: { + agoraKit.onDestory() + }).coordinateSpace(name: "OuterV") + } +} + +struct ActionSheetView: View { + @Binding var isShow: Bool + @Binding var isMute: Bool + @Binding var isVoiceBlur: Bool + @Binding var isAirborne: Bool + @Binding var attenuationValue: Float + @Binding var isVoice1: Bool + @StateObject var agoraKit: SpatialAudioRTC + @State private var opacity: Double = 0 + var body: some View { + ZStack { + Color.black.opacity(opacity) + .edgesIgnoringSafeArea(.all) + .onTapGesture { + withAnimation { + isShow.toggle() + opacity = isShow ? 0.4 : 0.0 + } + }.onAppear { + withAnimation { + opacity = isShow ? 0.4 : 0.0 + } + } + VStack { + HStack { + Text("Mute".localized) + Toggle("", isOn: $isMute).onChange(of: isMute) { value in + agoraKit.mediaPlayerMute(isVoice1: isVoice1, isMute: value) + } + }.padding(.horizontal, 15) + HStack { + Text("Voice Blur") + Toggle("", isOn: $isVoiceBlur).onChange(of: isVoiceBlur) { value in + agoraKit.mediaPlayerVoiceBlur(isVoice1: isVoice1, isOn: value) + } + }.padding(.horizontal, 15) + HStack { + Text("Airborne Simulation") + Toggle("", isOn: $isAirborne).onChange(of: isAirborne) { value in + agoraKit.mediaPlayerAirborne(isVoice1: isVoice1, isOn: value) + } + }.padding(.horizontal, 15) + HStack { + Text("Attenuation") + Slider(value: $attenuationValue) + .padding(.leading, 20) + .onChange(of: attenuationValue) { value in + agoraKit.mediaPlayerAttenuation(isVoice1: isVoice1, value: value) + } + }.padding(.horizontal, 15) + }.frame(height: 200) + .background(Color.white) + .offset(x: 0, y: isShow ? 200 : 0) + } + } +} + +#Preview { + SpatialAudio(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/SpatialAudio/SpatialAudioRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/SpatialAudio/SpatialAudioRTC.swift new file mode 100644 index 000000000..f24150bfc --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/SpatialAudio/SpatialAudioRTC.swift @@ -0,0 +1,260 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +let SCREENSIZE = UIScreen.main.bounds.size +class SpatialAudioRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var mediaPlayer1: AgoraRtcMediaPlayerProtocol! + private var mediaPlayer2: AgoraRtcMediaPlayerProtocol! + private var localSpatial: AgoraLocalSpatialAudioKit! + private var currentAngle = 0.0 + private var currentDistance = 0.0 + private var maxDistance: CGFloat = 10 + private let forward = simd_float3(1.0, 0.0, 0.0) + private let right = simd_float3(0.0, 1.0, 0.0) + private let up = simd_float3(0.0, 0.0, 1.0) + + var remoteUser1Frame: CGRect = .zero + var remoteUser2Frame: CGRect = .zero + @Published var remoteUser1: UInt = 0 + @Published var remoteUser2: UInt = 0 + + func setupRTC(configs: [String: Any], selfFrame: CGRect) { + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable audio module + agoraKit.enableAudio() + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + let localSpatialConfig = AgoraLocalSpatialAudioConfig() + localSpatialConfig.rtcEngine = agoraKit + localSpatial = AgoraLocalSpatialAudioKit.sharedLocalSpatialAudio(with: localSpatialConfig) + localSpatial.setAudioRecvRange(Float(SCREENSIZE.height)) + localSpatial.setMaxAudioRecvCount(2) + localSpatial.setDistanceUnit(1) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + option.autoSubscribeAudio = true + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + + updatePosition(frame: selfFrame) + } + + func setupVoice1Frame(frame: CGRect) { + mediaPlayer1 = agoraKit.createMediaPlayer(with: self) + mediaPlayer1.setLoopCount(-1) + mediaPlayer1.open("https://webdemo.agora.io/audiomixing.mp3", startPos: 0) + localSpatial.updatePlayerPositionInfo(Int(mediaPlayer1.getMediaPlayerId()), positionInfo: getPlayerPostion(view: frame)) + localSpatial.setPlayerAttenuation(0.2, playerId: UInt(mediaPlayer1.getMediaPlayerId()), forceSet: false) + } + + func setupVoice2Frame(frame: CGRect) { + mediaPlayer2 = agoraKit.createMediaPlayer(with: self) + mediaPlayer2.setLoopCount(-1) + mediaPlayer2.open("https://webdemo.agora.io/dang.mp3", startPos: 0) + localSpatial.updatePlayerPositionInfo(Int(mediaPlayer2.getMediaPlayerId()), positionInfo: getPlayerPostion(view: frame)) + localSpatial.setPlayerAttenuation(0.2, playerId: UInt(mediaPlayer2.getMediaPlayerId()), forceSet: false) + } + + func onTapMicSwitch(_ isOn: Bool) { + let option = AgoraRtcChannelMediaOptions() + option.publishMicrophoneTrack = isOn + agoraKit.updateChannel(with: option) + } + func onTapAudioAttenuationSwitch(_ isOn: Bool, frame: CGRect, selfFrame: CGRect) { + if isOn { + let audioZone = AgoraSpatialAudioZone() + audioZone.forwardLength = Float(frame.width) + audioZone.rightLength = Float(frame.height) + audioZone.upLength = Float(maxDistance) + audioZone.zoneSetId = 1 + audioZone.audioAttenuation = 1 + audioZone.forward = forward + audioZone.right = right + audioZone.up = up + audioZone.position = getViewCenterPostion(view: frame) + localSpatial.setZones([audioZone]) + } else { + localSpatial.setZones(nil) + } + let pos = getViewCenterPostion(view: selfFrame) + localSpatial.updateSelfPosition(pos, axisForward: forward, axisRight: right, axisUp: up) + } + + func mediaPlayerMute(isVoice1: Bool, isMute: Bool) { + if isVoice1 { + _ = isMute ? mediaPlayer1.pause() : mediaPlayer1.resume() + } else { + _ = isMute ? mediaPlayer1.pause() : mediaPlayer1.resume() + } + } + func mediaPlayerVoiceBlur(isVoice1: Bool, isOn: Bool) { + let params = AgoraSpatialAudioParams() + params.enable_blur = isOn + if isVoice1 { + mediaPlayer1.setSpatialAudioParams(params) + } else { + mediaPlayer1.setSpatialAudioParams(params) + } + } + func mediaPlayerAirborne(isVoice1: Bool, isOn: Bool) { + let params = AgoraSpatialAudioParams() + params.enable_air_absorb = isOn + if isVoice1 { + mediaPlayer1.setSpatialAudioParams(params) + } else { + mediaPlayer1.setSpatialAudioParams(params) + } + } + func mediaPlayerAttenuation(isVoice1: Bool, value: Float) { + let mediaPlayerId = isVoice1 ? UInt(mediaPlayer1.getMediaPlayerId()) : UInt(mediaPlayer2.getMediaPlayerId()) + localSpatial.setPlayerAttenuation(Double(value), + playerId: mediaPlayerId, + forceSet: false) + } + + func updatePosition(frame: CGRect) { + let pos = getViewCenterPostion(view: frame) + localSpatial.updateSelfPosition(pos, + axisForward: forward, + axisRight: right, + axisUp: up) + } + + private func getPlayerPostion(view: CGRect) -> AgoraRemoteVoicePositionInfo { + let position = getViewCenterPostion(view: view) + let positionInfo = AgoraRemoteVoicePositionInfo() + positionInfo.position = position + positionInfo.forward = forward + return positionInfo + } + private func getViewCenterPostion(view: CGRect) -> simd_float3 { + simd_float3(Float(view.minX + view.width * 0.5), + Float(view.minY + view.height * 0.5), + 0.0) + } + + func onDestory() { + agoraKit.disableAudio() + if isJoined { + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraLocalSpatialAudioKit.destroy() + AgoraRtcEngineKit.destroy() + } +} + +extension SpatialAudioRTC: AgoraRtcMediaPlayerDelegate { + func AgoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, + didChangedTo state: AgoraMediaPlayerState, + reason: AgoraMediaPlayerReason) { + if state == .openCompleted || state == .playBackAllLoopsCompleted || state == .playBackCompleted { + playerKit.play() + } + } +} + + +// agora rtc engine delegate events +extension SpatialAudioRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + if remoteUser1 == 0 { + localSpatial.updateRemotePosition(uid, positionInfo: getPlayerPostion(view: remoteUser1Frame)) + remoteUser1 = uid + } else if remoteUser2 == 0 { + localSpatial.updateRemotePosition(uid, positionInfo: getPlayerPostion(view: remoteUser2Frame)) + remoteUser2 = uid + } + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + if remoteUser1 == uid { + remoteUser1 = 0 + } else if remoteUser2 == uid { + remoteUser2 = 0 + } + localSpatial.removeRemotePosition(uid) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/StreamEncryption/StreamEncryption.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/StreamEncryption/StreamEncryption.swift new file mode 100644 index 000000000..656ca8274 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/StreamEncryption/StreamEncryption.swift @@ -0,0 +1,97 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct StreamEncryptionEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + @State private var encryptSecretField: String = "" + @State private var isShowActionSheet: Bool = false + @State private var mode: AgoraEncryptionMode = .AES128GCM2 + @State private var useCustom: Bool = false + + var body: some View { + VStack { + Spacer() + HStack { + Text("Encryption Mode".localized) + Spacer() + Button(useCustom ? "Custom" : mode.description()) { + isShowActionSheet.toggle() + }.confirmationDialog("Set Encryption Mode".localized, isPresented: $isShowActionSheet, titleVisibility: .visible) { + ForEach(AgoraEncryptionMode.allValues(), id: \.self) { item in + Button(item.description()) { + mode = item + useCustom = false + } + } + Button("Custom") { + useCustom = true + } + Button("Cancel".localized, role: .cancel) {} + } + Spacer() + }.padding(.leading, 15) + TextField("Enter encryption secret".localized, text: $encryptSecretField).textFieldStyle(.roundedBorder) + .padding(.horizontal, 15) + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName, + "mode": mode, + "secret": encryptSecretField, + "useCustom": useCustom] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: StreamEncryption(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + StreamEncryptionEntry() +} + +struct StreamEncryption: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = StreamEncryptionRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + StreamEncryption(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/StreamEncryption/StreamEncryptionRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/StreamEncryption/StreamEncryptionRTC.swift new file mode 100644 index 000000000..3acbbc190 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/StreamEncryption/StreamEncryptionRTC.swift @@ -0,0 +1,236 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class StreamEncryptionRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var useCustom: Bool = false + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + // get channel name from configs + guard let channelName = configs["channelName"] as? String, + let secret = configs["secret"] as? String, + let mode = configs["mode"] as? AgoraEncryptionMode, + let useCustom = configs["useCustom"] as? Bool else {return} + + self.useCustom = useCustom + + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // enable encryption + if !useCustom { + // sdk encryption + let config = AgoraEncryptionConfig() + config.encryptionMode = mode + config.encryptionKey = secret + config.encryptionKdfSalt = getEncryptionSaltFromServer() + let ret = agoraKit.enableEncryption(true, encryptionConfig: config) + if ret != 0 { + // for errors please take a look at: + // swiftlint:disable line_length + // CN https://docs.agora.io/cn/live-streaming-premium-legacy/API%20Reference/oc/Classes/AgoraRtcChannel.html?platform=iOS#//api/name/enableEncryption:encryptionConfig: + // swiftlint:enable line_length + // EN https://docs.agora.io/en/video-calling/develop/media-stream-encryption#implement--media-stream-encryption + LogUtils.log(message: "enableEncryption call failed: \(ret), please check your params", level: .error) + } + } else { + // your own custom algorithm encryption + AgoraCustomEncryption.registerPacketProcessing(agoraKit) + } + + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func getEncryptionSaltFromServer() -> Data { + // Salt string should be the output of the following command: + // openssl rand -base64 32 + let saltBase64String = "NiIeJ08AbtcQVjvV+oOEvF/4Dz5dy1CIwa805C8J2w0=" + let data = Data(base64Encoded: saltBase64String.data(using: .utf8) ?? Data()) + return data ?? Data() + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + agoraKit.enableEncryption(false, encryptionConfig: AgoraEncryptionConfig()) + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + + if useCustom { + // deregister packet processing + AgoraCustomEncryption.deregisterPacketProcessing(agoraKit) + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension StreamEncryptionRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoMetadata/VideoMetaDataRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoMetadata/VideoMetaDataRTC.swift new file mode 100644 index 000000000..5a42b3b7c --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoMetadata/VideoMetaDataRTC.swift @@ -0,0 +1,239 @@ +// +// VideoMetaDataRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import Foundation +import AgoraRtcKit + +class VideoMetaDataRTC: NSObject, ObservableObject { + @Published var receivedMsg = "" + @Published var showAlert = false + + var agoraKit: AgoraRtcEngineKit! + private var localView: VideoUIView! + private var remoteView: VideoUIView! + private var isJoined: Bool = false + // video metadata to be sent later + var metadata: Data? + // metadata lenght limitation + let MAX_META_LENGTH = 1024 + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // register metadata delegate and datasource + agoraKit.setMediaMetadataDataSource(self, with: .video) + agoraKit.setMediaMetadataDelegate(self, with: .video) + + guard let channelName = configs["channelName"] as? String else {return} + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + let resolution = (GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize) ?? .zero + let fps = (GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate) ?? .fps15 + let orientation = (GlobalSettings.shared.getSetting(key: "orientation")? + .selectedOption().value as? AgoraVideoOutputOrientationMode) ?? .fixedPortrait + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, + mirrorMode: .auto)) + + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = localView.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { [weak self] token in + guard let self = self else { return } + + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + } + }) + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +/// agora rtc engine delegate events +extension VideoMetaDataRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + + // 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.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + localView.statsInfo?.updateChannelStats(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) { + localView.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView.statsInfo?.updateVideoStats(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) { + remoteView.statsInfo?.updateAudioStats(stats) + } +} + +extension VideoMetaDataRTC: AgoraMediaMetadataDelegate, AgoraMediaMetadataDataSource { + func metadataMaxSize() -> Int { + // the data to send should not exceed this size + return MAX_META_LENGTH + } + + /// Callback when the SDK is ready to send metadata. + /// You need to specify the metadata in the return value of this method. + /// Ensure that the size of the metadata that you specify in this callback does not exceed the value set in the metadataMaxSize callback. + /// @param timestamp The timestamp (ms) of the current metadata. + /// @return The metadata that you want to send in the format of Data + func readyToSendMetadata(atTimestamp timestamp: TimeInterval, sourceType: AgoraVideoSourceType) -> Data? { + guard let metadata = self.metadata else { return nil } + + // clear self.metadata to nil after any success send to avoid redundancy + self.metadata = nil + + if metadata.count > MAX_META_LENGTH { + // if data exceeding limit, return nil to not send anything + LogUtils.log(message: "invalid metadata: length exceeds \(MAX_META_LENGTH)", level: .info) + return nil + } + LogUtils.log(message: "metadata sent", level: .info) + self.metadata = nil + return metadata + } + + /// Callback when the local user receives the metadata. + /// @param data The received metadata. + /// @param uid The ID of the user who sends the metadata. + /// @param timestamp The timestamp (ms) of the received metadata. + func receiveMetadata(_ data: Data, fromUser uid: Int, atTimestamp timestamp: TimeInterval) { + DispatchQueue.main.async { + LogUtils.log(message: "metadata received", level: .info) + self.receivedMsg = String(data: data, encoding: .utf8) ?? "" + self.showAlert = true +// let alert = UIAlertController(title: "Metadata received", message: String(data: data, encoding: .utf8), preferredStyle: .alert) +// alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) +// self.present(alert, animated: true, completion: nil) + } + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoMetadata/VideoMetadata.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoMetadata/VideoMetadata.swift new file mode 100644 index 000000000..854b39943 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoMetadata/VideoMetadata.swift @@ -0,0 +1,75 @@ +// +// VideoMetadata.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/27. +// + +import SwiftUI + +struct VideoMetadataEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: VideoMetadata(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct VideoMetadata: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var agoraKit = VideoMetaDataRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + + Button("Send Message".localized) { + agoraKit.metadata = "\(Date())".data(using: .utf8) + } + .padding(.bottom, 150) + } + .alert(isPresented: $agoraKit.showAlert) { + Alert( + title: Text("Metadata received"), + message: Text(agoraKit.receivedMsg) + + ) + } + .onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + VideoMetadata() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoProcess/VideoProcess.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoProcess/VideoProcess.swift new file mode 100644 index 000000000..5c08ea6e9 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoProcess/VideoProcess.swift @@ -0,0 +1,215 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct VideoProcessEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: VideoProcess(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + VideoProcessEntry() +} + +struct VideoProcess: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = VideoProcessRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + @State private var beautySwitch: Bool = false + @State private var colorEnhanceSwitch: Bool = false + @State private var virtualBgSwitch: Bool = false + @State private var lightenSlider: Float = 0.5 + @State private var rednessSlider: Float = 0.5 + @State private var sharpnessSlider: Float = 0.5 + @State private var smoothnessSlider: Float = 0.5 + @State private var lowLightEnhanceSwitch: Bool = false + @State private var videoDenoiseSwitch: Bool = false + @State private var strengthSlider: Float = 0.5 + @State private var skinProtectSlider: Float = 0.5 + @State private var selectedSegment = 0 + private let segments = ["Image".localized, + "Color".localized, + "Blur".localized, + "Video".localized] + + var body: some View { + ScrollView { + VStack { + HStack{ + localView + remoteView + }.frame(height: 200) + HStack { + Text("Face Beauty".localized) + Spacer() + Toggle("", isOn: $beautySwitch) + .frame(width: 50) + .onChange(of: beautySwitch) { value in + agoraKit.onChangeBeauty(value) + } + Spacer() + } + .padding(.leading, 20) + HStack { + VStack { + Text("Lightening".localized) + .frame(maxWidth: .infinity, + alignment: .leading) + Slider(value: $lightenSlider).onChange(of: lightenSlider) { value in + agoraKit.onLightenSlider(value, + isOn: beautySwitch) + } + } + VStack { + Text("Redness".localized) + .frame(maxWidth: .infinity, + alignment: .leading) + Slider(value: $rednessSlider).onChange(of: rednessSlider) { value in + agoraKit.onRednessSlider(value, + isOn: beautySwitch) + } + } + }.padding(.horizontal, 20) + HStack { + VStack { + Text("Sharpness".localized) + .frame(maxWidth: .infinity, + alignment: .leading) + Slider(value: $sharpnessSlider).onChange(of: sharpnessSlider) { value in + agoraKit.onSharpnessSlider(value, isOn: beautySwitch) + } + } + VStack { + Text("Smoothness".localized) + .frame(maxWidth: .infinity, + alignment: .leading) + Slider(value: $smoothnessSlider).onChange(of: smoothnessSlider) { value in + agoraKit.onSmoothSlider(value, isOn: beautySwitch) + } + } + }.padding(.horizontal, 20) + HStack { + Text("Low light Enhancement".localized) + Spacer() + Toggle("", isOn: $lowLightEnhanceSwitch) + .frame(width: 50) + .onChange(of: lowLightEnhanceSwitch) { value in + agoraKit.onChangeLowLightEnhance(value) + } + Spacer() + } + .padding(.horizontal, 20) + .padding(.top, 20) + HStack { + Text("Video Dencise".localized) + Spacer() + Toggle("", isOn: $videoDenoiseSwitch) + .frame(width: 50) + .onChange(of: videoDenoiseSwitch) { value in + agoraKit.onChangeVideoDenoise(value) + } + Spacer() + }.padding(.horizontal, 20) + HStack { + Text("Color Enhancement".localized) + Spacer() + Toggle("", isOn: $colorEnhanceSwitch) + .frame(width: 50) + .onChange(of: colorEnhanceSwitch) { value in + agoraKit.onChangeColorEnhance(value) + } + Spacer() + } + .padding(.horizontal, 20) + .padding(.top, 20) + HStack { + VStack { + Text("Strength".localized) + .frame(maxWidth: .infinity, + alignment: .leading) + Slider(value: $strengthSlider).onChange(of: strengthSlider) { value in + agoraKit.onStrengthSlider(value, + isOn: colorEnhanceSwitch) + } + } + VStack { + Text("Skin Protect".localized) + .frame(maxWidth: .infinity, + alignment: .leading) + Slider(value: $skinProtectSlider).onChange(of: skinProtectSlider) { value in + agoraKit.onSkinProtectSlider(value, + isOn: colorEnhanceSwitch) + } + } + } + .padding(.horizontal, 20) + .padding(.bottom, 20) + HStack { + Text("Virtual Background".localized) + Spacer() + Toggle("", isOn: $virtualBgSwitch) + .frame(width: 50) + .onChange(of: virtualBgSwitch) { value in + agoraKit.onChangeVirtualBgSwtich(value, + index: selectedSegment) + } + Spacer() + }.padding(.horizontal, 20) + Picker(selection: $selectedSegment, label: Text("")) { + ForEach(Array(segments.indices), id: \.self) { index in + Text(segments[index]) + } + } + .pickerStyle(SegmentedPickerStyle()) + .onChange(of: selectedSegment, perform: { value in + agoraKit.onChangeVirtualBackground(index: value, + isOn: virtualBgSwitch) + }) + .disabled(!virtualBgSwitch) + .padding(.horizontal, 20) + .padding(.bottom, 20) + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } + } +} + +#Preview { + VideoProcess(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoProcess/VideoProcessRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoProcess/VideoProcessRTC.swift new file mode 100644 index 000000000..b0004dade --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VideoProcess/VideoProcessRTC.swift @@ -0,0 +1,311 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class VideoProcessRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + private var beautifyOption = AgoraBeautyOptions() + private var skinProtect = 0.5 + private var strength = 0.5 + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // enable filters + agoraKit.enableExtension(withVendor: "agora_video_filters_clear_vision", + extension: "clear_vision", + enabled: true, + sourceType: .primaryCamera) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onChangeBeauty(_ isOn: Bool) { + if isOn { + if agoraKit.isFeatureAvailable(onDevice: .videoPreprocessBeauty) { + agoraKit.setBeautyEffectOptions(true, options: beautifyOption) + } else { + ToastView.show(text: "The feature is unavailable in the device!") + } + } else { + agoraKit.setBeautyEffectOptions(false, options: beautifyOption) + } + } + + func onLightenSlider(_ value: Float, isOn: Bool) { + beautifyOption.lighteningLevel = value + agoraKit.setBeautyEffectOptions(isOn, options: beautifyOption) + } + + func onRednessSlider(_ value: Float, isOn: Bool) { + beautifyOption.rednessLevel = value + agoraKit.setBeautyEffectOptions(isOn, options: beautifyOption) + } + + func onSharpnessSlider(_ value: Float, isOn: Bool) { + beautifyOption.sharpnessLevel = value + agoraKit.setBeautyEffectOptions(isOn, options: beautifyOption) + } + + func onSmoothSlider(_ value: Float, isOn: Bool) { + beautifyOption.smoothnessLevel = value + agoraKit.setBeautyEffectOptions(isOn, options: beautifyOption) + } + + func onChangeLowLightEnhance(_ isOn: Bool) { + let options = AgoraLowlightEnhanceOptions() + options.level = .fast + options.mode = .auto + agoraKit.setLowlightEnhanceOptions(isOn, options: options) + } + + func onChangeVideoDenoise(_ isOn: Bool) { + let options = AgoraVideoDenoiserOptions() + options.level = .highQuality + options.mode = .manual + agoraKit.setVideoDenoiserOptions(isOn, options: options) + } + + func onChangeColorEnhance(_ isOn: Bool) { + let options = AgoraColorEnhanceOptions() + options.strengthLevel = Float(strength) + options.skinProtectLevel = Float(skinProtect) + agoraKit.setColorEnhanceOptions(isOn, options: options) + } + + func onStrengthSlider(_ value: Float, isOn: Bool) { + strength = Double(value) + let options = AgoraColorEnhanceOptions() + options.strengthLevel = Float(strength) + options.skinProtectLevel = Float(skinProtect) + agoraKit.setColorEnhanceOptions(isOn, options: options) + } + + func onSkinProtectSlider(_ value: Float, isOn: Bool) { + skinProtect = Double(value) + let options = AgoraColorEnhanceOptions() + options.strengthLevel = Float(strength) + options.skinProtectLevel = Float(skinProtect) + agoraKit.setColorEnhanceOptions(isOn, options: options) + } + + func onChangeVirtualBgSwtich(_ isOn: Bool, index: Int) { + if isOn { + if agoraKit.isFeatureAvailable(onDevice: .videoPreprocessVirtualBackground) { + onChangeVirtualBackground(index: index, isOn: isOn) + } else { + ToastView.show(text: "The feature is unavailable in the device!") + } + } else { + onChangeVirtualBackground(index: index, isOn: isOn) + } + } + + func onChangeVirtualBackground(index: Int, isOn: Bool) { + let source = AgoraVirtualBackgroundSource() + switch index { + case 0: + let imgPath = Bundle.main.path(forResource: "agora-logo", ofType: "png") + source.backgroundSourceType = .img + source.source = imgPath + + case 1: + source.backgroundSourceType = .color + source.color = 0xFFFFFF + + case 2: + source.backgroundSourceType = .blur + source.blurDegree = .high + + case 3: + let videoPath = Bundle.main.path(forResource: "sample", ofType: "mov") + source.backgroundSourceType = .video + source.source = videoPath + + default: break + } + source.backgroundSourceType = isOn ? source.backgroundSourceType : .none + let result = agoraKit.enableVirtualBackground(isOn, backData: source, segData: AgoraSegmentationProperty()) + print("result == \(result)") + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + agoraKit.enableVirtualBackground(false, backData: nil, segData: nil) + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension VideoProcessRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VoiceChanger/VoiceChanger.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VoiceChanger/VoiceChanger.swift new file mode 100644 index 000000000..7e2546a01 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VoiceChanger/VoiceChanger.swift @@ -0,0 +1,526 @@ +// +// VoiceChanger.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/29. +// + +import SwiftUI + +struct VoiceChangerEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: VoiceChanger(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +struct VoiceChanger: View { + @State var configs: [String: Any] = [:] + @ObservedObject private var voiceChangerRTC = VoiceChangerRTC() + @State var selectedChatBeautifier: AgoraVoiceBeautifierPreset = .presetOff + @State var selectedTimbreTransformation: AgoraVoiceBeautifierPreset = .presetOff + @State var selectedVoiceChanger: AgoraAudioEffectPreset = .off + @State var selectedStyleTransformation: AgoraAudioEffectPreset = .off + @State var selectedRoomAcoustics: AgoraAudioEffectPreset = .off + @State var selectedPitchCorrection: AgoraAudioEffectPreset = .off + @State var selectedVoiceConversion: AgoraVoiceConversionPreset = .off + @State var selectedAinsModel: AUDIO_AINS_MODE = .AINS_MODE_BALANCED + @State var currentAudioEffects: AgoraAudioEffectPreset = .off + @State var selectedVoiceEqualizationFreq: AgoraAudioEqualizationBandFrequency = .band31 + @State var selectedReverbKay: AgoraAudioReverbType = .dryLevel + + @State var tonicModeValue: Float = 1 + @State var tonicPitchValue: Float = 1 + @State var voiceFormantValue: Float = 0 + @State var bandGainValue: Float = 0 + @State var pitchValue: Float = 1 + @State var reverbValue: Float = 0.5 + + @State var shouldPreset = true + @State private var tonicModeEnable = false + @State private var tonicPitchEnable = false + + @State private var tonicModeValueSliderRange: ClosedRange = 1.0...3.0 + @State private var tonicPitchValueSliderRange: ClosedRange = 1.0...12.0 + @State private var voiceFormantValueSliderRange: ClosedRange = -1.0...1.0 + @State private var pitchValueSliderRange: ClosedRange = 0.5...2.0 + @State private var bandGainSliderRange: ClosedRange = -15.0...15.0 + @State private var reverbValueSliderRange: ClosedRange = 0.0...1.0 + + @State var ainsModelCases: [AUDIO_AINS_MODE] = [ + .AINS_MODE_BALANCED, + .AINS_MODE_AGGRESSIVE, + .AINS_MODE_ULTRALOWLATENCY + ] + + @State var chatBeautifierCases: [AgoraVoiceBeautifierPreset] = [ + .presetOff, + .presetChatBeautifierFresh, + .presetChatBeautifierVitality, + .presetChatBeautifierMagnetic + ] + + @State var timbreTransformationCases: [AgoraVoiceBeautifierPreset] = [ + .presetOff, + .timbreTransformationVigorous, + .timbreTransformationDeep, + .timbreTransformationMellow, + .timbreTransformationFalsetto, + .timbreTransformationFull, + .timbreTransformationClear, + .timbreTransformationResounding, + .timbreTransformatRinging + ] + + @State var voiceChangerCases: [AgoraAudioEffectPreset] = [ + .off, + .voiceChangerEffectUncle, + .voiceChangerEffectOldMan, + .voiceChangerEffectBoy, + .voiceChangerEffectSister, + .voiceChangerEffectGirl, + .voiceChangerEffectPigKin, + .voiceChangerEffectHulk + ] + + @State var voiceConversion: [AgoraVoiceConversionPreset] = [ + .off, + .neutral, + .sweet, + .changerSolid, + .changerBass + ] + + @State var styleTransformationCases: [AgoraAudioEffectPreset] = [ + .off, + .styleTransformationPopular, + .styleTransformationRnb + ] + + @State var roomAcousticsCases: [AgoraAudioEffectPreset] = [ + .off, + .roomAcousticsKTV, + .roomAcousVocalConcer, + .roomAcousStudio, + .roomAcousPhonograph, + .roomAcousVirtualStereo, + .roomAcousSpatial, + .roomAcousEthereal, + .roomAcous3DVoice + ] + + @State var pitchCorrectionCases: [AgoraAudioEffectPreset] = [ + .off, + .pitchCorrection + ] + + @State var voiceConversionCases: [AgoraVoiceConversionPreset] = [ + .off, + .neutral, + .sweet, + .changerSolid, + .changerBass + ] + + @State var voiceEqualizationFreqCases: [AgoraAudioEqualizationBandFrequency] = [ + .band31, + .band62, + .band125, + .band250, + .band500, + .band1K, + .band2K, + .band4K, + .band8K, + .band16K + ] + + @State var reverbKeyCases: [AgoraAudioReverbType] = [ + .dryLevel, + .wetLevel, + .roomSize, + .wetDelay, + .strength + ] + + var reverbMap: [AgoraAudioReverbType: Int] = [ + .dryLevel: 0, + .wetLevel: 0, + .roomSize: 0, + .wetDelay: 0, + .strength: 0 + ] + + var localView = VideoView(type: .local, + audioOnly: true) + var remoteView = VideoView(type: .remote, + audioOnly: true) + + var body: some View { + VStack { + HStack { + localView + remoteView + } + .frame(maxHeight: 200) + .padding(.bottom, 50) + + ScrollView { + VStack(alignment: .leading) { + HStack { + Text("AINSModel".localized) + Picker("", selection: $selectedAinsModel) { + ForEach(ainsModelCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedAinsModel) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setAINSMode(true, mode: newValue) + resetAllSelectors(except: "AINSModel") + updateAudioEffectsControls(.off) + } + } + } + Text("Voice Beautifier & Effects Preset") + .font(.system(size: 15, weight: .bold)) + .frame(maxWidth: .infinity, alignment: .leading) + HStack { + Text("Set Chat Beautifier".localized) + Picker("", selection: $selectedChatBeautifier) { + ForEach(chatBeautifierCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedChatBeautifier) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setVoiceBeautifierPreset(newValue) + resetAllSelectors(except: "ChatBeautifier") + updateAudioEffectsControls(.off) + } + } + } + + HStack { + Text("Set Timbre Transformation".localized) + Picker("", selection: $selectedTimbreTransformation) { + ForEach(timbreTransformationCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedTimbreTransformation) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setVoiceBeautifierPreset(newValue) + resetAllSelectors(except: "TimbreTransformation") + updateAudioEffectsControls(.off) + } + } + } + + HStack { + Text("Set Voice Changer".localized) + Picker("", selection: $selectedVoiceChanger) { + ForEach(voiceChangerCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedVoiceChanger) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setAudioEffectPreset(newValue) + resetAllSelectors(except: "VoiceChanger") + updateAudioEffectsControls(newValue) + } + } + } + + HStack { + Text("Set Style Transformation".localized) + Picker("", selection: $selectedStyleTransformation) { + ForEach(styleTransformationCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedStyleTransformation) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setAudioEffectPreset(newValue) + resetAllSelectors(except: "StyleTransformation") + updateAudioEffectsControls(newValue) + } + } + } + + HStack { + Text("Set Room Acoustics".localized) + Picker("", selection: $selectedRoomAcoustics) { + ForEach(roomAcousticsCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedRoomAcoustics) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setAudioEffectPreset(newValue) + resetAllSelectors(except: "RoomAcoustics") + updateAudioEffectsControls(newValue) + } + } + } + + HStack { + Text("Pitch Correction".localized) + Picker("", selection: $selectedPitchCorrection) { + ForEach(pitchCorrectionCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedPitchCorrection) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setAudioEffectPreset(newValue) + resetAllSelectors(except: "PitchCorrection") + updateAudioEffectsControls(newValue) + } + } + } + + HStack { + Text(selectedPitchCorrection == .off ? "N/A" : "Tonic Mode".localized) + .foregroundStyle(tonicModeEnable ? .black : .gray) + Slider(value: $tonicModeValue, in: tonicModeValueSliderRange) { isEditing in + if !isEditing { + voiceChangerRTC.agoraKit.setAudioEffectParameters(currentAudioEffects, param1: Int32(tonicModeValue), param2: Int32(tonicPitchValue)) + } + } + .tint(tonicModeEnable ? .blue : .gray) + .disabled(!tonicModeEnable) + + Text(selectedPitchCorrection == .off ? "N/A" : "Tonic Pitch".localized) + .foregroundStyle(tonicModeEnable ? .black : .gray) + Slider(value: $tonicPitchValue, in: tonicPitchValueSliderRange) { isEditing in + if !isEditing { + voiceChangerRTC.agoraKit.setAudioEffectParameters(currentAudioEffects, param1: Int32(tonicModeValue), param2: Int32(tonicPitchValue)) + } + } + .tint(tonicModeEnable ? .blue : .gray) + .disabled(!tonicPitchEnable) + } + + HStack { + Text("Voice Conversion".localized) + Picker("", selection: $selectedVoiceConversion) { + ForEach(voiceConversionCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedVoiceConversion) { newValue in + if shouldPreset { + voiceChangerRTC.agoraKit.setVoiceConversionPreset(newValue) + resetAllSelectors(except: "VoiceConversion") + updateAudioEffectsControls(.off) + } + } + } + + VStack { + Text("Voice Formant".localized) + Slider(value: $voiceFormantValue, in: voiceFormantValueSliderRange) { isEditing in + if !isEditing { + voiceChangerRTC.agoraKit.setLocalVoiceFormant(Double(voiceFormantValue)) + } + } + } + + Text("Customize Voice Effects".localized) + .font(.system(size: 15, weight: .bold)) + .frame(maxWidth: .infinity, alignment: .leading) + HStack { + Text("Pitch".localized) + Slider(value: $pitchValue, in: pitchValueSliderRange) { isEditing in + if !isEditing { + voiceChangerRTC.agoraKit.setLocalVoicePitch(Double(pitchValue)) + } + } + } + + HStack { + Text("BandFreq".localized) + Picker("", selection: $selectedVoiceEqualizationFreq) { + ForEach(voiceEqualizationFreqCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedVoiceEqualizationFreq) { newValue in + voiceChangerRTC.agoraKit.setLocalVoiceEqualizationOf(selectedVoiceEqualizationFreq, withGain: Int(bandGainValue)) + } + } + + HStack { + Text("BandGain".localized) + Slider(value: $bandGainValue, in: bandGainSliderRange) { isEditing in + if !isEditing { + voiceChangerRTC.agoraKit.setLocalVoiceEqualizationOf(selectedVoiceEqualizationFreq, withGain: Int(bandGainValue)) + } + } + } + + HStack { + Text("ReverbKey".localized) + Picker("", selection: $selectedReverbKay) { + ForEach(reverbKeyCases) { e in + Text(e.description()).tag(e) + } + } + .onChange(of: selectedReverbKay) { newValue in + updateReverbValueRange(reverbKey: newValue) + } + } + + HStack { + Text("ReverbValue".localized) + Slider(value: $reverbValue, in: reverbValueSliderRange) { isEditing in + if !isEditing { + voiceChangerRTC.agoraKit.setLocalVoiceReverbOf(selectedReverbKay, withValue: Int(reverbValue)) + } + } + } + + } + .padding(.all, 20) + .frame(maxWidth: .infinity, alignment: .leading) + } + } + .onAppear(perform: { + voiceChangerRTC.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + voiceChangerRTC.onDestory() + }) + } +} + +extension VoiceChanger { + private func resetAllSelectors(except selected: String) { + shouldPreset = false + if selected != "ChatBeautifier" { + selectedChatBeautifier = .presetOff + } + if selected != "TimbreTransformation" { + selectedTimbreTransformation = .presetOff + } + if selected != "VoiceChanger" { + selectedVoiceChanger = .off + } + if selected != "StyleTransformation" { + selectedStyleTransformation = .off + } + if selected != "RoomAcoustics" { + selectedRoomAcoustics = .off + } + if selected != "PitchCorrection" { + selectedPitchCorrection = .off + } + if selected != "VoiceConversion" { + selectedVoiceConversion = .off + } + if selected != "AINSModel" { + selectedAinsModel = .AINS_MODE_BALANCED + } + DispatchQueue.main.async { + shouldPreset = true + } + } + + func updateAudioEffectsControls(_ effect: AgoraAudioEffectPreset) { + currentAudioEffects = effect + if effect == .roomAcous3DVoice { + tonicModeEnable = true + tonicPitchEnable = false + tonicModeValueSliderRange = 0...60 + tonicModeValue = 10 + } else if effect == .pitchCorrection { + tonicModeEnable = true + tonicPitchEnable = true + tonicModeValueSliderRange = 1...3 + tonicModeValue = 1 + + tonicPitchValueSliderRange = 1...12 + tonicPitchValue = 4 + } else { + tonicModeEnable = false + tonicPitchEnable = false + } + } + + private func updateReverbValueRange(reverbKey: AgoraAudioReverbType) { + var min: Float = 0, max: Float = 0 + switch reverbKey { + case .dryLevel: + min = -20 + max = 10 + + case .wetLevel: + min = -20 + max = 10 + + case .roomSize: + min = 0 + max = 100 + + case .wetDelay: + min = 0 + max = 200 + + case .strength: + min = 0 + max = 100 + + default: break + } + reverbValueSliderRange = min...max + reverbValue = Float(reverbMap[reverbKey] ?? 0) + } +} + +extension AgoraVoiceBeautifierPreset: Identifiable { + public var id: Int { rawValue } +} + +extension AgoraAudioEffectPreset: Identifiable { + public var id: Int { rawValue } +} + +extension AgoraVoiceConversionPreset: Identifiable { + public var id: Int { rawValue } +} + +extension AUDIO_AINS_MODE: Identifiable { + public var id: Int { rawValue } +} + +extension AgoraAudioEqualizationBandFrequency: Identifiable { + public var id: Int { rawValue } +} + +extension AgoraAudioReverbType: Identifiable { + public var id: Int { rawValue } +} +#Preview { + VoiceChanger() +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VoiceChanger/VoiceChangerRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VoiceChanger/VoiceChangerRTC.swift new file mode 100644 index 000000000..455f5d0cb --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Advanced/VoiceChanger/VoiceChangerRTC.swift @@ -0,0 +1,191 @@ +// +// VoiceChangerRTC.swift +// APIExample-SwiftUI +// +// Created by qinhui on 2024/9/29. +// + +import Foundation +import AgoraRtcKit + +class VoiceChangerRTC: NSObject, ObservableObject { + var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + +// setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension VoiceChangerRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift new file mode 100644 index 000000000..3efaaf670 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift @@ -0,0 +1,170 @@ +// +// JoinchannelVideoEnter.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI +import AgoraRtcKit + +struct JoinChannelAudioEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var isShowAudioScence: Bool = false + @State private var isShowAudioProfile: Bool = false + @State private var profile: AgoraAudioProfile = .default + @State private var scenario: AgoraAudioScenario = .default + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + HStack { + Text("Audio Scenario".localized) + Spacer() + Button { + self.isShowAudioProfile = true + } label: { + Text(scenario.description()) + }.confirmationDialog("Set Audio Scenario".localized, isPresented: $isShowAudioProfile, titleVisibility: .visible) { + ForEach(AgoraAudioScenario.allValues(), id: \.self) { item in + getAudioScenarioAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 15, trailing: 35)) + HStack { + Text("Audio Profile".localized) + Spacer() + Button(profile.description()) { + self.isShowAudioScence = true + }.confirmationDialog("Set Audio Profile".localized, isPresented: $isShowAudioScence, titleVisibility: .visible) { + ForEach(AgoraAudioProfile.allValues(), id: \.self) { item in + getAudioProfileAction(item) + } + Button("Cancel".localized, role: .cancel) {} + } + }.padding(EdgeInsets(top: 0, leading: 35, bottom: 0, trailing: 35)) + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName, + "audioProfile": profile, + "audioScenario": scenario] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: JoinChannelAudio(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } + + private func getAudioProfileAction(_ profile: AgoraAudioProfile) -> some View { + Button(profile.description()){ + self.profile = profile + } + } + + private func getAudioScenarioAction(_ scenario: AgoraAudioScenario) -> some View { + Button(scenario.description()){ + self.scenario = scenario + } + } +} + +#Preview { + JoinChannelAudioEntry() +} + +struct JoinChannelAudio: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = JoinChannelAudioRTC() + @State private var isShowAudioProfile: Bool = false + @State private var scenario: AgoraAudioScenario = .default + @State private var recordingVolumeSlider: Double = 100 + @State private var playbackVolumeSlider: Double = 100 + @State private var inEarMonitoringVolumeSlider: Double = 100 + @State private var inEarMonitoringSwitch: Bool = false + + var localView = VideoView(type: .local, + audioOnly: true) + var remoteView = VideoView(type: .remote, + audioOnly: true) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + HStack { + Text("Audio Scenario".localized) + Spacer() + Button(scenario.description()) { + isShowAudioProfile = true + }.confirmationDialog("Set Audio Scenario".localized, isPresented: $isShowAudioProfile, titleVisibility: .visible) { + ForEach(AgoraAudioScenario.allValues(), id: \.self) { item in + getAudioScenarioAction(item) + } + Button("Cancel".localized, role: .cancel) {} + }.padding(.trailing, 30) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 10, trailing: 15)) + HStack { + Text("RecordingVolume".localized) + Spacer() + Slider(value: $recordingVolumeSlider, in: 0...400, step: 1).onChange(of: recordingVolumeSlider) { value in + agoraKit.onChangeRecordingVolume(value) + }.frame(maxWidth: 150) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + HStack { + Text("PlaybackVolume".localized) + Spacer() + Slider(value: $playbackVolumeSlider, in: 0...400, step: 1).onChange(of: playbackVolumeSlider) { value in + agoraKit.onChangePlaybackVolume(value) + }.frame(maxWidth: 150) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + HStack { + Text("InEar Monitoring".localized) + Spacer() + Toggle("", isOn: $inEarMonitoringSwitch).onChange(of: inEarMonitoringSwitch) { value in + agoraKit.toggleInEarMonitoring(value) + }.padding(.trailing, 20) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + HStack { + Text("InEar Monitoring Volume".localized) + Spacer() + Slider(value: $inEarMonitoringVolumeSlider, in: 0...100, step: 1).onChange(of: inEarMonitoringVolumeSlider) { value in + agoraKit.onChangeInEarMonitoringVolume(value) + }.frame(maxWidth: 150).disabled(!inEarMonitoringSwitch) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + }.onAppear(perform: { + scenario = configs["audioScenario"] as! AgoraAudioScenario + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } + + private func getAudioScenarioAction(_ scenario: AgoraAudioScenario) -> some View { + Button(action: { + self.scenario = scenario + self.agoraKit.setAudioScenario(scenario: scenario) + }, label: { + Text(scenario.description()) + }) + } +} + +#Preview { + JoinChannelAudio(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelAudio/JoinChannelAudioRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelAudio/JoinChannelAudioRTC.swift new file mode 100644 index 000000000..a479d4136 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelAudio/JoinChannelAudioRTC.swift @@ -0,0 +1,207 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class JoinChannelAudioRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + guard let channelName = configs["channelName"] as? String, + let audioProfile = configs["audioProfile"] as? AgoraAudioProfile, + let audioScenario = configs["audioScenario"] as? AgoraAudioScenario + else { return } + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + // set audio scenario + config.audioScenario = audioScenario + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + + // disable video module + agoraKit.disableVideo() + + agoraKit.enableAudio() + + // set audio profile + agoraKit.setAudioProfile(audioProfile) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // enable volume indicator + agoraKit.enableAudioVolumeIndication(200, smooth: 3, reportVad: true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = false + option.publishMicrophoneTrack = true + option.autoSubscribeAudio = true + option.autoSubscribeVideo = false + option.clientRoleType = GlobalSettings.shared.getUserRole() + + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + func onDestory() { + agoraKit.enable(inEarMonitoring: false) + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func setAudioScenario(scenario: AgoraAudioScenario) { + agoraKit.setAudioScenario(scenario) + } + + func onChangeRecordingVolume(_ value: Double) { + let value: Int = Int(value) + print("adjustRecordingSignalVolume \(value)") + agoraKit.adjustRecordingSignalVolume(value) + } + + func onChangePlaybackVolume(_ value: Double) { + let value: Int = Int(value) + print("adjustPlaybackSignalVolume \(value)") + agoraKit.adjustPlaybackSignalVolume(value) + } + + func toggleInEarMonitoring(_ isOn: Bool) { + agoraKit.enable(inEarMonitoring: isOn) + } + + func onChangeInEarMonitoringVolume(_ value: Double) { + let value: Int = Int(value) + print("setInEarMonitoringVolume \(value)") + agoraKit.setInEarMonitoringVolume(value) + } +} + +// agora rtc engine delegate events +extension JoinChannelAudioRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// Reports which users are speaking, the speakers' volumes, and whether the local user is speaking. + /// @params speakers volume info for all speakers + /// @params totalVolume Total volume after audio mixing. The value range is [0,255]. + func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) { +// for speaker in speakers { +// if let audioView = audioViews[speaker.uid] { +// audioView.setInfo(text: "Volume:\(speaker.volume)") +// } +// } + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift new file mode 100644 index 000000000..ab36f2b39 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift @@ -0,0 +1,96 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct JoinChannelVideoRecorderEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: JoinChannelVideoRecorder(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + JoinChannelVideoRecorderEntry() +} + +struct JoinChannelVideoRecorder: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @State private var isLocalStart: Bool = false + @State private var isRemoteStart: Bool = false + @State private var localRecord: String = "Recording".localized + @State private var remoteRecord: String = "Recording".localized + @ObservedObject private var agoraKit = JoinChannelVideoRecorderRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + ZStack(alignment: .bottomTrailing) { + localView + Button(localRecord) { + isLocalStart.toggle() + localRecord = isLocalStart ? "Stop Recording".localized : "Recording".localized + agoraKit.onTapLocalRecordButton(isStart: isLocalStart) + }.overlay( + RoundedRectangle(cornerRadius: 5).stroke(Color.red, lineWidth: 2).padding(-5) + ).foregroundStyle(.red) + .padding(.bottom, 20) + .padding(.trailing, 20) + } + ZStack(alignment: .bottomTrailing) { + remoteView + Button(remoteRecord) { + isRemoteStart.toggle() + remoteRecord = isRemoteStart ? "Stop Recording".localized : "Recording".localized + agoraKit.onTapRemoteRecordButton(isStart: isRemoteStart) + }.overlay( + RoundedRectangle(cornerRadius: 5).stroke(Color.red, lineWidth: 2).padding(-5) + ).foregroundStyle(.red) + .padding(.bottom, 20) + .padding(.trailing, 20) + .opacity(agoraKit.isRemoteJoind ? 1.0 : 0) + } + }.frame(maxHeight: 200) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + JoinChannelVideoRecorder(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorderRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorderRTC.swift new file mode 100644 index 000000000..185ddf1c4 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorderRTC.swift @@ -0,0 +1,263 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class JoinChannelVideoRecorderRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + private var localView: VideoUIView? + private var remoteView: VideoUIView? + private var channelName: String? + + @Published var isRemoteJoind: Bool = false + + private var storagePath: String { + let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first + return documentPath ?? "" + } + private lazy var localRecord: AgoraMediaRecorder? = { + let streamInfo = AgoraRecorderStreamInfo() + streamInfo.channelId = channelName ?? "" + streamInfo.uid = localView?.uid ?? 0 + let record = agoraKit.createMediaRecorder(withInfo: streamInfo) + record?.setMediaRecorderDelegate(self) + return record + }() + private lazy var remoteRecord: AgoraMediaRecorder? = { + let streamInfo = AgoraRecorderStreamInfo() + streamInfo.channelId = channelName ?? "" + streamInfo.uid = remoteView?.uid ?? 0 + let record = agoraKit.createMediaRecorder(withInfo: streamInfo) + record?.setMediaRecorderDelegate(self) + return record + }() + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + self.channelName = channelName + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + localRecord?.stopRecording() + remoteRecord?.stopRecording() + agoraKit.destroy(localRecord) + agoraKit.destroy(remoteRecord) + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } + + func onTapLocalRecordButton(isStart: Bool) { + let path = storagePath + "/\(localView?.uid ?? 0).mp4" + if isStart { + let config = AgoraMediaRecorderConfiguration() + config.storagePath = path + config.containerFormat = .MP4 + config.maxDurationMs = 10 * 1000 + localRecord?.startRecording(config) + } else { + localRecord?.stopRecording() + ToastView.show(text: path) + } + } + + func onTapRemoteRecordButton(isStart: Bool) { + let path = storagePath + "/\(remoteView?.uid ?? 0).mp4" + if isStart { + let config = AgoraMediaRecorderConfiguration() + config.storagePath = path + config.containerFormat = .MP4 + config.maxDurationMs = 10 * 1000 + remoteRecord?.startRecording(config) + } else { + remoteRecord?.stopRecording() + ToastView.show(text: path) + } + } +} + +extension JoinChannelVideoRecorderRTC: AgoraMediaRecorderDelegate { + func mediaRecorder(_ recorder: AgoraMediaRecorder, + stateDidChanged channelId: String, + uid: UInt, + state: AgoraMediaRecorderState, + reason: AgoraMediaRecorderReasonCode) { + LogUtils.log(message: "uid == \(uid) state == \(state.rawValue)", level: .info) + } + + func mediaRecorder(_ recorder: AgoraMediaRecorder, informationDidUpdated channelId: String, uid: UInt, info: AgoraMediaRecorderInfo) { + LogUtils.log(message: "uid == \(uid) info == \(info.recorderFileName)", level: .info) + } +} + +// agora rtc engine delegate events +extension JoinChannelVideoRecorderRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + isRemoteJoind = true + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + isRemoteJoind = false + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoToken.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoToken.swift new file mode 100644 index 000000000..4788ac831 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoToken.swift @@ -0,0 +1,95 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct JoinChannelVideoTokenEntry: View { + @State private var channelName: String = "" + @State private var appId: String = "" + @State private var token: String = "" + @State private var isActive = false + @State private var showAlert = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack(alignment: .leading) { + Spacer() + Text("AppID") + TextField("Please the input APPID".localized, text: $appId).textFieldStyle(.roundedBorder) + Text("Token") + TextField("Please the input Token".localized, text: $token).textFieldStyle(.roundedBorder) + Text("Channel Name") + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder) + HStack { + Spacer() + Button { + configs = ["channelName": channelName, + "appId": appId, + "token": token] + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(appId.isEmpty || token.isEmpty || channelName.isEmpty) + Spacer() + }.padding(.top, 20) + Spacer() + NavigationLink(destination: JoinChannelVideoToken(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + }.padding(EdgeInsets(top: 0, leading: 50, bottom: 0, trailing: 50)) + + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button(action: { + showAlert = true + }) { + Image("tips") + }.alert(isPresented: $showAlert) { + Alert(title: Text("Quick input APPID and Token methods".localized), message: Text("I: the mobile phone and Mac log in to the same Apple account. After copying the Mac, it will automatically synchronize other terminals with the same account. The mobile phone can directly click the input box to paste.\n\n II: use https://cl1p.net/ online clipboard:\n\n1.Enter in a URL that starts with cl1p.net. Example cl1p.net/uqztgjnqcalmd\n\n2.Paste in anything you want.\n\n3.On another computer enter the same URL and get your stuff.".localized), dismissButton: .default(Text("OK"))) + } + } + } + } +} +#Preview { + JoinChannelVideoTokenEntry() +} + +struct JoinChannelVideoToken: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = JoinChannelVideoTokenRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + JoinChannelVideoToken(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoTokenRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoTokenRTC.swift new file mode 100644 index 000000000..3765bf031 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoTokenRTC.swift @@ -0,0 +1,195 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class JoinChannelVideoTokenRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + + // get channel name from configs + guard let channelName = (configs["channelName"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines), + let appId = (configs["appId"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines), + let token = (configs["token"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines) else {return} + + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = appId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension JoinChannelVideoTokenRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift new file mode 100644 index 000000000..e4f80f200 --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift @@ -0,0 +1,69 @@ +// +// JoinChannelVideoView.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import SwiftUI + +struct JoinChannelVideoEntry: View { + @State private var channelName: String = "" + @State private var isActive = false + @State private var configs: [String: Any] = [:] + + var body: some View { + VStack { + Spacer() + TextField("Enter channel name".localized, text: $channelName).textFieldStyle(.roundedBorder).padding() + Button { + configs = ["channelName": channelName] + self.isActive = true + } label: { + Text("Join".localized) + }.disabled(channelName.isEmpty) + Spacer() + NavigationLink(destination: JoinChannelVideo(configs: configs).navigationTitle(channelName).navigationBarTitleDisplayMode(.inline), isActive: $isActive) { + EmptyView() + } + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + JoinChannelVideoEntry() +} + +struct JoinChannelVideo: View { + @State var configs: [String: Any] = [:] + + @State private var statsInfo: String = "" + @ObservedObject private var agoraKit = JoinChannelVideoRTC() + + var localView = VideoView(type: .local, + audioOnly: false) + var remoteView = VideoView(type: .remote, + audioOnly: false) + + var body: some View { + VStack { + HStack{ + localView + remoteView + }.frame(maxHeight: 200) + Spacer() + }.onAppear(perform: { + agoraKit.setupRTC(configs: configs, + localView: localView.videoView, + remoteView: remoteView.videoView) + }).onDisappear(perform: { + agoraKit.onDestory() + }) + } +} + +#Preview { + JoinChannelVideo(configs: [:]) +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo/JoinChannelVideoRTC.swift b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo/JoinChannelVideoRTC.swift new file mode 100644 index 000000000..d92903e2b --- /dev/null +++ b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/Basic/JoinChannelVideo/JoinChannelVideoRTC.swift @@ -0,0 +1,192 @@ +// +// JoinChannelVideoRTC.swift +// APIExample-SwiftUI +// +// Created by zhaoyongqiang on 2024/3/19. +// + +import AgoraRtcKit +import SwiftUI + +class JoinChannelVideoRTC: NSObject, ObservableObject { + private var agoraKit: AgoraRtcEngineKit! + private var isJoined: Bool = false + + private var localView: VideoUIView? + private var remoteView: VideoUIView? + + func setupRTC(configs: [String: Any], + localView: VideoUIView, + remoteView: VideoUIView) { + self.localView = localView + self.remoteView = remoteView + // set up agora instance when view loaded + let config = AgoraRtcEngineConfig() + config.appId = KeyCenter.AppId + config.areaCode = GlobalSettings.shared.area + config.channelProfile = .liveBroadcasting + agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self) + // Configuring Privatization Parameters + Util.configPrivatization(agoraKit: agoraKit) + + agoraKit.setLogFile(LogUtils.sdkLogPath()) + // get channel name from configs + guard let channelName = configs["channelName"] as? String else {return} + let fps = GlobalSettings.shared.getFps() + let resolution = GlobalSettings.shared.getResolution() + let orientation = GlobalSettings.shared.getOrientation() + + // make myself a broadcaster + agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) + // enable video module and set up video encoding configs + agoraKit.enableVideo() + agoraKit.enableAudio() + agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution, + frameRate: fps, + bitrate: AgoraVideoBitrateStandard, + orientationMode: orientation, mirrorMode: .auto)) + + setupCanvasView(view: localView.videoView) + + // Set audio route to speaker + agoraKit.setDefaultAudioRouteToSpeakerphone(true) + + // start joining channel + // 1. Users can only see each other after they join the + // same channel successfully using the same app id. + // 2. If app certificate is turned on at dashboard, token is needed + // when joining channel. The channel name and uid used to calculate + // the token has to match the ones used for channel join + let option = AgoraRtcChannelMediaOptions() + option.publishCameraTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.clientRoleType = GlobalSettings.shared.getUserRole() + NetworkManager.shared.generateToken(channelName: channelName, success: { token in + let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) + if result != 0 { + // Usually happens with invalid parameters + // Error code description can be found at: + // en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + LogUtils.log(message: "joinChannel call failed: \(result), please check your params", level: .error) + } + }) + } + + private func setupCanvasView(view: UIView?) { + // set up local video to render your local camera preview + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = 0 + // the view to be binded + videoCanvas.view = view + videoCanvas.renderMode = .hidden + agoraKit.setupLocalVideo(videoCanvas) + // you have to call startPreview to see local video + agoraKit.startPreview() + } + + func onDestory() { + agoraKit.disableAudio() + agoraKit.disableVideo() + if isJoined { + agoraKit.stopPreview() + agoraKit.leaveChannel { (stats) -> Void in + LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) + } + } + AgoraRtcEngineKit.destroy() + } +} + +// agora rtc engine delegate events +extension JoinChannelVideoRTC: AgoraRtcEngineDelegate { + /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out + /// what is happening + /// Warning code description can be found at: + /// en: https://api-ref.agora.io/en/voice-sdk/ios/3.x/Constants/AgoraWarningCode.html + /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html + /// @param warningCode warning code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) { + LogUtils.log(message: "warning: \(warningCode.description)", level: .warning) + } + + /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand + /// to let user know something wrong is happening + /// Error code description can be found at: + /// en: https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraerrorcode + /// cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code + /// @param errorCode error code of the problem + func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) { + LogUtils.log(message: "error: \(errorCode)", level: .error) +// self.showAlert(title: "Error", message: "Error \(errorCode.description) occur") + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { + self.isJoined = true + localView?.uid = uid + LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) + } + + /// 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) { + LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info) + remoteView?.uid = uid + // 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?.videoView + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + /// 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) { + LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info) + remoteView?.uid = 0 + // to unlink your view from sdk, so that your view reference will be released + // note the video will stay at its last frame, to completely remove it + // you will need to remove the EAGL sublayer from your binded view + let videoCanvas = AgoraRtcVideoCanvas() + videoCanvas.uid = uid + // the view to be binded + videoCanvas.view = nil + videoCanvas.renderMode = .hidden + agoraKit.setupRemoteVideo(videoCanvas) + } + + func rtcEngine(_ engine: AgoraRtcEngineKit, connectionChangedTo state: AgoraConnectionState, reason: AgoraConnectionChangedReason) { + LogUtils.log(message: "Connection state changed: \(state) \(reason)", level: .info) + } + + /// 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) { + localView?.statsInfo?.updateChannelStats(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) { + localView?.statsInfo?.updateLocalAudioStats(stats) + } + + /// Reports the statistics of the video stream from each remote user/host. + /// @param stats stats struct + func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) { + remoteView?.statsInfo?.updateVideoStats(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) { + remoteView?.statsInfo?.updateAudioStats(stats) + } +} diff --git a/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/output.pcm b/iOS/APIExample-SwiftUI/APIExample-SwiftUI/Examples/output.pcm new file mode 100644 index 0000000000000000000000000000000000000000..24ad15ad9041b520fabf7cb67a853e10f63357b9 GIT binary patch literal 4799796 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

D-V6#*mtTMvAqS|p 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Ξrf4c?rmqNq+PF=buj@2kOSw=2p+I5>_rM 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/} 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

~KwH5%(E6@hIVG;b@VyMlgEnFKC|7$QC;B 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%0Ai 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%0Dx%9MK<6GT}~3;ArUdw9lp3({Qi{%fgzSzi~-1D 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 F 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 literal 0 HcmV?d00001 diff --git a/windows/APIExample/APIExample/stdafx.cpp b/windows/APIExample/APIExample/stdafx.cpp index b25fb9e73..8797e7223 100755 --- a/windows/APIExample/APIExample/stdafx.cpp +++ b/windows/APIExample/APIExample/stdafx.cpp @@ -5,6 +5,7 @@ #include "stdafx.h" #include "CConfig.h" + wchar_t commonGroupDoc[INFO_LEN] = { 0 }; wchar_t commonDocumentWebsite[INFO_LEN] = { 0 }; wchar_t commonFAQWebsite[INFO_LEN] = { 0 }; @@ -318,6 +319,11 @@ wchar_t advancedMetadataVideo[INFO_LEN] = { 0 }; wchar_t advancedMetadataAudio[INFO_LEN] = { 0 }; wchar_t advancedMetadataSend[INFO_LEN] = { 0 }; + +//transparent backgroud +wchar_t TransparentBackground[INFO_LEN] = { 0 }; + + std::string cs2utf8(CString str) { char szBuf[2 * MAX_PATH] = { 0 }; @@ -767,6 +773,10 @@ void InitKeyInfomation() _tcscpy_s(advancedMetadataAudio, INFO_LEN, Str(_T("Metadata.Audio"))); _tcscpy_s(advancedMetadataSend, INFO_LEN, Str(_T("Metadata.Send"))); + //transparent bg + _tcscpy_s(TransparentBackground, INFO_LEN, Str(_T("TransparentBackground"))); + + /* _tcscpy_s(, INFO_LEN, Str(_T(""))); _tcscpy_s(, INFO_LEN, Str(_T(""))); _tcscpy_s(, INFO_LEN, Str(_T(""))); diff --git a/windows/APIExample/APIExample/zh-cn.ini b/windows/APIExample/APIExample/zh-cn.ini index 9d2e80bcd..7d44135cb 100755 --- a/windows/APIExample/APIExample/zh-cn.ini +++ b/windows/APIExample/APIExample/zh-cn.ini @@ -294,4 +294,6 @@ LocalVideoTranscoding.VirtualBg=͸ Metadata.Video=ƵԪ Metadata.Audio=ƵԪ -Metadata.Send= \ No newline at end of file +Metadata.Send= + +TransparentBackground=͸ \ No newline at end of file From 4a5da3fafda6820a13b09bbcd8be78cfb162e0f0 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 11 Sep 2024 15:09:52 +0800 Subject: [PATCH 004/166] fix: media relay(mac) bug fixed --- .../ChannelMediaRelay/ChannelMediaRelay.swift | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/macOS/APIExample/Examples/Advanced/ChannelMediaRelay/ChannelMediaRelay.swift b/macOS/APIExample/Examples/Advanced/ChannelMediaRelay/ChannelMediaRelay.swift index fa2ff91b1..87dbc9b96 100644 --- a/macOS/APIExample/Examples/Advanced/ChannelMediaRelay/ChannelMediaRelay.swift +++ b/macOS/APIExample/Examples/Advanced/ChannelMediaRelay/ChannelMediaRelay.swift @@ -15,6 +15,8 @@ class ChannelMediaRelay: BaseViewController { @IBOutlet weak var Container: AGEVideoContainer! var agoraKit: AgoraRtcEngineKit! + // configure source info, channel name defaults to current, and uid defaults to local + let mediaRelayconfig = AgoraChannelMediaRelayConfiguration() /** --- Channel TextField --- @@ -58,15 +60,15 @@ class ChannelMediaRelay: BaseViewController { self.showAlert(message: "Destination channel name is empty") return } - // configure source info, channel name defaults to current, and uid defaults to local - let config = AgoraChannelMediaRelayConfiguration() - config.sourceInfo = AgoraChannelMediaRelayInfo(token: nil) + isProcessing = true - // configure target channel info - let destinationInfo = AgoraChannelMediaRelayInfo(token: nil) - config.setDestinationInfo(destinationInfo, forChannelName: destinationChannelName) - agoraKit.startOrUpdateChannelMediaRelay(config) - pauseRelayButton.isEnabled = true + NetworkManager.shared.generateToken(channelName: destinationChannelName) { token in + // configure target channel info + let destinationInfo = AgoraChannelMediaRelayInfo(token: token) + self.mediaRelayconfig.setDestinationInfo(destinationInfo, forChannelName: destinationChannelName) + self.agoraKit.startOrUpdateChannelMediaRelay(self.mediaRelayconfig) + self.pauseRelayButton.isEnabled = true + } } else { isProcessing = true isPauseRelaying = false @@ -211,6 +213,7 @@ class ChannelMediaRelay: BaseViewController { // cn: https://doc.shengwang.cn/api-ref/rtc/ios/error-code self.showAlert(title: "Error", message: "joinChannel call failed: \(result), please check your params") } + self.mediaRelayconfig.sourceInfo = AgoraChannelMediaRelayInfo(token: token) }) } else { isProcessing = true From a3f32a725a61b128ad1afeae42b88f090cc76709 Mon Sep 17 00:00:00 2001 From: "1138289316@qq.com" <1138289316@qq.com> Date: Wed, 11 Sep 2024 21:26:46 +0800 Subject: [PATCH 005/166] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E9=80=8F=E6=98=8E=E6=95=88=E6=9E=9C=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- windows/APIExample/APIExample/APIExample.rc | 33 ++ .../APIExample/APIExample/APIExample.vcxproj | 2 + .../APIExample/APIExample.vcxproj.filters | 9 + .../APIExample/APIExample/APIExampleDlg.cpp | 13 +- windows/APIExample/APIExample/APIExampleDlg.h | 2 + .../TransparentBg/TransparentBgDialog.cpp | 372 ++++++++++++++++++ .../TransparentBg/TransparentBgDialog.h | 101 +++++ windows/APIExample/APIExample/resource.h | 7 +- 8 files changed, 536 insertions(+), 3 deletions(-) create mode 100644 windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp create mode 100644 windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h diff --git a/windows/APIExample/APIExample/APIExample.rc b/windows/APIExample/APIExample/APIExample.rc index fb7ec45bc..7621d33ff 100755 --- a/windows/APIExample/APIExample/APIExample.rc +++ b/windows/APIExample/APIExample/APIExample.rc @@ -752,6 +752,20 @@ BEGIN EDITTEXT IDC_EDIT_TOKEN,69,363,128,29,ES_AUTOHSCROLL END +IDD_DIALOG_TRANSPARENT_BG DIALOGEX 0, 0, 632, 400 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Channel Name",IDC_STATIC_CHANNELNAME,136,360,48,8 + EDITTEXT IDC_EDIT_CHANNELNAME,216,358,172,13,ES_AUTOHSCROLL + PUSHBUTTON "JoinChannel",IDC_BUTTON_JOINCHANNEL,420,358,75,14 + LTEXT "",IDC_STATIC_DETAIL,23,370,412,27 + LTEXT "",IDC_STATIC_VIDEO,0,0,419,147 + LTEXT "",IDC_STATIC_VIDEO_RIGHT,233,175,176,136 + LTEXT "",IDC_STATIC_VIDEO_LEFT,2,173,171,136 + LISTBOX IDC_LIST_INFO_BROADCASTING,491,0,139,312,LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP +END + ///////////////////////////////////////////////////////////////////////////// // @@ -907,6 +921,14 @@ BEGIN HORZGUIDE, 163 END + IDD_DIALOG_VOLUME, DIALOG + BEGIN + END + + IDD_DIALOG_PEPORT_IN_CALL, DIALOG + BEGIN + END + IDD_DIALOG_REGIONAL_CONNECTION, DIALOG BEGIN END @@ -1048,6 +1070,12 @@ BEGIN HORZGUIDE, 348 HORZGUIDE, 363 END + + IDD_DIALOG_TRANSPARENT_BG, DIALOG + BEGIN + RIGHTMARGIN, 630 + BOTTOMMARGIN, 397 + END END #endif // APSTUDIO_INVOKED @@ -1187,6 +1215,11 @@ BEGIN 0 END +IDD_DIALOG_TRANSPARENT_BG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/windows/APIExample/APIExample/APIExample.vcxproj b/windows/APIExample/APIExample/APIExample.vcxproj index ae9d15a06..cc6dff5d2 100644 --- a/windows/APIExample/APIExample/APIExample.vcxproj +++ b/windows/APIExample/APIExample/APIExample.vcxproj @@ -295,6 +295,7 @@ if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)\$(Configuration)) + @@ -347,6 +348,7 @@ if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)\$(Configuration)) + diff --git a/windows/APIExample/APIExample/APIExample.vcxproj.filters b/windows/APIExample/APIExample/APIExample.vcxproj.filters index de1e3f9ea..12ef0a878 100644 --- a/windows/APIExample/APIExample/APIExample.vcxproj.filters +++ b/windows/APIExample/APIExample/APIExample.vcxproj.filters @@ -112,6 +112,9 @@ {ed782797-3b06-44a9-8894-6b9d93d0dfea} + + {2a74c488-9982-4577-8594-8320c71beb6d} + @@ -264,6 +267,9 @@ Advanced\Metadata + + Advanced\TransparentBg + @@ -404,6 +410,9 @@ Advanced\Metadata + + Advanced\TransparentBg + diff --git a/windows/APIExample/APIExample/APIExampleDlg.cpp b/windows/APIExample/APIExample/APIExampleDlg.cpp index d3f4d71b2..959268f1f 100755 --- a/windows/APIExample/APIExample/APIExampleDlg.cpp +++ b/windows/APIExample/APIExample/APIExampleDlg.cpp @@ -385,6 +385,12 @@ void CAPIExampleDlg::InitSceneDialog() m_pMultiVideoSourceTracks = new MultiVideoSourceTracks(&m_staMainArea); m_pMultiVideoSourceTracks->Create(MultiVideoSourceTracks::IDD); m_pMultiVideoSourceTracks->MoveWindow(&rcWnd); + + // transparent bg + m_TransparentDlg = new CTransparentBgDlg(&m_staMainArea); + m_TransparentDlg->Create(CTransparentBgDlg::IDD); + m_TransparentDlg->MoveWindow(&rcWnd); + } void CAPIExampleDlg::InitSceneList() @@ -608,7 +614,8 @@ void CAPIExampleDlg::CreateScene(CTreeCtrl& treeScene, CString selectedText) m_pmediaRecorderDlg->ShowWindow(SW_SHOW); } else if (selectedText.Compare(TransparentBackground) == 0) { - MessageBox(_T("TransparentBackground")); + m_TransparentDlg->InitAgora(); + m_TransparentDlg->ShowWindow(SW_SHOW); } //Sleep(500); @@ -715,6 +722,10 @@ void CAPIExampleDlg::ReleaseScene(CTreeCtrl& treeScene, HTREEITEM& hSelectItem) m_pmediaRecorderDlg->UnInitAgora(); m_pmediaRecorderDlg->ShowWindow(SW_HIDE); } + else if (str.Compare(TransparentBackground) == 0) { + m_TransparentDlg->UnInitAgora(); + m_TransparentDlg->ShowWindow(SW_HIDE); + } //Sleep(500); } diff --git a/windows/APIExample/APIExample/APIExampleDlg.h b/windows/APIExample/APIExample/APIExampleDlg.h index 12c9bd6bb..295ed85c9 100755 --- a/windows/APIExample/APIExample/APIExampleDlg.h +++ b/windows/APIExample/APIExample/APIExampleDlg.h @@ -33,6 +33,7 @@ #include "Advanced/PushExternalVideoYUV/PushExternalVideoYUV.h" #include "Advanced/MultiVideoSourceTracks/MultiVideoSourceTracks.h" #include "Advanced/FaceCapture/CAgoraFaceCaptureDlg.h" +#include "Advanced/TransparentBg/TransparentBgDialog.h" #include #include #include @@ -108,6 +109,7 @@ class CAPIExampleDlg : public CDialogEx MultiVideoSourceTracks *m_pMultiVideoSourceTracks = nullptr; CAgoraFaceCaptureDlg *m_pAgoraFaceCaptureDlg = nullptr; CDlgBeauty * m_pDlgBeauty = nullptr; + CTransparentBgDlg* m_TransparentDlg = nullptr; CString m_preSelectedItemText = _T(""); std::vector m_vecBasic, m_vecAdvanced; std::mutex m_mutex; diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp new file mode 100644 index 000000000..ee99d4698 --- /dev/null +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp @@ -0,0 +1,372 @@ +#include "stdafx.h" +#include "APIExample.h" +#include "TransparentBgDialog.h" + +void CTransparentBgEventHandler::onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) +{ + if (m_hMsgHanlder) { + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_JOINCHANNEL_SUCCESS), (WPARAM)uid, (LPARAM)elapsed); + } +} + +void CTransparentBgEventHandler::onUserJoined(uid_t uid, int elapsed) { + if (m_hMsgHanlder) { + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_USER_JOINED), (WPARAM)uid, (LPARAM)elapsed); + } +} + +void CTransparentBgEventHandler::onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) +{ + if (m_hMsgHanlder) { + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_USER_OFFLINE), (WPARAM)uid, (LPARAM)reason); + } +} + +void CTransparentBgEventHandler::onLeaveChannel(const RtcStats& stats) +{ + if (m_hMsgHanlder) { + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LEAVE_CHANNEL), 0, 0); + } +} + + +void CTransparentBgEventHandler::onLocalVideoStats(VIDEO_SOURCE_TYPE source, const LocalVideoStats& stats) +{ + if (m_hMsgHanlder && report) { + LocalVideoStats* s = new LocalVideoStats; + *s = stats; + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_VIDEO_STATS), (WPARAM)s, 0); + } +} + +IMPLEMENT_DYNAMIC(CTransparentBgDlg, CDialogEx) + +CTransparentBgDlg::CTransparentBgDlg(CWnd* pParent /*=nullptr*/) + : CDialogEx(IDD_DIALOG_TRANSPARENT_BG, pParent) +{ + +} + +CTransparentBgDlg::~CTransparentBgDlg() +{ +} + +void CTransparentBgDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogEx::DoDataExchange(pDX); + DDX_Control(pDX, IDC_STATIC_CHANNELNAME, m_staticChannelName); + DDX_Control(pDX, IDC_BUTTON_JOINCHANNEL, m_bnJoinChannel); + DDX_Control(pDX, IDC_EDIT_CHANNELNAME, m_editChannel); + DDX_Control(pDX, IDC_STATIC_VIDEO, m_staticVideo); + DDX_Control(pDX, IDC_STATIC_VIDEO_LEFT, m_staticVideoLeft); + DDX_Control(pDX, IDC_STATIC_VIDEO_RIGHT, m_staticVideoRight); + DDX_Control(pDX, IDC_LIST_INFO_BROADCASTING, m_listInfo); +} + + +BEGIN_MESSAGE_MAP(CTransparentBgDlg, CDialogEx) + + ON_MESSAGE(WM_MSGID(EID_JOINCHANNEL_SUCCESS), &CTransparentBgDlg::OnEIDJoinChannelSuccess) + ON_MESSAGE(WM_MSGID(EID_ERROR), &CTransparentBgDlg::OnEIDError) + ON_MESSAGE(WM_MSGID(EID_LEAVE_CHANNEL), &CTransparentBgDlg::OnEIDLeaveChannel) + ON_MESSAGE(WM_MSGID(EID_USER_JOINED), &CTransparentBgDlg::OnEIDUserJoined) + ON_MESSAGE(WM_MSGID(EID_USER_OFFLINE), &CTransparentBgDlg::OnEIDUserOffline) + + ON_MESSAGE(WM_MSGID(EID_LOCAL_AUDIO_STATS), &CTransparentBgDlg::onEIDLocalAudioStats) + ON_MESSAGE(WM_MSGID(EID_REMOTE_AUDIO_STATS), &CTransparentBgDlg::onEIDRemoteAudioStats) + ON_MESSAGE(WM_MSGID(EID_LOCAL_VIDEO_STATS), &CTransparentBgDlg::onEIDLocalVideoStats) + ON_MESSAGE(WM_MSGID(EID_REMOTE_VIDEO_STATS), &CTransparentBgDlg::onEIDRemoteVideoStats) + + ON_WM_SHOWWINDOW() + + ON_BN_CLICKED(IDC_BUTTON_JOINCHANNEL, &CTransparentBgDlg::OnBnClickedButtonJoinchannel) + ON_WM_SHOWWINDOW() +END_MESSAGE_MAP() + + +// CTransparentBgDlg message handlers +BOOL CTransparentBgDlg::OnInitDialog() +{ + CDialogEx::OnInitDialog(); + InitCtrlText(); + return TRUE; +} + + +//set control text from config. +void CTransparentBgDlg::InitCtrlText() +{ + m_staticChannelName.SetWindowText(commonCtrlChannel); + m_bnJoinChannel.SetWindowText(commonCtrlJoinChannel); +} + +int CTransparentBgDlg::JoinChannel(const char* channel) +{ + VideoEncoderConfiguration config; + m_rtcEngine->setVideoEncoderConfiguration(config); + std::string szChannelId = channel; + + ChannelMediaOptions options; + options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; + options.clientRoleType = CLIENT_ROLE_BROADCASTER; + options.autoSubscribeAudio = false; + options.autoSubscribeVideo = true; + options.publishMicrophoneTrack = false; + options.publishCameraTrack = true; + //join channel in the engine. + int ret = m_rtcEngine->joinChannel(APP_TOKEN, szChannelId.c_str(), m_uid, options); + return ret; +} + +int CTransparentBgDlg::LeaveChannel() +{ + if(!m_joinChannel) + { + return 0; + }; + int ret = m_rtcEngine->leaveChannel(); + m_joinChannel = false; + m_remoteId = 0; + return ret; +} + +//Initialize the Agora SDK +bool CTransparentBgDlg::InitAgora() +{ + //create Agora RTC engine + m_rtcEngine = createAgoraRtcEngine(); + if (!m_rtcEngine) { + m_listInfo.InsertString(m_listInfo.GetCount(), _T("createAgoraRtcEngine failed")); + return false; + } + //set message notify receiver window + m_eventHandler.SetMsgReceiver(m_hWnd); + + RtcEngineContext context; + std::string strAppID = GET_APP_ID; + context.appId = strAppID.c_str(); + context.eventHandler = &m_eventHandler; + //set channel profile in the engine to the CHANNEL_PROFILE_LIVE_BROADCASTING. + context.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; + //initialize the Agora RTC engine context. + int ret = m_rtcEngine->initialize(context); + if (ret != 0) { + m_initialize = false; + CString strInfo; + strInfo.Format(_T("initialize failed: %d"), ret); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + return false; + } + else + { + m_initialize = true; + m_listInfo.InsertString(m_listInfo.GetCount(), _T("createAgoraRtcEngine success")); + } + m_rtcEngine->enableVideo(); + m_rtcEngine->enableAudio(); + return true; +} + +//UnInitialize the Agora SDK +void CTransparentBgDlg::UnInitAgora() +{ + if (m_rtcEngine) { + if(m_joinChannel) + m_rtcEngine->leaveChannel(); + // m_rtcEngine->stopPreview(); + m_rtcEngine->disableVideo(); + if (m_initialize) { + m_rtcEngine->release(true); + } + m_rtcEngine = NULL; + } +} + + +LRESULT CTransparentBgDlg::OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam) +{ + CString strInfo; + strInfo.Format(TEXT("self join success, wParam=%u"), wParam); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + //notify parent window + ::PostMessage(GetParent()->GetSafeHwnd(), WM_MSGID(EID_JOINCHANNEL_SUCCESS), TRUE, 0); + return 0; +} + +LRESULT CTransparentBgDlg::OnEIDError(WPARAM wParam, LPARAM lParam) +{ + CString strInfo; + char* message = (char*)wParam; + int code = lParam; + strInfo.Format(TEXT("Error >> code=%d, message=%s"), code, utf82cs(std::string(message))); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + delete message; + return 0; +} + +LRESULT CTransparentBgDlg::OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam) +{ + m_uid = 0; + CString strInfo; + strInfo.Format(TEXT("leave channel success")); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + //notify parent window + ::PostMessage(GetParent()->GetSafeHwnd(), WM_MSGID(EID_JOINCHANNEL_SUCCESS), FALSE, 0); + return 0; +} + +LRESULT CTransparentBgDlg::OnEIDUserJoined(WPARAM wParam, LPARAM lParam) +{ + if (m_remoteId!=0) + { + m_listInfo.InsertString(m_listInfo.GetCount(), _T("user joined already")); + return 0; + } + CString strInfo; + strInfo.Format(TEXT("user %u joined"), wParam); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + + VideoCanvas canvas; + canvas.enableAlphaMask = true; + canvas.uid = wParam; + canvas.view = m_staticVideoRight.GetSafeHwnd(); + canvas.renderMode = media::base::RENDER_MODE_FIT; + m_rtcEngine->setupRemoteVideo(canvas); + return 0; +} + +LRESULT CTransparentBgDlg::OnEIDUserOffline(WPARAM wParam, LPARAM lParam) +{ + m_remoteId = 0; + uid_t remoteUid = (uid_t)wParam; + VideoCanvas canvas; + canvas.uid = remoteUid; + canvas.view = NULL; + m_rtcEngine->setupRemoteVideo(canvas); + CString strInfo; + strInfo.Format(TEXT("%u offline, reason:%d"), remoteUid, lParam); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + return 0; +} + +BOOL CTransparentBgDlg::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { + return TRUE; + } + return CDialogEx::PreTranslateMessage(pMsg); +} + + + +LRESULT CTransparentBgDlg::onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam) { + LocalAudioStats* stats = (LocalAudioStats*)wParam; + + //m_videoWnds[0].SetAudioStatsInfo(stats->sentBitrate, stats->txPacketLossRate); + + if (stats) { + delete stats; + stats = nullptr; + } + return 0; +} + +LRESULT CTransparentBgDlg::onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam) { + RemoteAudioStats* stats = (RemoteAudioStats*)wParam; + + /*for (int i = 0; i < VIDEO_COUNT; i++) + { + if (m_videoWnds[i].GetUID() == stats->uid) { + m_videoWnds[i].SetAudioStatsInfo(stats->receivedBitrate, stats->audioLossRate, stats->jitterBufferDelay); + break; + } + }*/ + + if (stats) { + delete stats; + stats = nullptr; + } + return 0; +} + + +LRESULT CTransparentBgDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) { + LocalVideoStats* stats = (LocalVideoStats*)wParam; + + /*m_videoWnds[0].SetVideoStatsInfo(stats->encodedFrameWidth, stats->encodedFrameHeight, stats->sentFrameRate, stats->sentBitrate, stats->txPacketLossRate); + + if (stats) { + delete stats; + stats = nullptr; + }*/ + + + return 0; +} + +LRESULT CTransparentBgDlg::onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam) { + RemoteVideoStats* stats = (RemoteVideoStats*)wParam; +// CString strInfo = _T("===onRemoteVideoStats==="); +// m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + return 0; +} + + + +void CTransparentBgDlg::OnBnClickedButtonJoinchannel() +{ + CString info; + if (!m_joinChannel) { + CString strChannelName; + m_editChannel.GetWindowText(strChannelName); + if (strChannelName.IsEmpty()) { + MessageBox(_T("频道号不能为空")); + return; + } + + std::string szChannelName = cs2utf8(strChannelName); + int ret = JoinChannel(szChannelName.c_str()); + if (ret == 0) { + m_joinChannel = true; + m_bnJoinChannel.SetWindowText(commonCtrlLeaveChannel); + m_rtcEngine->enableVideo(); + m_rtcEngine->startPreview(); + VideoCanvas canvas; + canvas.renderMode = media::base::RENDER_MODE_FIT; + canvas.uid = m_uid; + canvas.view = m_staticVideoLeft.GetSafeHwnd(); + m_rtcEngine->setupLocalVideo(canvas); + } + else { + const char* des = getAgoraSdkErrorDescription(ret); + info.Format(TEXT("join channel failed >> code=%d, des=%s"), ret, utf82cs(std::string(des))); + m_listInfo.InsertString(m_listInfo.GetCount(), info); + } + } + else { + int ret = LeaveChannel(); + if (0 == ret) { + m_bnJoinChannel.SetWindowText(commonCtrlJoinChannel); + } + else { + const char* des = getAgoraSdkErrorDescription(ret); + info.Format(TEXT("leave channel failed >> code=%d, des=%s"), ret, utf82cs(std::string(des))); + m_listInfo.InsertString(m_listInfo.GetCount(), info); + } + } + +} + + +void CTransparentBgDlg::OnShowWindow(BOOL bShow, UINT nStatus) +{ + CDialogEx::OnShowWindow(bShow, nStatus); + + if (bShow) { + //resume + } + else + { + //pause + } +} diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h new file mode 100644 index 000000000..8046b1cf8 --- /dev/null +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h @@ -0,0 +1,101 @@ +#pragma once +#include "AGVideoWnd.h" +#include +#include +#include "stdafx.h" + +class CTransparentBgEventHandler : public IRtcEngineEventHandler +{ +public: + void SetMsgReceiver(HWND hWnd) { m_hMsgHanlder = hWnd; } + virtual void onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) override; + virtual void onUserJoined(uid_t uid, int elapsed) override; + virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) override; + virtual void onLeaveChannel(const RtcStats& stats) override; + virtual void onLocalAudioStats(const LocalAudioStats& stats) override{ + if (m_hMsgHanlder&& report) { + LocalAudioStats* s = new LocalAudioStats; + *s = stats; + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_AUDIO_STATS), (WPARAM)s, 0); + + } + } + virtual void onRemoteAudioStats(const RemoteAudioStats& stats) { + if (m_hMsgHanlder&& report) { + RemoteAudioStats* s = new RemoteAudioStats; + *s = stats; + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_AUDIO_STATS), (WPARAM)s, 0); + + } + } + virtual void onRemoteVideoStats(const RemoteVideoStats& stats) { + if (m_hMsgHanlder&& report) { + RemoteVideoStats* s = new RemoteVideoStats; + *s = stats; + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_VIDEO_STATS), (WPARAM)s, 0); + } + } + virtual void onLocalVideoStats(VIDEO_SOURCE_TYPE source, const LocalVideoStats& stats) override; + virtual void onError(int err, const char* msg) { + if (m_hMsgHanlder) { + char* message = new char[1024]{0}; + memcpy(message, msg, strlen(msg)); + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_ERROR), (WPARAM)message, err); + + } + } +private: + HWND m_hMsgHanlder = nullptr; + bool report = true; +}; + +class CTransparentBgDlg : public CDialogEx +{ + DECLARE_DYNAMIC(CTransparentBgDlg) + +public: + CTransparentBgDlg(CWnd* pParent = nullptr); // standard constructor + virtual ~CTransparentBgDlg(); + bool InitAgora(); + void UnInitAgora(); + enum { IDD = IDD_DIALOG_TRANSPARENT_BG}; +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + DECLARE_MESSAGE_MAP() +public: + afx_msg LRESULT OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDError(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDUserJoined(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDUserOffline(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam); + +private: + void InitCtrlText(); + int JoinChannel(const char* channel); + int LeaveChannel(); + IRtcEngine* m_rtcEngine = nullptr; + CTransparentBgEventHandler m_eventHandler; + bool m_joinChannel = false; + bool m_initialize = false; + int m_uid = 1001; + int m_remoteId = 0; +public: + virtual BOOL OnInitDialog(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + afx_msg void OnBnClickedButtonJoinchannel(); +private: + CStatic m_staticChannelName; + CButton m_bnJoinChannel; + CEdit m_editChannel; + CStatic m_staticVideo; + CStatic m_staticVideoLeft; + CStatic m_staticVideoRight; + CListBox m_listInfo; +public: + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); +}; diff --git a/windows/APIExample/APIExample/resource.h b/windows/APIExample/APIExample/resource.h index 0ec5cd196..147f9e4b8 100755 --- a/windows/APIExample/APIExample/resource.h +++ b/windows/APIExample/APIExample/resource.h @@ -45,6 +45,7 @@ #define IDD_DIALOG_MULTI_VIDEO_SOURCE_TRACKS 162 #define IDD_DIALOG_FACE_CAPTURE 163 #define IDD_DIALOG_JOINCHANNELVIDEOBYTOKEN 164 +#define IDD_DIALOG_TRANSPARENT_BG 165 #define IDB_BITMAP_LOCAL 168 #define IDB_BITMAP_REMOTE 170 #define IDB_BITMAP_SPEAKER 171 @@ -401,7 +402,9 @@ #define IDC_EDIT_TOKEN 1150 #define IDC_EDIT_METADATA_INFO 1150 #define IDC_STATIC_TOKEN 1151 +#define IDC_STATIC_VIDEO_LEFT 1151 #define IDC_USER_ID 1152 +#define IDC_STATIC_VIDEO_RIGHT 1152 #define IDC_EDIT_USER_ID 1153 #define IDC_BUTTON_ADD_CROSS_CHANNEL 1154 #define IDC_CROSS_CHANNEL_LIST 1155 @@ -423,9 +426,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 173 +#define _APS_NEXT_RESOURCE_VALUE 175 #define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1151 +#define _APS_NEXT_CONTROL_VALUE 1153 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif From e7349643fca52d79b7825ffd1aed1e70dc64a262 Mon Sep 17 00:00:00 2001 From: "1138289316@qq.com" <1138289316@qq.com> Date: Thu, 12 Sep 2024 18:30:47 +0800 Subject: [PATCH 006/166] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../APIExample/APIExample/APIExample.vcxproj | 6 +- .../APIExample/APIExample.vcxproj.filters | 12 + .../AbstractMediaPlayerSourceObserver.cpp | 45 ++ .../AbstractMediaPlayerSourceObserver.h | 27 + .../TransparentBg/TransparentBgDialog.cpp | 501 ++++++++++++------ .../TransparentBg/TransparentBgDialog.h | 110 ++-- windows/APIExample/APIExample/resource.h | 2 +- 7 files changed, 493 insertions(+), 210 deletions(-) create mode 100644 windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.cpp create mode 100644 windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.h diff --git a/windows/APIExample/APIExample/APIExample.vcxproj b/windows/APIExample/APIExample/APIExample.vcxproj index cc6dff5d2..caa961adc 100644 --- a/windows/APIExample/APIExample/APIExample.vcxproj +++ b/windows/APIExample/APIExample/APIExample.vcxproj @@ -94,7 +94,7 @@ Level3 Disabled false - WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions); + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) $(solutionDir)ThirdParty\libFFmpeg\include;$(solutionDir)ThirdParty\Boost;$(SolutionDir)sdk\high_level_api\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir) MultiThreadedDLL @@ -267,6 +267,7 @@ if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)\$(Configuration)) + @@ -320,6 +321,7 @@ if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)\$(Configuration)) + @@ -397,6 +399,7 @@ if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)\$(Configuration)) Document + @@ -420,6 +423,7 @@ if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)\$(Configuration)) Document + diff --git a/windows/APIExample/APIExample/APIExample.vcxproj.filters b/windows/APIExample/APIExample/APIExample.vcxproj.filters index 12ef0a878..a16906e88 100644 --- a/windows/APIExample/APIExample/APIExample.vcxproj.filters +++ b/windows/APIExample/APIExample/APIExample.vcxproj.filters @@ -270,6 +270,9 @@ Advanced\TransparentBg + + Header Files + @@ -413,6 +416,9 @@ Advanced\TransparentBg + + Source Files + @@ -429,6 +435,9 @@ Resource Files + + Resource Files + @@ -451,6 +460,9 @@ Resource Files + + Resource Files + diff --git a/windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.cpp b/windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.cpp new file mode 100644 index 000000000..2cfadad76 --- /dev/null +++ b/windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.cpp @@ -0,0 +1,45 @@ +#include "AbstractMediaPlayerSourceObserver.h" + +void AbstractMediaPlayerSourceObserver::onPlayerSourceStateChanged(media::base::MEDIA_PLAYER_STATE state, media::base::MEDIA_PLAYER_REASON reason) +{ +} + +void AbstractMediaPlayerSourceObserver::onPositionChanged(int64_t positionMs, int64_t timestampMs) +{ +} + +void AbstractMediaPlayerSourceObserver::onPlayerEvent(media::base::MEDIA_PLAYER_EVENT eventCode, int64_t elapsedTime, const char *message) +{ +} + +void AbstractMediaPlayerSourceObserver::onMetaData(const void *data, int length) +{ +} + +void AbstractMediaPlayerSourceObserver::onPlayBufferUpdated(int64_t playCachedBuffer) +{ +} + +void AbstractMediaPlayerSourceObserver::onPreloadEvent(const char *src, media::base::PLAYER_PRELOAD_EVENT event) +{ +} + +void AbstractMediaPlayerSourceObserver::onCompleted() +{ +} + +void AbstractMediaPlayerSourceObserver::onAgoraCDNTokenWillExpire() +{ +} + +void AbstractMediaPlayerSourceObserver::onPlayerSrcInfoChanged(const media::base::SrcInfo &from, const media::base::SrcInfo &to) +{ +} + +void AbstractMediaPlayerSourceObserver::onPlayerInfoUpdated(const media::base::PlayerUpdatedInfo &info) +{ +} + +void AbstractMediaPlayerSourceObserver::onAudioVolumeIndication(int volume) +{ +} diff --git a/windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.h b/windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.h new file mode 100644 index 000000000..362b10e5e --- /dev/null +++ b/windows/APIExample/APIExample/AbstractMediaPlayerSourceObserver.h @@ -0,0 +1,27 @@ +#pragma once +#include "stdafx.h" +#include +#include +#include + +using namespace agora; +using namespace agora::rtc; +class AbstractMediaPlayerSourceObserver : + public IMediaPlayerSourceObserver +{ +public: + + virtual void onPlayerSourceStateChanged(media::base::MEDIA_PLAYER_STATE state, media::base::MEDIA_PLAYER_REASON reason) override; + void onPositionChanged(int64_t positionMs, int64_t timestampMs) override; + void onPlayerEvent(media::base::MEDIA_PLAYER_EVENT eventCode, int64_t elapsedTime, const char* message) override; + void onMetaData(const void* data, int length) override; + void onPlayBufferUpdated(int64_t playCachedBuffer) override; + void onPreloadEvent(const char* src, media::base::PLAYER_PRELOAD_EVENT event) override; + void onCompleted() override; + void onAgoraCDNTokenWillExpire() override; + void onPlayerSrcInfoChanged(const media::base::SrcInfo& from, const media::base::SrcInfo& to) override; + void onPlayerInfoUpdated(const media::base::PlayerUpdatedInfo& info) override; + void onAudioVolumeIndication(int volume) override; + +}; + diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp index ee99d4698..35e9a54b9 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp @@ -2,56 +2,60 @@ #include "APIExample.h" #include "TransparentBgDialog.h" -void CTransparentBgEventHandler::onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) +void CTransparentBgEventHandler::onJoinChannelSuccess(const char *channel, uid_t uid, int elapsed) { - if (m_hMsgHanlder) { + if (m_hMsgHanlder) + { ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_JOINCHANNEL_SUCCESS), (WPARAM)uid, (LPARAM)elapsed); } } -void CTransparentBgEventHandler::onUserJoined(uid_t uid, int elapsed) { - if (m_hMsgHanlder) { +void CTransparentBgEventHandler::onUserJoined(uid_t uid, int elapsed) +{ + if (m_hMsgHanlder) + { ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_USER_JOINED), (WPARAM)uid, (LPARAM)elapsed); } } void CTransparentBgEventHandler::onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) { - if (m_hMsgHanlder) { + if (m_hMsgHanlder) + { ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_USER_OFFLINE), (WPARAM)uid, (LPARAM)reason); } } -void CTransparentBgEventHandler::onLeaveChannel(const RtcStats& stats) +void CTransparentBgEventHandler::onLeaveChannel(const RtcStats &stats) { - if (m_hMsgHanlder) { + if (m_hMsgHanlder) + { ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LEAVE_CHANNEL), 0, 0); } } - -void CTransparentBgEventHandler::onLocalVideoStats(VIDEO_SOURCE_TYPE source, const LocalVideoStats& stats) +void CTransparentBgEventHandler::onLocalVideoStats(VIDEO_SOURCE_TYPE source, const LocalVideoStats &stats) { - if (m_hMsgHanlder && report) { - LocalVideoStats* s = new LocalVideoStats; - *s = stats; - ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_VIDEO_STATS), (WPARAM)s, 0); - } + if (m_hMsgHanlder && report) + { + LocalVideoStats *s = new LocalVideoStats; + *s = stats; + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_VIDEO_STATS), (WPARAM)s, 0); + } } IMPLEMENT_DYNAMIC(CTransparentBgDlg, CDialogEx) -CTransparentBgDlg::CTransparentBgDlg(CWnd* pParent /*=nullptr*/) - : CDialogEx(IDD_DIALOG_TRANSPARENT_BG, pParent) +CTransparentBgDlg::CTransparentBgDlg(CWnd *pParent /*=nullptr*/) + : CDialogEx(IDD_DIALOG_TRANSPARENT_BG, pParent) { - } CTransparentBgDlg::~CTransparentBgDlg() { } -void CTransparentBgDlg::DoDataExchange(CDataExchange* pDX) +void CTransparentBgDlg::DoDataExchange(CDataExchange *pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_STATIC_CHANNELNAME, m_staticChannelName); @@ -63,48 +67,52 @@ void CTransparentBgDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_LIST_INFO_BROADCASTING, m_listInfo); } - BEGIN_MESSAGE_MAP(CTransparentBgDlg, CDialogEx) - ON_MESSAGE(WM_MSGID(EID_JOINCHANNEL_SUCCESS), &CTransparentBgDlg::OnEIDJoinChannelSuccess) - ON_MESSAGE(WM_MSGID(EID_ERROR), &CTransparentBgDlg::OnEIDError) - ON_MESSAGE(WM_MSGID(EID_LEAVE_CHANNEL), &CTransparentBgDlg::OnEIDLeaveChannel) - ON_MESSAGE(WM_MSGID(EID_USER_JOINED), &CTransparentBgDlg::OnEIDUserJoined) - ON_MESSAGE(WM_MSGID(EID_USER_OFFLINE), &CTransparentBgDlg::OnEIDUserOffline) - - ON_MESSAGE(WM_MSGID(EID_LOCAL_AUDIO_STATS), &CTransparentBgDlg::onEIDLocalAudioStats) - ON_MESSAGE(WM_MSGID(EID_REMOTE_AUDIO_STATS), &CTransparentBgDlg::onEIDRemoteAudioStats) - ON_MESSAGE(WM_MSGID(EID_LOCAL_VIDEO_STATS), &CTransparentBgDlg::onEIDLocalVideoStats) - ON_MESSAGE(WM_MSGID(EID_REMOTE_VIDEO_STATS), &CTransparentBgDlg::onEIDRemoteVideoStats) - - ON_WM_SHOWWINDOW() - - ON_BN_CLICKED(IDC_BUTTON_JOINCHANNEL, &CTransparentBgDlg::OnBnClickedButtonJoinchannel) - ON_WM_SHOWWINDOW() -END_MESSAGE_MAP() +ON_MESSAGE(WM_MSGID(EID_JOINCHANNEL_SUCCESS), &CTransparentBgDlg::OnEIDJoinChannelSuccess) +ON_MESSAGE(WM_MSGID(EID_ERROR), &CTransparentBgDlg::OnEIDError) +ON_MESSAGE(WM_MSGID(EID_LEAVE_CHANNEL), &CTransparentBgDlg::OnEIDLeaveChannel) +ON_MESSAGE(WM_MSGID(EID_USER_JOINED), &CTransparentBgDlg::OnEIDUserJoined) +ON_MESSAGE(WM_MSGID(EID_USER_OFFLINE), &CTransparentBgDlg::OnEIDUserOffline) + +ON_MESSAGE(WM_MSGID(EID_LOCAL_AUDIO_STATS), &CTransparentBgDlg::onEIDLocalAudioStats) +ON_MESSAGE(WM_MSGID(EID_REMOTE_AUDIO_STATS), &CTransparentBgDlg::onEIDRemoteAudioStats) +ON_MESSAGE(WM_MSGID(EID_LOCAL_VIDEO_STATS), &CTransparentBgDlg::onEIDLocalVideoStats) +ON_MESSAGE(WM_MSGID(EID_REMOTE_VIDEO_STATS), &CTransparentBgDlg::onEIDRemoteVideoStats) + +ON_WM_SHOWWINDOW() +ON_BN_CLICKED(IDC_BUTTON_JOINCHANNEL, &CTransparentBgDlg::OnBnClickedButtonJoinchannel) +ON_WM_SHOWWINDOW() +END_MESSAGE_MAP() // CTransparentBgDlg message handlers BOOL CTransparentBgDlg::OnInitDialog() { CDialogEx::OnInitDialog(); + + m_listInfo.ResetContent(); InitCtrlText(); return TRUE; } - -//set control text from config. +// set control text from config. void CTransparentBgDlg::InitCtrlText() { m_staticChannelName.SetWindowText(commonCtrlChannel); m_bnJoinChannel.SetWindowText(commonCtrlJoinChannel); + m_editChannel.SetWindowText(_T("")); + + m_staticVideo.Invalidate(); + m_staticVideoLeft.Invalidate(); + m_staticVideoRight.Invalidate(); } -int CTransparentBgDlg::JoinChannel(const char* channel) +int CTransparentBgDlg::JoinChannel(const char *channel) { VideoEncoderConfiguration config; + config.advanceOptions.encodeAlpha = true; m_rtcEngine->setVideoEncoderConfiguration(config); - std::string szChannelId = channel; ChannelMediaOptions options; options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; @@ -112,83 +120,229 @@ int CTransparentBgDlg::JoinChannel(const char* channel) options.autoSubscribeAudio = false; options.autoSubscribeVideo = true; options.publishMicrophoneTrack = false; - options.publishCameraTrack = true; - //join channel in the engine. - int ret = m_rtcEngine->joinChannel(APP_TOKEN, szChannelId.c_str(), m_uid, options); + options.publishCameraTrack = false; + options.publishCustomVideoTrack = true; + // join channel in the engine. + int ret = m_rtcEngine->joinChannel(APP_TOKEN, channel, m_uid, options); + return ret; } int CTransparentBgDlg::LeaveChannel() { - if(!m_joinChannel) - { - return 0; + if (!m_joinChannel) + { + return 0; }; + m_rtcEngine->stopPreview(); int ret = m_rtcEngine->leaveChannel(); m_joinChannel = false; m_remoteId = 0; return ret; } -//Initialize the Agora SDK +void CTransparentBgDlg::StartPlay() +{ + m_mediaPlayer = m_rtcEngine->createMediaPlayer(); + if (m_mediaPlayer) + { + m_mediaPlayer->setView((agora::media::base::view_t)m_staticVideo.GetSafeHwnd()); + m_mediaPlayer->setRenderMode(RENDER_MODE_FIT); + m_mediaPlayer->registerVideoFrameObserver(this); + m_mediaPlayer->registerPlayerSourceObserver(this); + MediaSource mediaSource; + CString videoUrl = GetExePath() + _T("\\yuvj_full_range_alpha_1280_540_left.mp4"); + std::string tmp = cs2utf8(videoUrl); + mediaSource.url = tmp.c_str(); + CString pathInfo; + int ret = m_mediaPlayer->openWithMediaSource(mediaSource); + CString strInfo; + strInfo.Format(_T("openWithMediaSource ret: %d"), ret); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + m_mediaPlayer->setLoopCount(-1); + } +} + +void CTransparentBgDlg::StopPlay() +{ + if (m_mediaPlayer) + { + m_mediaPlayer->stop(); + } +} +void CTransparentBgDlg::onFrame(const VideoFrame *frame) +{ + if (m_rtcEngine) + { + // int nSize = videoFrame.height * videoFrame.width; + // //set UV to 128 to mask color information + // memset(videoFrame.uBuffer, 128, nSize / 4); + // memset(videoFrame.vBuffer, 128, nSize / 4); + + // mediaEngine->pushVideoFrame(frame); + + // CString strInfo; + // strInfo.Format(_T("height ret: %d"), frame->height); + // m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + } +} + +void CTransparentBgDlg::onPlayerSourceStateChanged(media::base::MEDIA_PLAYER_STATE state, media::base::MEDIA_PLAYER_REASON reason) +{ + CString strState; + CString strError; + switch (state) + { + case agora::media::base::PLAYER_STATE_OPEN_COMPLETED: + strState = _T("PLAYER_STATE_OPEN_COMPLETED"); + m_mediaPlayer->play(); + break; + case agora::media::base::PLAYER_STATE_OPENING: + strState = _T("PLAYER_STATE_OPENING"); + break; + case agora::media::base::PLAYER_STATE_IDLE: + strState = _T("PLAYER_STATE_IDLE"); + break; + case agora::media::base::PLAYER_STATE_PLAYING: + strState = _T("PLAYER_STATE_PLAYING"); + break; + case agora::media::base::PLAYER_STATE_PLAYBACK_COMPLETED: + strState = _T("PLAYER_STATE_PLAYBACK_COMPLETED"); + break; + case agora::media::base::PLAYER_STATE_PLAYBACK_ALL_LOOPS_COMPLETED: + strState = _T("PLAYER_STATE_PLAYBACK_ALL_LOOPS_COMPLETED"); + break; + case agora::media::base::PLAYER_STATE_PAUSED: + strState = _T("PLAYER_STATE_PAUSED"); + break; + case agora::media::base::PLAYER_STATE_STOPPED: + strState = _T("PLAYER_STATE_STOPPED"); + break; + case agora::media::base::PLAYER_STATE_FAILED: + strState = _T("PLAYER_STATE_FAILED"); + m_mediaPlayer->stop(); + break; + default: + strState = _T("PLAYER_STATE_UNKNOWN"); + break; + } + switch (reason) + { + case agora::media::base::PLAYER_REASON_URL_NOT_FOUND: + strError = _T("PLAYER_ERROR_URL_NOT_FOUND"); + break; + case agora::media::base::PLAYER_REASON_NONE: + strError = _T("PLAYER_ERROR_NONE"); + break; + case agora::media::base::PLAYER_REASON_CODEC_NOT_SUPPORTED: + strError = _T("PLAYER_ERROR_NONE"); + break; + case agora::media::base::PLAYER_REASON_INVALID_ARGUMENTS: + strError = _T("PLAYER_ERROR_INVALID_ARGUMENTS"); + break; + case agora::media::base::PLAYER_REASON_SRC_BUFFER_UNDERFLOW: + strError = _T("PLAY_ERROR_SRC_BUFFER_UNDERFLOW"); + break; + case agora::media::base::PLAYER_REASON_INTERNAL: + strError = _T("PLAYER_ERROR_INTERNAL"); + break; + case agora::media::base::PLAYER_REASON_INVALID_STATE: + strError = _T("PLAYER_ERROR_INVALID_STATE"); + break; + case agora::media::base::PLAYER_REASON_NO_RESOURCE: + strError = _T("PLAYER_ERROR_NO_RESOURCE"); + break; + case agora::media::base::PLAYER_REASON_OBJ_NOT_INITIALIZED: + strError = _T("PLAYER_ERROR_OBJ_NOT_INITIALIZED"); + break; + case agora::media::base::PLAYER_REASON_INVALID_CONNECTION_STATE: + strError = _T("PLAYER_ERROR_INVALID_CONNECTION_STATE"); + break; + case agora::media::base::PLAYER_REASON_UNKNOWN_STREAM_TYPE: + strError = _T("PLAYER_ERROR_UNKNOWN_STREAM_TYPE"); + break; + case agora::media::base::PLAYER_REASON_VIDEO_RENDER_FAILED: + strError = _T("PLAYER_ERROR_VIDEO_RENDER_FAILED"); + break; + } + CString strInfo; + strInfo.Format(_T("sta:%s,\nerr:%s"), strState, strError); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); +} + +// Initialize the Agora SDK bool CTransparentBgDlg::InitAgora() { - //create Agora RTC engine + // create Agora RTC engine m_rtcEngine = createAgoraRtcEngine(); - if (!m_rtcEngine) { + if (!m_rtcEngine) + { m_listInfo.InsertString(m_listInfo.GetCount(), _T("createAgoraRtcEngine failed")); return false; } - //set message notify receiver window + // set message notify receiver window m_eventHandler.SetMsgReceiver(m_hWnd); RtcEngineContext context; - std::string strAppID = GET_APP_ID; - context.appId = strAppID.c_str(); + std::string strAppID = GET_APP_ID; + context.appId = strAppID.c_str(); context.eventHandler = &m_eventHandler; - //set channel profile in the engine to the CHANNEL_PROFILE_LIVE_BROADCASTING. - context.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; - //initialize the Agora RTC engine context. + // set channel profile in the engine to the CHANNEL_PROFILE_LIVE_BROADCASTING. + context.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; + // initialize the Agora RTC engine context. int ret = m_rtcEngine->initialize(context); - if (ret != 0) { + if (ret != 0) + { m_initialize = false; CString strInfo; strInfo.Format(_T("initialize failed: %d"), ret); m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return false; } - else + else { m_initialize = true; m_listInfo.InsertString(m_listInfo.GetCount(), _T("createAgoraRtcEngine success")); + + mediaEngine.queryInterface(m_rtcEngine, agora::rtc::AGORA_IID_MEDIA_ENGINE); + agora::base::AParameter apm(m_rtcEngine); + mediaEngine->setExternalVideoSource(true, true); } m_rtcEngine->enableVideo(); - m_rtcEngine->enableAudio(); + m_rtcEngine->enableAudio(); return true; } -//UnInitialize the Agora SDK +// UnInitialize the Agora SDK void CTransparentBgDlg::UnInitAgora() { - if (m_rtcEngine) { - if(m_joinChannel) - m_rtcEngine->leaveChannel(); - // m_rtcEngine->stopPreview(); + if (m_rtcEngine) + { + if (m_joinChannel) + LeaveChannel(); + // m_rtcEngine->stopPreview(); m_rtcEngine->disableVideo(); - if (m_initialize) { - m_rtcEngine->release(true); - } + if (m_mediaPlayer) + { + + m_mediaPlayer->Release(); + m_mediaPlayer = nullptr; + } + + if (m_initialize) + { + m_rtcEngine->release(true); + } m_rtcEngine = NULL; } } - LRESULT CTransparentBgDlg::OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam) { - CString strInfo; - strInfo.Format(TEXT("self join success, wParam=%u"), wParam); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - //notify parent window + CString strInfo; + strInfo.Format(TEXT("self join success, wParam=%u"), wParam); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + // notify parent window ::PostMessage(GetParent()->GetSafeHwnd(), WM_MSGID(EID_JOINCHANNEL_SUCCESS), TRUE, 0); return 0; } @@ -196,9 +350,9 @@ LRESULT CTransparentBgDlg::OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam) LRESULT CTransparentBgDlg::OnEIDError(WPARAM wParam, LPARAM lParam) { CString strInfo; - char* message = (char*)wParam; + char *message = (char *)wParam; int code = lParam; - strInfo.Format(TEXT("Error >> code=%d, message=%s"), code, utf82cs(std::string(message))); + strInfo.Format(TEXT("Error >> code=%d, message=%s"), code, message); m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); delete message; return 0; @@ -206,167 +360,184 @@ LRESULT CTransparentBgDlg::OnEIDError(WPARAM wParam, LPARAM lParam) LRESULT CTransparentBgDlg::OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam) { - m_uid = 0; CString strInfo; strInfo.Format(TEXT("leave channel success")); m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - //notify parent window + // notify parent window ::PostMessage(GetParent()->GetSafeHwnd(), WM_MSGID(EID_JOINCHANNEL_SUCCESS), FALSE, 0); return 0; } LRESULT CTransparentBgDlg::OnEIDUserJoined(WPARAM wParam, LPARAM lParam) { - if (m_remoteId!=0) + if (m_remoteId != 0) { m_listInfo.InsertString(m_listInfo.GetCount(), _T("user joined already")); return 0; } CString strInfo; - strInfo.Format(TEXT("user %u joined"), wParam); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - - VideoCanvas canvas; + strInfo.Format(TEXT("user %u joined"), wParam); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + uid_t remoteUid = (uid_t)wParam; + m_remoteId = remoteUid; + VideoCanvas canvas; canvas.enableAlphaMask = true; - canvas.uid = wParam; - canvas.view = m_staticVideoRight.GetSafeHwnd(); - canvas.renderMode = media::base::RENDER_MODE_FIT; - m_rtcEngine->setupRemoteVideo(canvas); + canvas.uid = m_remoteId; + canvas.view = m_staticVideoRight.GetSafeHwnd(); + canvas.renderMode = media::base::RENDER_MODE_FIT; + m_rtcEngine->setupRemoteVideo(canvas); return 0; } LRESULT CTransparentBgDlg::OnEIDUserOffline(WPARAM wParam, LPARAM lParam) { - m_remoteId = 0; uid_t remoteUid = (uid_t)wParam; - VideoCanvas canvas; - canvas.uid = remoteUid; - canvas.view = NULL; - m_rtcEngine->setupRemoteVideo(canvas); - CString strInfo; - strInfo.Format(TEXT("%u offline, reason:%d"), remoteUid, lParam); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + if (m_remoteId == remoteUid) + { + m_remoteId = 0; + VideoCanvas canvas; + canvas.uid = remoteUid; + canvas.view = NULL; + m_rtcEngine->setupRemoteVideo(canvas); + CString strInfo; + strInfo.Format(TEXT("%u offline, reason:%d"), remoteUid, lParam); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + } return 0; } -BOOL CTransparentBgDlg::PreTranslateMessage(MSG* pMsg) +BOOL CTransparentBgDlg::PreTranslateMessage(MSG *pMsg) { - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { - return TRUE; - } - return CDialogEx::PreTranslateMessage(pMsg); + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) + { + return TRUE; + } + return CDialogEx::PreTranslateMessage(pMsg); } +LRESULT CTransparentBgDlg::onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam) +{ + LocalAudioStats *stats = (LocalAudioStats *)wParam; + // m_videoWnds[0].SetAudioStatsInfo(stats->sentBitrate, stats->txPacketLossRate); -LRESULT CTransparentBgDlg::onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam) { - LocalAudioStats* stats = (LocalAudioStats*)wParam; - - //m_videoWnds[0].SetAudioStatsInfo(stats->sentBitrate, stats->txPacketLossRate); - - if (stats) { - delete stats; - stats = nullptr; - } - return 0; + if (stats) + { + delete stats; + stats = nullptr; + } + return 0; } -LRESULT CTransparentBgDlg::onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam) { - RemoteAudioStats* stats = (RemoteAudioStats*)wParam; - - /*for (int i = 0; i < VIDEO_COUNT; i++) - { - if (m_videoWnds[i].GetUID() == stats->uid) { - m_videoWnds[i].SetAudioStatsInfo(stats->receivedBitrate, stats->audioLossRate, stats->jitterBufferDelay); - break; - } - }*/ - - if (stats) { - delete stats; - stats = nullptr; - } - return 0; -} +LRESULT CTransparentBgDlg::onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam) +{ + RemoteAudioStats *stats = (RemoteAudioStats *)wParam; + /*for (int i = 0; i < VIDEO_COUNT; i++) + { + if (m_videoWnds[i].GetUID() == stats->uid) { + m_videoWnds[i].SetAudioStatsInfo(stats->receivedBitrate, stats->audioLossRate, stats->jitterBufferDelay); + break; + } + }*/ -LRESULT CTransparentBgDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) { - LocalVideoStats* stats = (LocalVideoStats*)wParam; + if (stats) + { + delete stats; + stats = nullptr; + } + return 0; +} - /*m_videoWnds[0].SetVideoStatsInfo(stats->encodedFrameWidth, stats->encodedFrameHeight, stats->sentFrameRate, stats->sentBitrate, stats->txPacketLossRate); +LRESULT CTransparentBgDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) +{ + LocalVideoStats *stats = (LocalVideoStats *)wParam; - if (stats) { - delete stats; - stats = nullptr; - }*/ + /*m_videoWnds[0].SetVideoStatsInfo(stats->encodedFrameWidth, stats->encodedFrameHeight, stats->sentFrameRate, stats->sentBitrate, stats->txPacketLossRate); - - return 0; -} + if (stats) { + delete stats; + stats = nullptr; + }*/ -LRESULT CTransparentBgDlg::onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam) { - RemoteVideoStats* stats = (RemoteVideoStats*)wParam; -// CString strInfo = _T("===onRemoteVideoStats==="); -// m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - return 0; + return 0; } - +LRESULT CTransparentBgDlg::onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam) +{ + RemoteVideoStats *stats = (RemoteVideoStats *)wParam; + // CString strInfo = _T("===onRemoteVideoStats==="); + // m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + return 0; +} void CTransparentBgDlg::OnBnClickedButtonJoinchannel() { CString info; - if (!m_joinChannel) { + if (!m_joinChannel) + { CString strChannelName; m_editChannel.GetWindowText(strChannelName); - if (strChannelName.IsEmpty()) { + if (strChannelName.IsEmpty()) + { MessageBox(_T("频道号不能为空")); return; } + VideoCanvas canvas; + canvas.sourceType = VIDEO_SOURCE_CUSTOM; + canvas.enableAlphaMask = true; + canvas.renderMode = media::base::RENDER_MODE_FIT; + canvas.uid = m_uid; + canvas.view = m_staticVideoLeft.GetSafeHwnd(); + m_rtcEngine->setupLocalVideo(canvas); + m_rtcEngine->startPreview(VIDEO_SOURCE_CUSTOM); + std::string szChannelName = cs2utf8(strChannelName); int ret = JoinChannel(szChannelName.c_str()); - if (ret == 0) { + if (ret == 0) + { m_joinChannel = true; m_bnJoinChannel.SetWindowText(commonCtrlLeaveChannel); - m_rtcEngine->enableVideo(); - m_rtcEngine->startPreview(); - VideoCanvas canvas; - canvas.renderMode = media::base::RENDER_MODE_FIT; - canvas.uid = m_uid; - canvas.view = m_staticVideoLeft.GetSafeHwnd(); - m_rtcEngine->setupLocalVideo(canvas); + + StartPlay(); } - else { - const char* des = getAgoraSdkErrorDescription(ret); + else + { + const char *des = getAgoraSdkErrorDescription(ret); info.Format(TEXT("join channel failed >> code=%d, des=%s"), ret, utf82cs(std::string(des))); m_listInfo.InsertString(m_listInfo.GetCount(), info); } } - else { + else + { int ret = LeaveChannel(); - if (0 == ret) { - m_bnJoinChannel.SetWindowText(commonCtrlJoinChannel); + if (0 == ret) + { + InitCtrlText(); + StopPlay(); } - else { - const char* des = getAgoraSdkErrorDescription(ret); + else + { + const char *des = getAgoraSdkErrorDescription(ret); info.Format(TEXT("leave channel failed >> code=%d, des=%s"), ret, utf82cs(std::string(des))); m_listInfo.InsertString(m_listInfo.GetCount(), info); } } - } - void CTransparentBgDlg::OnShowWindow(BOOL bShow, UINT nStatus) { CDialogEx::OnShowWindow(bShow, nStatus); - if (bShow) { - //resume - } - else - { - //pause - } + if (bShow) + { + // resume + m_listInfo.ResetContent(); + } + else + { + // pause + InitCtrlText(); + } } diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h index 8046b1cf8..4798d9fd1 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h @@ -3,91 +3,114 @@ #include #include #include "stdafx.h" +#include +#include +#include "AbstractMediaPlayerSourceObserver.h" +using namespace agora::media::base; class CTransparentBgEventHandler : public IRtcEngineEventHandler { public: - void SetMsgReceiver(HWND hWnd) { m_hMsgHanlder = hWnd; } - virtual void onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) override; - virtual void onUserJoined(uid_t uid, int elapsed) override; - virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) override; - virtual void onLeaveChannel(const RtcStats& stats) override; - virtual void onLocalAudioStats(const LocalAudioStats& stats) override{ - if (m_hMsgHanlder&& report) { - LocalAudioStats* s = new LocalAudioStats; + void SetMsgReceiver(HWND hWnd) { m_hMsgHanlder = hWnd; } + virtual void onJoinChannelSuccess(const char *channel, uid_t uid, int elapsed) override; + virtual void onUserJoined(uid_t uid, int elapsed) override; + virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) override; + virtual void onLeaveChannel(const RtcStats &stats) override; + virtual void onLocalAudioStats(const LocalAudioStats &stats) override + { + if (m_hMsgHanlder && report) + { + LocalAudioStats *s = new LocalAudioStats; *s = stats; ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_AUDIO_STATS), (WPARAM)s, 0); - } } - virtual void onRemoteAudioStats(const RemoteAudioStats& stats) { - if (m_hMsgHanlder&& report) { - RemoteAudioStats* s = new RemoteAudioStats; + virtual void onRemoteAudioStats(const RemoteAudioStats &stats) + { + if (m_hMsgHanlder && report) + { + RemoteAudioStats *s = new RemoteAudioStats; *s = stats; ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_AUDIO_STATS), (WPARAM)s, 0); - } } - virtual void onRemoteVideoStats(const RemoteVideoStats& stats) { - if (m_hMsgHanlder&& report) { - RemoteVideoStats* s = new RemoteVideoStats; + virtual void onRemoteVideoStats(const RemoteVideoStats &stats) + { + if (m_hMsgHanlder && report) + { + RemoteVideoStats *s = new RemoteVideoStats; *s = stats; ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_VIDEO_STATS), (WPARAM)s, 0); } } - virtual void onLocalVideoStats(VIDEO_SOURCE_TYPE source, const LocalVideoStats& stats) override; - virtual void onError(int err, const char* msg) { - if (m_hMsgHanlder) { - char* message = new char[1024]{0}; - memcpy(message, msg, strlen(msg)); - ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_ERROR), (WPARAM)message, err); + virtual void onLocalVideoStats(VIDEO_SOURCE_TYPE source, const LocalVideoStats &stats) override; + virtual void onError(int err, const char *msg) + { + if (m_hMsgHanlder) + { + char *message = new char[1024]{0}; + memcpy(message, msg, strlen(msg)); + ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_ERROR), (WPARAM)message, err); + } + } - } - } private: - HWND m_hMsgHanlder = nullptr; + HWND m_hMsgHanlder = nullptr; bool report = true; }; -class CTransparentBgDlg : public CDialogEx +class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver,AbstractMediaPlayerSourceObserver { DECLARE_DYNAMIC(CTransparentBgDlg) public: - CTransparentBgDlg(CWnd* pParent = nullptr); // standard constructor + CTransparentBgDlg(CWnd *pParent = nullptr); // standard constructor virtual ~CTransparentBgDlg(); - bool InitAgora(); - void UnInitAgora(); - enum { IDD = IDD_DIALOG_TRANSPARENT_BG}; + bool InitAgora(); + void UnInitAgora(); + void StartPlay(); + void StopPlay(); + virtual void onFrame(const VideoFrame *frame); + virtual void onPlayerSourceStateChanged(media::base::MEDIA_PLAYER_STATE state, media::base::MEDIA_PLAYER_REASON reason); + enum + { + IDD = IDD_DIALOG_TRANSPARENT_BG + }; + protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support DECLARE_MESSAGE_MAP() public: - afx_msg LRESULT OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnEIDError(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnEIDUserJoined(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnEIDUserOffline(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDError(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDUserJoined(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEIDUserOffline(WPARAM wParam, LPARAM lParam); afx_msg LRESULT onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam); afx_msg LRESULT onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam); afx_msg LRESULT onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam); afx_msg LRESULT onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam); private: - void InitCtrlText(); - int JoinChannel(const char* channel); + void InitCtrlText(); + int JoinChannel(const char *channel); int LeaveChannel(); - IRtcEngine* m_rtcEngine = nullptr; - CTransparentBgEventHandler m_eventHandler; - bool m_joinChannel = false; - bool m_initialize = false; + IRtcEngine *m_rtcEngine = nullptr; + agora_refptr m_mediaPlayer = nullptr; + agora::util::AutoPtr mediaEngine; + CTransparentBgEventHandler m_eventHandler; + agora::media::base::ExternalVideoFrame m_videoFrame; + bool m_joinChannel = false; + bool m_initialize = false; int m_uid = 1001; int m_remoteId = 0; + public: virtual BOOL OnInitDialog(); - virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL PreTranslateMessage(MSG *pMsg); afx_msg void OnBnClickedButtonJoinchannel(); + private: CStatic m_staticChannelName; CButton m_bnJoinChannel; @@ -96,6 +119,7 @@ class CTransparentBgDlg : public CDialogEx CStatic m_staticVideoLeft; CStatic m_staticVideoRight; CListBox m_listInfo; + public: afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); }; diff --git a/windows/APIExample/APIExample/resource.h b/windows/APIExample/APIExample/resource.h index 147f9e4b8..5cfaac205 100755 --- a/windows/APIExample/APIExample/resource.h +++ b/windows/APIExample/APIExample/resource.h @@ -426,7 +426,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 175 +#define _APS_NEXT_RESOURCE_VALUE 177 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1153 #define _APS_NEXT_SYMED_VALUE 101 From 88fd5169e53fa37d7e7b68af90f2c064f491e9ab Mon Sep 17 00:00:00 2001 From: "1138289316@qq.com" <1138289316@qq.com> Date: Thu, 12 Sep 2024 20:08:38 +0800 Subject: [PATCH 007/166] =?UTF-8?q?feat:=20windows=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BA=86=E6=9E=84=E5=BB=BA=E7=9A=84=E6=97=B6=E5=80=99=E6=8B=B7?= =?UTF-8?q?=E8=B4=9D=E8=A7=86=E9=A2=91=E6=96=87=E4=BB=B6=E5=88=B0=E7=9B=B8?= =?UTF-8?q?=E5=BA=94=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../APIExample/APIExample/APIExample.vcxproj | 4 ++- .../TransparentBg/TransparentBgDialog.cpp | 25 ++++++++++++++----- .../TransparentBg/TransparentBgDialog.h | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/windows/APIExample/APIExample/APIExample.vcxproj b/windows/APIExample/APIExample/APIExample.vcxproj index caa961adc..ca7174446 100644 --- a/windows/APIExample/APIExample/APIExample.vcxproj +++ b/windows/APIExample/APIExample/APIExample.vcxproj @@ -121,7 +121,8 @@ if exist zh-cn.ini (copy zh-cn.ini $(SolutionDir)$(Configuration)) if exist en.ini (copy en.ini $(SolutionDir)$(Configuration)) copy $(SolutionDir)APIExample\Advanced\LocalVideoTranscoding\agora.png $(SolutionDir)$(Configuration) copy $(SolutionDir)APIExample\Advanced\LocalVideoTranscoding\agora.jpg $(SolutionDir)$(Configuration) -if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Configuration)) +if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Configuration)) +if exist $(SolutionDir)APIExample\res\yuvj_full_range_alpha_1280_540_left.mp4 (copy $(SolutionDir)APIExample\res\yuvj_full_range_alpha_1280_540_left.mp4 $(SolutionDir)$(Configuration)) @@ -167,6 +168,7 @@ if exist en.ini (copy en.ini $(SolutionDir)$(Platform)\$(Configuration)) copy $(SolutionDir)APIExample\Advanced\LocalVideoTranscoding\agora.png $(SolutionDir)$(Platform)\$(Configuration) copy $(SolutionDir)APIExample\Advanced\LocalVideoTranscoding\agora.jpg $(SolutionDir)$(Platform)\$(Configuration) if exist sample.yuv (copy sample.yuv $(SolutionDir)$(Platform)$(Configuration)) +if exist $(SolutionDir)APIExample\res\yuvj_full_range_alpha_1280_540_left.mp4 (copy $(SolutionDir)APIExample\res\yuvj_full_range_alpha_1280_540_left.mp4 $(SolutionDir)$(Configuration)) diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp index 35e9a54b9..2e778f3bc 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp @@ -174,12 +174,24 @@ void CTransparentBgDlg::onFrame(const VideoFrame *frame) { if (m_rtcEngine) { - // int nSize = videoFrame.height * videoFrame.width; - // //set UV to 128 to mask color information - // memset(videoFrame.uBuffer, 128, nSize / 4); - // memset(videoFrame.vBuffer, 128, nSize / 4); - // mediaEngine->pushVideoFrame(frame); + // 创建ExternalVideoFrame对象 + agora::media::base::ExternalVideoFrame externalFrame; + externalFrame.alphaStitchMode = ALPHA_STITCH_LEFT; + externalFrame.type = agora::media::base::ExternalVideoFrame::VIDEO_BUFFER_TYPE::VIDEO_BUFFER_RAW_DATA; + externalFrame.format = agora::media::base::VIDEO_PIXEL_I420; + externalFrame.stride = frame->width; + externalFrame.height = frame->height; + externalFrame.timestamp = m_rtcEngine->getCurrentMonotonicTimeInMs(); + + int bufferSize = frame->yStride * frame->height + frame->uStride * (frame->height >> 1) + frame->vStride * (frame->height >> 1); + externalFrame.buffer = new uint8_t[bufferSize]; + memcpy(externalFrame.buffer, frame->yBuffer, frame->yStride * frame->height); + memcpy((uint8_t *)externalFrame.buffer + frame->yStride * frame->height, frame->uBuffer, frame->uStride * (frame->height >> 1)); + memcpy((uint8_t *)externalFrame.buffer + frame->yStride * frame->height + frame->uStride * (frame->height >> 1), frame->vBuffer, frame->vStride * (frame->height / 2)); + mediaEngine->pushVideoFrame(&externalFrame); + // 释放缓冲区 + delete[] externalFrame.buffer; // CString strInfo; // strInfo.Format(_T("height ret: %d"), frame->height); @@ -324,7 +336,7 @@ void CTransparentBgDlg::UnInitAgora() m_rtcEngine->disableVideo(); if (m_mediaPlayer) { - + // m_mediaPlayer->registerPlayerSourceObserver(nullptr); m_mediaPlayer->Release(); m_mediaPlayer = nullptr; } @@ -485,6 +497,7 @@ void CTransparentBgDlg::OnBnClickedButtonJoinchannel() } VideoCanvas canvas; + canvas.mirrorMode = VIDEO_MIRROR_MODE_DISABLED; canvas.sourceType = VIDEO_SOURCE_CUSTOM; canvas.enableAlphaMask = true; canvas.renderMode = media::base::RENDER_MODE_FIT; diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h index 4798d9fd1..f2641d5c3 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h @@ -99,7 +99,7 @@ class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver,Abs agora_refptr m_mediaPlayer = nullptr; agora::util::AutoPtr mediaEngine; CTransparentBgEventHandler m_eventHandler; - agora::media::base::ExternalVideoFrame m_videoFrame; + //agora::media::base::ExternalVideoFrame m_videoFrame; bool m_joinChannel = false; bool m_initialize = false; int m_uid = 1001; From 29f2fca3882ef0c27798d2c72844808d6af4b968 Mon Sep 17 00:00:00 2001 From: "1138289316@qq.com" <1138289316@qq.com> Date: Thu, 12 Sep 2024 21:25:36 +0800 Subject: [PATCH 008/166] =?UTF-8?q?feat:=20=E9=80=8F=E6=98=8E=E6=95=88?= =?UTF-8?q?=E6=9E=9C=E6=A8=A1=E5=9D=97=E4=BC=98=E5=8C=96=E4=BA=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransparentBg/TransparentBgDialog.cpp | 74 +++++++++++-------- .../TransparentBg/TransparentBgDialog.h | 34 ++++----- 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp index 2e778f3bc..7d0198360 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp @@ -90,9 +90,6 @@ END_MESSAGE_MAP() BOOL CTransparentBgDlg::OnInitDialog() { CDialogEx::OnInitDialog(); - - m_listInfo.ResetContent(); - InitCtrlText(); return TRUE; } @@ -102,7 +99,10 @@ void CTransparentBgDlg::InitCtrlText() m_staticChannelName.SetWindowText(commonCtrlChannel); m_bnJoinChannel.SetWindowText(commonCtrlJoinChannel); m_editChannel.SetWindowText(_T("")); +} +void CTransparentBgDlg::InvalidateVideo() +{ m_staticVideo.Invalidate(); m_staticVideoLeft.Invalidate(); m_staticVideoRight.Invalidate(); @@ -377,6 +377,7 @@ LRESULT CTransparentBgDlg::OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam) m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); // notify parent window ::PostMessage(GetParent()->GetSafeHwnd(), WM_MSGID(EID_JOINCHANNEL_SUCCESS), FALSE, 0); + InvalidateVideo(); return 0; } @@ -415,6 +416,7 @@ LRESULT CTransparentBgDlg::OnEIDUserOffline(WPARAM wParam, LPARAM lParam) strInfo.Format(TEXT("%u offline, reason:%d"), remoteUid, lParam); m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); } + InvalidateVideo(); return 0; } @@ -431,13 +433,13 @@ LRESULT CTransparentBgDlg::onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam) { LocalAudioStats *stats = (LocalAudioStats *)wParam; - // m_videoWnds[0].SetAudioStatsInfo(stats->sentBitrate, stats->txPacketLossRate); + CString strInfo = _T("===onLocalAudioStats==="); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - if (stats) - { - delete stats; - stats = nullptr; - } + strInfo.Format(_T("numChannels:%u"), stats->numChannels); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("sentSampleRate:%u"), stats->sentSampleRate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -445,19 +447,13 @@ LRESULT CTransparentBgDlg::onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam) { RemoteAudioStats *stats = (RemoteAudioStats *)wParam; - /*for (int i = 0; i < VIDEO_COUNT; i++) - { - if (m_videoWnds[i].GetUID() == stats->uid) { - m_videoWnds[i].SetAudioStatsInfo(stats->receivedBitrate, stats->audioLossRate, stats->jitterBufferDelay); - break; - } - }*/ + CString strInfo = _T("===onRemoteAudioStats==="); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - if (stats) - { - delete stats; - stats = nullptr; - } + strInfo.Format(_T("uid:%u"), stats->uid); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("quality:%d"), stats->quality); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -465,12 +461,18 @@ LRESULT CTransparentBgDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) { LocalVideoStats *stats = (LocalVideoStats *)wParam; - /*m_videoWnds[0].SetVideoStatsInfo(stats->encodedFrameWidth, stats->encodedFrameHeight, stats->sentFrameRate, stats->sentBitrate, stats->txPacketLossRate); + CString strInfo = _T("===onLocalVideoStats==="); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - if (stats) { - delete stats; - stats = nullptr; - }*/ + strInfo.Format(_T("uid:%u"), stats->uid); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("sentBitrate:%d"), stats->sentBitrate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + + strInfo.Format(_T("sentFrameRate:%d"), stats->sentFrameRate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("encoderOutputFrameRate:%d"), stats->encoderOutputFrameRate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -478,8 +480,20 @@ LRESULT CTransparentBgDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) LRESULT CTransparentBgDlg::onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam) { RemoteVideoStats *stats = (RemoteVideoStats *)wParam; - // CString strInfo = _T("===onRemoteVideoStats==="); - // m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + CString strInfo = _T("===onRemoteVideoStats==="); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("uid:%u"), stats->uid); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("delay:%d"), stats->delay); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + + strInfo.Format(_T("width:%d"), stats->width); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("height:%d"), stats->height); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + + strInfo.Format(_T("receivedBitrate:%d"), stats->receivedBitrate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -528,6 +542,7 @@ void CTransparentBgDlg::OnBnClickedButtonJoinchannel() if (0 == ret) { InitCtrlText(); + InvalidateVideo(); StopPlay(); } else @@ -545,12 +560,11 @@ void CTransparentBgDlg::OnShowWindow(BOOL bShow, UINT nStatus) if (bShow) { - // resume m_listInfo.ResetContent(); } else { - // pause InitCtrlText(); + InvalidateVideo(); } } diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h index f2641d5c3..759058f9b 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h @@ -59,7 +59,7 @@ class CTransparentBgEventHandler : public IRtcEngineEventHandler bool report = true; }; -class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver,AbstractMediaPlayerSourceObserver +class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver, AbstractMediaPlayerSourceObserver { DECLARE_DYNAMIC(CTransparentBgDlg) @@ -79,6 +79,8 @@ class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver,Abs protected: virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL PreTranslateMessage(MSG *pMsg); DECLARE_MESSAGE_MAP() public: afx_msg LRESULT OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam); @@ -90,26 +92,14 @@ class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver,Abs afx_msg LRESULT onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam); afx_msg LRESULT onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam); afx_msg LRESULT onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnBnClickedButtonJoinchannel(); private: void InitCtrlText(); int JoinChannel(const char *channel); int LeaveChannel(); - IRtcEngine *m_rtcEngine = nullptr; - agora_refptr m_mediaPlayer = nullptr; - agora::util::AutoPtr mediaEngine; - CTransparentBgEventHandler m_eventHandler; - //agora::media::base::ExternalVideoFrame m_videoFrame; - bool m_joinChannel = false; - bool m_initialize = false; - int m_uid = 1001; - int m_remoteId = 0; - -public: - virtual BOOL OnInitDialog(); - virtual BOOL PreTranslateMessage(MSG *pMsg); - - afx_msg void OnBnClickedButtonJoinchannel(); + void InvalidateVideo(); private: CStatic m_staticChannelName; @@ -120,6 +110,14 @@ class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver,Abs CStatic m_staticVideoRight; CListBox m_listInfo; -public: - afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + IRtcEngine *m_rtcEngine = nullptr; + agora_refptr m_mediaPlayer = nullptr; + agora::util::AutoPtr mediaEngine; + CTransparentBgEventHandler m_eventHandler; + // agora::media::base::ExternalVideoFrame m_videoFrame; + bool m_joinChannel = false; + bool m_initialize = false; + int m_uid = 1001; + int m_remoteId = 0; + }; From 99aa53b416dc5bcf1b9976bd7e13c6ff04cbb1f4 Mon Sep 17 00:00:00 2001 From: "1138289316@qq.com" <1138289316@qq.com> Date: Thu, 19 Sep 2024 11:45:37 +0800 Subject: [PATCH 009/166] =?UTF-8?q?feat:=20windows=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E9=80=8F=E6=98=8E=E5=BA=A6=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransparentBg/TransparentBgDialog.cpp | 163 +++++++++++++++--- .../TransparentBg/TransparentBgDialog.h | 21 ++- 2 files changed, 159 insertions(+), 25 deletions(-) diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp index 7d0198360..f3f7cb8d2 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.cpp @@ -86,13 +86,118 @@ ON_BN_CLICKED(IDC_BUTTON_JOINCHANNEL, &CTransparentBgDlg::OnBnClickedButtonJoinc ON_WM_SHOWWINDOW() END_MESSAGE_MAP() +BOOL CTransparentBgDlg::_IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) +{ + typedef LONG(WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW *, ULONG, ULONGLONG); + static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL; + if (RtlVerifyVersionInfoFn == NULL) + if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll")) + RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress( + ntdllModule, "RtlVerifyVersionInfo"); + if (RtlVerifyVersionInfoFn == NULL) + return FALSE; + RTL_OSVERSIONINFOEXW versionInfo = {}; + ULONGLONG conditionMask = 0; + versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + versionInfo.dwMajorVersion = major; + versionInfo.dwMinorVersion = minor; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + return (RtlVerifyVersionInfoFn(&versionInfo, + VER_MAJORVERSION | VER_MINORVERSION, + conditionMask) == 0) + ? TRUE + : FALSE; +} + +void CTransparentBgDlg::enable_alpha_composition(void *hwnd) +{ + if (!_IsWindowsVistaOrGreater()) + { + return; + } + BOOL composition; + if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition) + return; + BOOL opaque; + DWORD color; + if (_IsWindows8OrGreater() || + (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque)) + { + HRGN region = ::CreateRectRgn(0, 0, -1, -1); + DWM_BLURBEHIND bb = {}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = region; + bb.fEnable = TRUE; + ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); + ::DeleteObject(region); + } + else + { + DWM_BLURBEHIND bb = {}; + bb.dwFlags = DWM_BB_ENABLE; + ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); + } +} + // CTransparentBgDlg message handlers BOOL CTransparentBgDlg::OnInitDialog() { CDialogEx::OnInitDialog(); + CString className("TransparentWindowClass"); + WNDCLASS wndcls = {}; + HINSTANCE hInst = AfxGetInstanceHandle(); + if (!(::GetClassInfo(hInst, className, &wndcls))) + { + wndcls.style = CS_HREDRAW | CS_VREDRAW; + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.cbClsExtra = wndcls.cbWndExtra = 0; + wndcls.hInstance = hInst; + wndcls.hIcon = NULL; + wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); + wndcls.hbrBackground = NULL; + wndcls.lpszMenuName = NULL; + wndcls.lpszClassName = className; + if (AfxRegisterClass(&wndcls)) + { + hWnd = CreateWindowEx( + 0, // 扩展窗口样式 + className, // 窗口类名 + _T("透明窗口"), // 窗口标题 + WS_OVERLAPPEDWINDOW & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX & ~WS_SYSMENU, // 窗口样式 + CW_USEDEFAULT, CW_USEDEFAULT, // 窗口位置 + 800, 600, // 窗口大小 + this->GetSafeHwnd(), // 父窗口句柄 + NULL, // 菜单句柄 + AfxGetInstanceHandle(), // 应用程序实例句柄 + NULL // 窗口创建数据 + ); + if (hWnd) + { + enable_alpha_composition(hWnd); + } + } + } return TRUE; } +void CTransparentBgDlg::ShowTransparentWindow() +{ + if (hWnd) + { + ::ShowWindow(hWnd, SW_SHOW); // 显示窗口 + UpdateWindow(); // 更新窗口 + } +} +void CTransparentBgDlg::HideTransparentWindow() +{ + if (hWnd) + { + ::ShowWindow(hWnd, SW_HIDE); // 隐藏窗口 + UpdateWindow(); // 更新窗口 + } +} + // set control text from config. void CTransparentBgDlg::InitCtrlText() { @@ -346,6 +451,14 @@ void CTransparentBgDlg::UnInitAgora() m_rtcEngine->release(true); } m_rtcEngine = NULL; + + // if (hWnd) + // { + + // ::DestroyWindow(hWnd); + // hWnd = NULL; + // } + HideTransparentWindow(); } } @@ -396,9 +509,11 @@ LRESULT CTransparentBgDlg::OnEIDUserJoined(WPARAM wParam, LPARAM lParam) VideoCanvas canvas; canvas.enableAlphaMask = true; canvas.uid = m_remoteId; - canvas.view = m_staticVideoRight.GetSafeHwnd(); + // canvas.view = m_staticVideoRight.GetSafeHwnd(); + canvas.view = hWnd; canvas.renderMode = media::base::RENDER_MODE_FIT; m_rtcEngine->setupRemoteVideo(canvas); + ShowTransparentWindow(); return 0; } @@ -412,6 +527,7 @@ LRESULT CTransparentBgDlg::OnEIDUserOffline(WPARAM wParam, LPARAM lParam) canvas.uid = remoteUid; canvas.view = NULL; m_rtcEngine->setupRemoteVideo(canvas); + HideTransparentWindow(); CString strInfo; strInfo.Format(TEXT("%u offline, reason:%d"), remoteUid, lParam); m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); @@ -433,13 +549,13 @@ LRESULT CTransparentBgDlg::onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam) { LocalAudioStats *stats = (LocalAudioStats *)wParam; - CString strInfo = _T("===onLocalAudioStats==="); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + CString strInfo = _T("===onLocalAudioStats==="); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - strInfo.Format(_T("numChannels:%u"), stats->numChannels); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - strInfo.Format(_T("sentSampleRate:%u"), stats->sentSampleRate); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("numChannels:%u"), stats->numChannels); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("sentSampleRate:%u"), stats->sentSampleRate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -448,12 +564,12 @@ LRESULT CTransparentBgDlg::onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam) RemoteAudioStats *stats = (RemoteAudioStats *)wParam; CString strInfo = _T("===onRemoteAudioStats==="); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - strInfo.Format(_T("uid:%u"), stats->uid); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - strInfo.Format(_T("quality:%d"), stats->quality); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("uid:%u"), stats->uid); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("quality:%d"), stats->quality); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -462,17 +578,17 @@ LRESULT CTransparentBgDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) LocalVideoStats *stats = (LocalVideoStats *)wParam; CString strInfo = _T("===onLocalVideoStats==="); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - - strInfo.Format(_T("uid:%u"), stats->uid); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - strInfo.Format(_T("sentBitrate:%d"), stats->sentBitrate); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - - strInfo.Format(_T("sentFrameRate:%d"), stats->sentFrameRate); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); - strInfo.Format(_T("encoderOutputFrameRate:%d"), stats->encoderOutputFrameRate); - m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + + strInfo.Format(_T("uid:%u"), stats->uid); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("sentBitrate:%d"), stats->sentBitrate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + + strInfo.Format(_T("sentFrameRate:%d"), stats->sentFrameRate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); + strInfo.Format(_T("encoderOutputFrameRate:%d"), stats->encoderOutputFrameRate); + m_listInfo.InsertString(m_listInfo.GetCount(), strInfo); return 0; } @@ -539,6 +655,7 @@ void CTransparentBgDlg::OnBnClickedButtonJoinchannel() else { int ret = LeaveChannel(); + HideTransparentWindow(); if (0 == ret) { InitCtrlText(); diff --git a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h index 759058f9b..f470e59a1 100644 --- a/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h +++ b/windows/APIExample/APIExample/Advanced/TransparentBg/TransparentBgDialog.h @@ -8,6 +8,20 @@ #include "AbstractMediaPlayerSourceObserver.h" using namespace agora::media::base; +#define _IsWindowsVistaOrGreater() \ + _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), \ + 0) // _WIN32_WINNT_VISTA +#define _IsWindows8OrGreater() \ + _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), \ + 0) // _WIN32_WINNT_WIN8 +#define _IsWindows8Point1OrGreater() \ + _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), \ + 0) // _WIN32_WINNT_WINBLUE +#define _IsWindows10OrGreater() \ + _IsWindowsVersionOrGreater( \ + HIBYTE(0x0A00), LOBYTE(0x0A00), \ + 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10 + class CTransparentBgEventHandler : public IRtcEngineEventHandler { public: @@ -100,8 +114,11 @@ class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver, Ab int JoinChannel(const char *channel); int LeaveChannel(); void InvalidateVideo(); + static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD); + void enable_alpha_composition(void *hwnd); + void ShowTransparentWindow(); + void HideTransparentWindow(); -private: CStatic m_staticChannelName; CButton m_bnJoinChannel; CEdit m_editChannel; @@ -119,5 +136,5 @@ class CTransparentBgDlg : public CDialogEx, media::base::IVideoFrameObserver, Ab bool m_initialize = false; int m_uid = 1001; int m_remoteId = 0; - + HWND hWnd = NULL; }; From bd579e24047a096d055c9f7f64fd0f0c860667a2 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Mon, 23 Sep 2024 17:34:10 +0800 Subject: [PATCH 010/166] fix: disable microphone track publishing in custom audio source cases. --- .../Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift | 2 +- .../Examples/Advanced/CustomAudioSource/CustomAudioSource.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift index f6bb34b48..c10880ba8 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift @@ -95,7 +95,7 @@ class CustomPcmAudioSourceMain: BaseViewController { // the token has to match the ones used for channel join let option = AgoraRtcChannelMediaOptions() option.publishCameraTrack = false - option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = false option.publishCustomAudioTrack = GlobalSettings.shared.getUserRole() == .broadcaster option.publishCustomAudioTrackId = Int(trackId) option.clientRoleType = GlobalSettings.shared.getUserRole() diff --git a/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift b/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift index 884ad7cf5..112c45266 100644 --- a/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift +++ b/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift @@ -214,7 +214,7 @@ class CustomAudioSource: BaseViewController { isProcessing = true let option = AgoraRtcChannelMediaOptions() - option.publishMicrophoneTrack = true + option.publishMicrophoneTrack = false option.publishCustomAudioTrack = true option.publishCameraTrack = false option.publishCustomAudioTrackId = Int(trackId) From ab74cc451788d08fc1ad5f85d428f4fe0a2c69d8 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Mon, 23 Sep 2024 18:08:30 +0800 Subject: [PATCH 011/166] fix: disable microphone track publishing in custom audio source cases. --- .../Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift b/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift index 69b7d1ece..fc8151330 100644 --- a/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift +++ b/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift @@ -96,7 +96,7 @@ class CustomPcmAudioSourceMain: BaseViewController { // the token has to match the ones used for channel join let option = AgoraRtcChannelMediaOptions() option.publishCameraTrack = false - option.publishMicrophoneTrack = GlobalSettings.shared.getUserRole() == .broadcaster + option.publishMicrophoneTrack = false option.publishCustomAudioTrack = GlobalSettings.shared.getUserRole() == .broadcaster option.publishCustomAudioTrackId = Int(trackId) option.clientRoleType = GlobalSettings.shared.getUserRole() From b59257743eedf3d87b66df2a1fd447f7c5c33419 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Tue, 24 Sep 2024 12:11:25 +0800 Subject: [PATCH 012/166] fix: audio source fixed --- .../project.pbxproj | 16 +++------ .../CustomPcmAudioSource.storyboard | 35 +++++++++++++++---- .../CustomPcmAudioSource.swift | 12 +++++-- .../CustomPcmAudioSource.strings | 5 ++- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj b/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj index 322376567..d233acb6f 100644 --- a/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj +++ b/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -982,12 +982,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = JDPG69R49Z; + DEVELOPMENT_TEAM = YS397FG5PA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1038,7 +1036,6 @@ PRODUCT_BUNDLE_IDENTIFIER = io.agora.api.examples.audio; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = AgoraLab2020; SWIFT_OBJC_BRIDGING_HEADER = "APIExample-Audio/APIExample-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -1056,11 +1053,9 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = JDPG69R49Z; + DEVELOPMENT_TEAM = YS397FG5PA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1111,7 +1106,6 @@ PRODUCT_BUNDLE_IDENTIFIER = io.agora.api.examples.audio; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = AgoraLab2020; SWIFT_OBJC_BRIDGING_HEADER = "APIExample-Audio/APIExample-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/Base.lproj/CustomPcmAudioSource.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/Base.lproj/CustomPcmAudioSource.storyboard index e97fd4969..26dd2be87 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/Base.lproj/CustomPcmAudioSource.storyboard +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/Base.lproj/CustomPcmAudioSource.storyboard @@ -1,9 +1,9 @@ - + - + @@ -18,7 +18,7 @@ - + @@ -70,7 +70,7 @@ - + - + + + + + + + + + + + + + + + + + - + @@ -123,6 +145,7 @@ + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift index c10880ba8..206d9a942 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift @@ -41,12 +41,14 @@ class CustomPcmAudioSourceMain: BaseViewController { var audioViews: [UInt: VideoView] = [:] @IBOutlet weak var playAudioView: UIView! @IBOutlet weak var pushPcmSwitch: UISwitch! + @IBOutlet weak var pushMicrophoneSwitch: UISwitch! private var trackId: Int32 = 0 // indicate if current instance has joined channel var isJoined: Bool = false { didSet { pushPcmSwitch.isEnabled = isJoined + pushMicrophoneSwitch.isEnabled = pushPcmSwitch.isEnabled } } @@ -96,9 +98,6 @@ class CustomPcmAudioSourceMain: BaseViewController { let option = AgoraRtcChannelMediaOptions() option.publishCameraTrack = false option.publishMicrophoneTrack = false - option.publishCustomAudioTrack = GlobalSettings.shared.getUserRole() == .broadcaster - option.publishCustomAudioTrackId = Int(trackId) - option.clientRoleType = GlobalSettings.shared.getUserRole() NetworkManager.shared.generateToken(channelName: channelName, success: { token in let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option) if result != 0 { @@ -135,6 +134,13 @@ class CustomPcmAudioSourceMain: BaseViewController { } let mediaOption = AgoraRtcChannelMediaOptions() mediaOption.publishCustomAudioTrack = sender.isOn + mediaOption.publishCustomAudioTrackId = Int(trackId) + agoraKit.updateChannel(with: mediaOption) + } + + @IBAction func pushMicrophone(_ sender: UISwitch) { + let mediaOption = AgoraRtcChannelMediaOptions() + mediaOption.publishMicrophoneTrack = sender.isOn agoraKit.updateChannel(with: mediaOption) } } diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/zh-Hans.lproj/CustomPcmAudioSource.strings b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/zh-Hans.lproj/CustomPcmAudioSource.strings index 0f1d5b653..713d581e2 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/zh-Hans.lproj/CustomPcmAudioSource.strings +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/zh-Hans.lproj/CustomPcmAudioSource.strings @@ -6,7 +6,10 @@ "Cwr-m3-kGh.text" = "麦克风"; /* Class = "UILabel"; text = "Push PCM"; ObjectID = "Dbo-LJ-5lv"; */ -"Dbo-LJ-5lv.text" = "播放 PCM"; +"Dbo-LJ-5lv.text" = "发布本地音频"; + +/* Class = "UILabel"; text = "Push Microphone"; ObjectID = "3Sp-t2-4ZJ"; */ +"3Sp-t2-4ZJ.text" = "发布麦克风"; /* Class = "UITextField"; placeholder = "Enter channel name"; ObjectID = "SdL-FU-6ht"; */ "SdL-FU-6ht.placeholder" = "输入频道名"; From ce4fcbe40c7db20458f1efa61be630c7bd5724d1 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Tue, 24 Sep 2024 14:34:29 +0800 Subject: [PATCH 013/166] fix: build fail --- .../APIExample.xcodeproj/project.pbxproj | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj index 96f2b94d2..964b9b9a3 100644 --- a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj +++ b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj @@ -134,6 +134,14 @@ A7CA48C424553CF700507435 /* Popover.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A7CA48C224553CF600507435 /* Popover.storyboard */; }; B9C914453E92C7F49C93E1F5 /* Pods_APIExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8551A4BC255CE49B383BC575 /* Pods_APIExample.framework */; }; CBCDE23FB64E60D6A79F3723 /* Pods_Agora_ScreenShare_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09E72C5D1AABD812866E41A6 /* Pods_Agora_ScreenShare_Extension.framework */; }; + DD4E2A9E2CA2821D00EDE110 /* CustomViewPIPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A952CA2821D00EDE110 /* CustomViewPIPService.swift */; }; + DD4E2A9F2CA2821D00EDE110 /* CustomViewPIPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A962CA2821D00EDE110 /* CustomViewPIPViewController.swift */; }; + DD4E2AA02CA2821D00EDE110 /* PIPBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A982CA2821D00EDE110 /* PIPBaseViewController.swift */; }; + DD4E2AA12CA2821D00EDE110 /* ChannelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A992CA2821D00EDE110 /* ChannelViewController.swift */; }; + DD4E2AA22CA2821D00EDE110 /* PixelBufferPIPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A9A2CA2821D00EDE110 /* PixelBufferPIPService.swift */; }; + DD4E2AA32CA2821D00EDE110 /* PixelBufferPIPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A9B2CA2821D00EDE110 /* PixelBufferPIPViewController.swift */; }; + DD4E2AA42CA2821D00EDE110 /* PixelBufferRenderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4E2A9C2CA2821D00EDE110 /* PixelBufferRenderView.swift */; }; + DD4E2AA62CA282CF00EDE110 /* PictureInPicture.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DD4E2AA52CA282CF00EDE110 /* PictureInPicture.storyboard */; }; DDFD50262C205BF20050B344 /* TransparentRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFD50252C205BF20050B344 /* TransparentRender.swift */; }; DDFD50282C205CF40050B344 /* TransparentRender.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DDFD50272C205CF40050B344 /* TransparentRender.storyboard */; }; DDFD502A2C2065D00050B344 /* yuv_limit_range_alpha_1280_540_right.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = DDFD50292C2065D00050B344 /* yuv_limit_range_alpha_1280_540_right.mp4 */; }; @@ -152,9 +160,7 @@ E726C0042A96FD3A006870E2 /* AudioWaveform.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E726C0002A96FD3A006870E2 /* AudioWaveform.storyboard */; }; E726C0052A96FD3A006870E2 /* AudioWaveform.swift in Sources */ = {isa = PBXBuildFile; fileRef = E726C0022A96FD3A006870E2 /* AudioWaveform.swift */; }; E726C0082A96FF15006870E2 /* ZSNBoxingView.m in Sources */ = {isa = PBXBuildFile; fileRef = E726C0062A96FF15006870E2 /* ZSNBoxingView.m */; }; - E728B84728B5FFCB00674A4A /* PictureInPicture.strings in Resources */ = {isa = PBXBuildFile; fileRef = E728B84228B5FFCB00674A4A /* PictureInPicture.strings */; }; E728B84828B5FFCB00674A4A /* PictureInPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = E728B84428B5FFCB00674A4A /* PictureInPicture.swift */; }; - E728B84928B5FFCB00674A4A /* PictureInPicture.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E728B84528B5FFCB00674A4A /* PictureInPicture.storyboard */; }; E728B84C28B6015800674A4A /* AgoraPictureInPictureController.m in Sources */ = {isa = PBXBuildFile; fileRef = E728B84B28B6015800674A4A /* AgoraPictureInPictureController.m */; }; E728B84F28B601A300674A4A /* AgoraSampleBufferRender.m in Sources */ = {isa = PBXBuildFile; fileRef = E728B84E28B601A300674A4A /* AgoraSampleBufferRender.m */; }; E728B85128B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib in Resources */ = {isa = PBXBuildFile; fileRef = E728B85028B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib */; }; @@ -449,6 +455,14 @@ A7CA48C324553CF600507435 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Popover.storyboard; sourceTree = ""; }; BC25C1A6D9E6B8827D095985 /* Pods_SimpleFilter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SimpleFilter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CC6D08A23527C200339E4FD6 /* Pods-SimpleAudioFilter.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleAudioFilter.release.xcconfig"; path = "Target Support Files/Pods-SimpleAudioFilter/Pods-SimpleAudioFilter.release.xcconfig"; sourceTree = ""; }; + DD4E2A952CA2821D00EDE110 /* CustomViewPIPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewPIPService.swift; sourceTree = ""; }; + DD4E2A962CA2821D00EDE110 /* CustomViewPIPViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewPIPViewController.swift; sourceTree = ""; }; + DD4E2A982CA2821D00EDE110 /* PIPBaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PIPBaseViewController.swift; sourceTree = ""; }; + DD4E2A992CA2821D00EDE110 /* ChannelViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelViewController.swift; sourceTree = ""; }; + DD4E2A9A2CA2821D00EDE110 /* PixelBufferPIPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferPIPService.swift; sourceTree = ""; }; + DD4E2A9B2CA2821D00EDE110 /* PixelBufferPIPViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferPIPViewController.swift; sourceTree = ""; }; + DD4E2A9C2CA2821D00EDE110 /* PixelBufferRenderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferRenderView.swift; sourceTree = ""; }; + DD4E2AA52CA282CF00EDE110 /* PictureInPicture.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = PictureInPicture.storyboard; sourceTree = ""; }; DDFD50252C205BF20050B344 /* TransparentRender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransparentRender.swift; sourceTree = ""; }; DDFD50272C205CF40050B344 /* TransparentRender.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TransparentRender.storyboard; sourceTree = ""; }; DDFD50292C2065D00050B344 /* yuv_limit_range_alpha_1280_540_right.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = yuv_limit_range_alpha_1280_540_right.mp4; sourceTree = ""; }; @@ -468,9 +482,7 @@ E726C0022A96FD3A006870E2 /* AudioWaveform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioWaveform.swift; sourceTree = ""; }; E726C0062A96FF15006870E2 /* ZSNBoxingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZSNBoxingView.m; sourceTree = ""; }; E726C0072A96FF15006870E2 /* ZSNBoxingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZSNBoxingView.h; sourceTree = ""; }; - E728B84328B5FFCB00674A4A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/PictureInPicture.strings"; sourceTree = ""; }; E728B84428B5FFCB00674A4A /* PictureInPicture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PictureInPicture.swift; sourceTree = ""; }; - E728B84628B5FFCB00674A4A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/PictureInPicture.storyboard; sourceTree = ""; }; E728B84A28B6015800674A4A /* AgoraPictureInPictureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AgoraPictureInPictureController.h; sourceTree = ""; }; E728B84B28B6015800674A4A /* AgoraPictureInPictureController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AgoraPictureInPictureController.m; sourceTree = ""; }; E728B84D28B601A300674A4A /* AgoraSampleBufferRender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AgoraSampleBufferRender.h; sourceTree = ""; }; @@ -1163,6 +1175,25 @@ name = "Supporting Files"; sourceTree = ""; }; + DD4E2A972CA2821D00EDE110 /* CustomViewPIPViewController */ = { + isa = PBXGroup; + children = ( + DD4E2A952CA2821D00EDE110 /* CustomViewPIPService.swift */, + DD4E2A962CA2821D00EDE110 /* CustomViewPIPViewController.swift */, + ); + path = CustomViewPIPViewController; + sourceTree = ""; + }; + DD4E2A9D2CA2821D00EDE110 /* PixelBufferPIPViewController */ = { + isa = PBXGroup; + children = ( + DD4E2A9A2CA2821D00EDE110 /* PixelBufferPIPService.swift */, + DD4E2A9B2CA2821D00EDE110 /* PixelBufferPIPViewController.swift */, + DD4E2A9C2CA2821D00EDE110 /* PixelBufferRenderView.swift */, + ); + path = PixelBufferPIPViewController; + sourceTree = ""; + }; DDFD50242C205BDF0050B344 /* TransparentRender */ = { isa = PBXGroup; children = ( @@ -1222,9 +1253,12 @@ E728B84128B5FFCB00674A4A /* PictureInPicture */ = { isa = PBXGroup; children = ( - E728B84228B5FFCB00674A4A /* PictureInPicture.strings */, + DD4E2A992CA2821D00EDE110 /* ChannelViewController.swift */, + DD4E2A972CA2821D00EDE110 /* CustomViewPIPViewController */, + DD4E2A982CA2821D00EDE110 /* PIPBaseViewController.swift */, + DD4E2A9D2CA2821D00EDE110 /* PixelBufferPIPViewController */, E728B84428B5FFCB00674A4A /* PictureInPicture.swift */, - E728B84528B5FFCB00674A4A /* PictureInPicture.storyboard */, + DD4E2AA52CA282CF00EDE110 /* PictureInPicture.storyboard */, ); path = PictureInPicture; sourceTree = ""; @@ -1642,9 +1676,9 @@ E726BFFC2A949F70006870E2 /* AudioRouterPlayer.storyboard in Resources */, 576EA54825AC3523000B3D79 /* CustomPcmAudioSource.storyboard in Resources */, E728B85828B86B0700674A4A /* CustomVideoSourcePushMulti.strings in Resources */, + DD4E2AA62CA282CF00EDE110 /* PictureInPicture.storyboard in Resources */, 6709B23C2806BB4A000BCC58 /* RawAudioData.storyboard in Resources */, 033A9F7F252D8B5900BC26E1 /* AudioMixing.storyboard in Resources */, - E728B84728B5FFCB00674A4A /* PictureInPicture.strings in Resources */, E7A49CB829011E7500F06DD4 /* MutliCamera.strings in Resources */, E7A49CFA29029E0000F06DD4 /* ThirdBeautify.storyboard in Resources */, E7A49D0929067F8300F06DD4 /* SenseBeautify.strings in Resources */, @@ -1654,7 +1688,6 @@ 0339D6D224E91B80008739CD /* QuickSwitchChannelVCItem.xib in Resources */, E7163F8A29651D8900EBBD55 /* AR.scnassets in Resources */, E7AD0DE129C85FFB00C9A4B0 /* sample.mov in Resources */, - E728B84928B5FFCB00674A4A /* PictureInPicture.storyboard in Resources */, 03BEED0D251CAB9C005E78F4 /* audioeffect.mp3 in Resources */, A7CA48C424553CF700507435 /* Popover.storyboard in Resources */, E7A49D42290907E200F06DD4 /* BytedEffect.storyboard in Resources */, @@ -1863,6 +1896,7 @@ E7A49D4B29090FA000F06DD4 /* BERenderHelper.m in Sources */, E7A49D172907DD2600F06DD4 /* EffectsLicense.m in Sources */, E728B84F28B601A300674A4A /* AgoraSampleBufferRender.m in Sources */, + DD4E2AA02CA2821D00EDE110 /* PIPBaseViewController.swift in Sources */, 8B333DA9267B4BC3002A3785 /* SettingsCells.swift in Sources */, E7A49D4829090F8000F06DD4 /* BEFrameProcessor.mm in Sources */, 033A9EFC252D61E200BC26E1 /* CustomVideoRender.swift in Sources */, @@ -1879,12 +1913,14 @@ E7A49D342907E74A00F06DD4 /* BundleUtil.m in Sources */, 036C42B524D2A3C600A59000 /* AgoraMetalRender.swift in Sources */, E72055EA28F943520030E6D1 /* Util.swift in Sources */, + DD4E2AA22CA2821D00EDE110 /* PixelBufferPIPService.swift in Sources */, E74788AE29C7FB6900CD7415 /* JoinChannelVideoRecorder.swift in Sources */, E7A49D41290907E200F06DD4 /* BytedEffectVC.m in Sources */, E7A49D142907DC2800F06DD4 /* EffectsProcess.m in Sources */, 03DF1D9324CFC29700DF7151 /* ExternalAudio.mm in Sources */, 036CBA4625198F1A00D74FAD /* AgoraCustomEncryption.mm in Sources */, E7899BDE2861673600851463 /* CreateDataStream.swift in Sources */, + DD4E2A9E2CA2821D00EDE110 /* CustomViewPIPService.swift in Sources */, 03B12DA8251125A500E55818 /* VideoView.swift in Sources */, E7A49D282907DDFF00F06DD4 /* EffectsDetector.m in Sources */, 576EA54225AC3310000B3D79 /* CustomPcmAudioSource.swift in Sources */, @@ -1895,6 +1931,7 @@ E7A49D572909101D00F06DD4 /* BEImageUtils.m in Sources */, 8BC751D7273E502700552265 /* LiveStreaming.swift in Sources */, E721600F28D3314B006431BD /* AlertManager.swift in Sources */, + DD4E2AA32CA2821D00EDE110 /* PixelBufferPIPViewController.swift in Sources */, E7A49CFF29029E0000F06DD4 /* FUManager.m in Sources */, 0339D6D424E91BAA008739CD /* QuickSwitchChannelVCItem.swift in Sources */, E7163F822964149800EBBD55 /* ARKit.swift in Sources */, @@ -1941,10 +1978,13 @@ 03BCEC762449EB5000ED7177 /* LogViewController.swift in Sources */, E7A49CBA29011E7500F06DD4 /* MutliCamera.swift in Sources */, 0339D6D624E91CEB008739CD /* QuickSwitchChannel.swift in Sources */, + DD4E2AA12CA2821D00EDE110 /* ChannelViewController.swift in Sources */, E74877CA28A2611C00CA2F58 /* ToastView.swift in Sources */, A7847F942458089E00469187 /* AgoraExtension.swift in Sources */, + DD4E2A9F2CA2821D00EDE110 /* CustomViewPIPViewController.swift in Sources */, E74877BA28A23C1400CA2F58 /* JSONObject.swift in Sources */, 03414B5325546C7200AB114D /* AgoraYUVImageSourcePush.m in Sources */, + DD4E2AA42CA2821D00EDE110 /* PixelBufferRenderView.swift in Sources */, 03BCEC50244938C500ED7177 /* BaseViewController.swift in Sources */, 67CB2F0C27EB318200CB19D2 /* SpatialAudio.swift in Sources */, ); @@ -2334,22 +2374,6 @@ name = AudioWaveform.storyboard; sourceTree = ""; }; - E728B84228B5FFCB00674A4A /* PictureInPicture.strings */ = { - isa = PBXVariantGroup; - children = ( - E728B84328B5FFCB00674A4A /* zh-Hans */, - ); - name = PictureInPicture.strings; - sourceTree = ""; - }; - E728B84528B5FFCB00674A4A /* PictureInPicture.storyboard */ = { - isa = PBXVariantGroup; - children = ( - E728B84628B5FFCB00674A4A /* Base */, - ); - name = PictureInPicture.storyboard; - sourceTree = ""; - }; E728B85328B86B0700674A4A /* CustomVideoSourcePushMulti.strings */ = { isa = PBXVariantGroup; children = ( From 0af470766e357ab5d52f6859582e906ad6fd4cc4 Mon Sep 17 00:00:00 2001 From: qinhui <> Date: Tue, 24 Sep 2024 14:47:25 +0800 Subject: [PATCH 014/166] fix build issues --- .../APIExample.xcodeproj/project.pbxproj | 100 +++++++++++------- .../PictureInPicture/PictureInPicture.strings | 12 +++ 2 files changed, 76 insertions(+), 36 deletions(-) create mode 100644 iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.strings diff --git a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj index 96f2b94d2..2fc6d2da7 100644 --- a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj +++ b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj @@ -152,9 +152,7 @@ E726C0042A96FD3A006870E2 /* AudioWaveform.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E726C0002A96FD3A006870E2 /* AudioWaveform.storyboard */; }; E726C0052A96FD3A006870E2 /* AudioWaveform.swift in Sources */ = {isa = PBXBuildFile; fileRef = E726C0022A96FD3A006870E2 /* AudioWaveform.swift */; }; E726C0082A96FF15006870E2 /* ZSNBoxingView.m in Sources */ = {isa = PBXBuildFile; fileRef = E726C0062A96FF15006870E2 /* ZSNBoxingView.m */; }; - E728B84728B5FFCB00674A4A /* PictureInPicture.strings in Resources */ = {isa = PBXBuildFile; fileRef = E728B84228B5FFCB00674A4A /* PictureInPicture.strings */; }; E728B84828B5FFCB00674A4A /* PictureInPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = E728B84428B5FFCB00674A4A /* PictureInPicture.swift */; }; - E728B84928B5FFCB00674A4A /* PictureInPicture.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E728B84528B5FFCB00674A4A /* PictureInPicture.storyboard */; }; E728B84C28B6015800674A4A /* AgoraPictureInPictureController.m in Sources */ = {isa = PBXBuildFile; fileRef = E728B84B28B6015800674A4A /* AgoraPictureInPictureController.m */; }; E728B84F28B601A300674A4A /* AgoraSampleBufferRender.m in Sources */ = {isa = PBXBuildFile; fileRef = E728B84E28B601A300674A4A /* AgoraSampleBufferRender.m */; }; E728B85128B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib in Resources */ = {isa = PBXBuildFile; fileRef = E728B85028B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib */; }; @@ -226,6 +224,15 @@ E7A49D6B2909115200F06DD4 /* BEEffectResourceHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A49D6A2909115100F06DD4 /* BEEffectResourceHelper.m */; }; E7AD0DE129C85FFB00C9A4B0 /* sample.mov in Resources */ = {isa = PBXBuildFile; fileRef = E7AD0DE029C85FFB00C9A4B0 /* sample.mov */; }; E7AD0DE329C95EB500C9A4B0 /* PickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7AD0DE229C95EB500C9A4B0 /* PickerView.swift */; }; + F728B9D72CA295D7007813BB /* PictureInPicture.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F728B9CD2CA295D7007813BB /* PictureInPicture.storyboard */; }; + F728B9D82CA295D7007813BB /* ChannelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9CE2CA295D7007813BB /* ChannelViewController.swift */; }; + F728B9D92CA295D7007813BB /* CustomViewPIPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9CF2CA295D7007813BB /* CustomViewPIPService.swift */; }; + F728B9DA2CA295D7007813BB /* CustomViewPIPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9D02CA295D7007813BB /* CustomViewPIPViewController.swift */; }; + F728B9DB2CA295D7007813BB /* PIPBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9D22CA295D7007813BB /* PIPBaseViewController.swift */; }; + F728B9DC2CA295D7007813BB /* PixelBufferPIPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9D32CA295D7007813BB /* PixelBufferPIPService.swift */; }; + F728B9DD2CA295D7007813BB /* PixelBufferPIPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9D42CA295D7007813BB /* PixelBufferPIPViewController.swift */; }; + F728B9DE2CA295D7007813BB /* PixelBufferRenderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F728B9D52CA295D7007813BB /* PixelBufferRenderView.swift */; }; + F728B9E02CA29625007813BB /* PictureInPicture.strings in Resources */ = {isa = PBXBuildFile; fileRef = F728B9DF2CA29625007813BB /* PictureInPicture.strings */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -468,9 +475,7 @@ E726C0022A96FD3A006870E2 /* AudioWaveform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioWaveform.swift; sourceTree = ""; }; E726C0062A96FF15006870E2 /* ZSNBoxingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZSNBoxingView.m; sourceTree = ""; }; E726C0072A96FF15006870E2 /* ZSNBoxingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZSNBoxingView.h; sourceTree = ""; }; - E728B84328B5FFCB00674A4A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/PictureInPicture.strings"; sourceTree = ""; }; E728B84428B5FFCB00674A4A /* PictureInPicture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PictureInPicture.swift; sourceTree = ""; }; - E728B84628B5FFCB00674A4A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/PictureInPicture.storyboard; sourceTree = ""; }; E728B84A28B6015800674A4A /* AgoraPictureInPictureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AgoraPictureInPictureController.h; sourceTree = ""; }; E728B84B28B6015800674A4A /* AgoraPictureInPictureController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AgoraPictureInPictureController.m; sourceTree = ""; }; E728B84D28B601A300674A4A /* AgoraSampleBufferRender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AgoraSampleBufferRender.h; sourceTree = ""; }; @@ -582,6 +587,15 @@ E7AD0DE229C95EB500C9A4B0 /* PickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickerView.swift; sourceTree = ""; }; EAD308B056B63304DA681699 /* Pods-Agora-ScreenShare-Extension(Socket).release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Agora-ScreenShare-Extension(Socket).release.xcconfig"; path = "Target Support Files/Pods-Agora-ScreenShare-Extension(Socket)/Pods-Agora-ScreenShare-Extension(Socket).release.xcconfig"; sourceTree = ""; }; EB8CDD3F04870C6A31287732 /* Pods_audioFilter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_audioFilter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F728B9CD2CA295D7007813BB /* PictureInPicture.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = PictureInPicture.storyboard; sourceTree = ""; }; + F728B9CE2CA295D7007813BB /* ChannelViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelViewController.swift; sourceTree = ""; }; + F728B9CF2CA295D7007813BB /* CustomViewPIPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewPIPService.swift; sourceTree = ""; }; + F728B9D02CA295D7007813BB /* CustomViewPIPViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewPIPViewController.swift; sourceTree = ""; }; + F728B9D22CA295D7007813BB /* PIPBaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PIPBaseViewController.swift; sourceTree = ""; }; + F728B9D32CA295D7007813BB /* PixelBufferPIPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferPIPService.swift; sourceTree = ""; }; + F728B9D42CA295D7007813BB /* PixelBufferPIPViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferPIPViewController.swift; sourceTree = ""; }; + F728B9D52CA295D7007813BB /* PixelBufferRenderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferRenderView.swift; sourceTree = ""; }; + F728B9DF2CA29625007813BB /* PictureInPicture.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = PictureInPicture.strings; sourceTree = ""; }; FAAC2AEE355D103B9E8527B5 /* Pods-Agora-ScreenShare-Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Agora-ScreenShare-Extension.debug.xcconfig"; path = "Target Support Files/Pods-Agora-ScreenShare-Extension/Pods-Agora-ScreenShare-Extension.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1222,9 +1236,13 @@ E728B84128B5FFCB00674A4A /* PictureInPicture */ = { isa = PBXGroup; children = ( - E728B84228B5FFCB00674A4A /* PictureInPicture.strings */, + F728B9CE2CA295D7007813BB /* ChannelViewController.swift */, + F728B9D12CA295D7007813BB /* CustomViewPIPViewController */, + F728B9CD2CA295D7007813BB /* PictureInPicture.storyboard */, + F728B9D22CA295D7007813BB /* PIPBaseViewController.swift */, + F728B9D62CA295D7007813BB /* PixelBufferPIPViewController */, E728B84428B5FFCB00674A4A /* PictureInPicture.swift */, - E728B84528B5FFCB00674A4A /* PictureInPicture.storyboard */, + F728B9DF2CA29625007813BB /* PictureInPicture.strings */, ); path = PictureInPicture; sourceTree = ""; @@ -1467,6 +1485,25 @@ path = Manager; sourceTree = ""; }; + F728B9D12CA295D7007813BB /* CustomViewPIPViewController */ = { + isa = PBXGroup; + children = ( + F728B9CF2CA295D7007813BB /* CustomViewPIPService.swift */, + F728B9D02CA295D7007813BB /* CustomViewPIPViewController.swift */, + ); + path = CustomViewPIPViewController; + sourceTree = ""; + }; + F728B9D62CA295D7007813BB /* PixelBufferPIPViewController */ = { + isa = PBXGroup; + children = ( + F728B9D32CA295D7007813BB /* PixelBufferPIPService.swift */, + F728B9D42CA295D7007813BB /* PixelBufferPIPViewController.swift */, + F728B9D52CA295D7007813BB /* PixelBufferRenderView.swift */, + ); + path = PixelBufferPIPViewController; + sourceTree = ""; + }; FD17F473C6A05604A44BDDDE /* Pods */ = { isa = PBXGroup; children = ( @@ -1638,13 +1675,13 @@ 033A9F3F252D89BC00BC26E1 /* RTMPStreaming.storyboard in Resources */, 033A9F2A252D737900BC26E1 /* Localizable.strings in Resources */, E726C0032A96FD3A006870E2 /* AudioWaveform.strings in Resources */, + F728B9E02CA29625007813BB /* PictureInPicture.strings in Resources */, 8BE7ABC2279E065000DFBCEF /* FusionCDN.strings in Resources */, E726BFFC2A949F70006870E2 /* AudioRouterPlayer.storyboard in Resources */, 576EA54825AC3523000B3D79 /* CustomPcmAudioSource.storyboard in Resources */, E728B85828B86B0700674A4A /* CustomVideoSourcePushMulti.strings in Resources */, 6709B23C2806BB4A000BCC58 /* RawAudioData.storyboard in Resources */, 033A9F7F252D8B5900BC26E1 /* AudioMixing.storyboard in Resources */, - E728B84728B5FFCB00674A4A /* PictureInPicture.strings in Resources */, E7A49CB829011E7500F06DD4 /* MutliCamera.strings in Resources */, E7A49CFA29029E0000F06DD4 /* ThirdBeautify.storyboard in Resources */, E7A49D0929067F8300F06DD4 /* SenseBeautify.strings in Resources */, @@ -1654,7 +1691,6 @@ 0339D6D224E91B80008739CD /* QuickSwitchChannelVCItem.xib in Resources */, E7163F8A29651D8900EBBD55 /* AR.scnassets in Resources */, E7AD0DE129C85FFB00C9A4B0 /* sample.mov in Resources */, - E728B84928B5FFCB00674A4A /* PictureInPicture.storyboard in Resources */, 03BEED0D251CAB9C005E78F4 /* audioeffect.mp3 in Resources */, A7CA48C424553CF700507435 /* Popover.storyboard in Resources */, E7A49D42290907E200F06DD4 /* BytedEffect.storyboard in Resources */, @@ -1703,6 +1739,7 @@ E728B85128B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib in Resources */, E7A49D362907EB6000F06DD4 /* SENSEME.lic in Resources */, 03D13BD72448758900B599B3 /* Main.storyboard in Resources */, + F728B9D72CA295D7007813BB /* PictureInPicture.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1841,6 +1878,7 @@ E7A49D232907DD9A00F06DD4 /* EffectsCommonObject.m in Sources */, E7A49D652909111400F06DD4 /* BEHttpRequestProvider.mm in Sources */, E7A49CFB29029E0000F06DD4 /* ThirdBeautify.swift in Sources */, + F728B9D92CA295D7007813BB /* CustomViewPIPService.swift in Sources */, 036CBA3F2519186300D74FAD /* StreamEncryption.swift in Sources */, E7A49D5129090FCC00F06DD4 /* BEEffectManager.mm in Sources */, E76347D32AAEF4AF005D130F /* BeautyAPI.m in Sources */, @@ -1874,10 +1912,12 @@ 0339BE64251DCA3B007D4FDD /* GlobalSettings.swift in Sources */, E728B85A28B86B0700674A4A /* CustomVideoSourcePushMulti.swift in Sources */, E728B84C28B6015800674A4A /* AgoraPictureInPictureController.m in Sources */, + F728B9D82CA295D7007813BB /* ChannelViewController.swift in Sources */, 8407E0942472320800AC5DE8 /* (null) in Sources */, 8B5E5B50274CB68E0040E97D /* RhythmPlayer.swift in Sources */, E7A49D342907E74A00F06DD4 /* BundleUtil.m in Sources */, 036C42B524D2A3C600A59000 /* AgoraMetalRender.swift in Sources */, + F728B9DC2CA295D7007813BB /* PixelBufferPIPService.swift in Sources */, E72055EA28F943520030E6D1 /* Util.swift in Sources */, E74788AE29C7FB6900CD7415 /* JoinChannelVideoRecorder.swift in Sources */, E7A49D41290907E200F06DD4 /* BytedEffectVC.m in Sources */, @@ -1889,11 +1929,13 @@ E7A49D282907DDFF00F06DD4 /* EffectsDetector.m in Sources */, 576EA54225AC3310000B3D79 /* CustomPcmAudioSource.swift in Sources */, E7A49D0B29067F8300F06DD4 /* SenseBeautifyVC.m in Sources */, + F728B9DB2CA295D7007813BB /* PIPBaseViewController.swift in Sources */, E7A49D202907DD8F00F06DD4 /* EffectsAttribute.m in Sources */, DDFD50262C205BF20050B344 /* TransparentRender.swift in Sources */, E7A49D6B2909115200F06DD4 /* BEEffectResourceHelper.m in Sources */, E7A49D572909101D00F06DD4 /* BEImageUtils.m in Sources */, 8BC751D7273E502700552265 /* LiveStreaming.swift in Sources */, + F728B9DD2CA295D7007813BB /* PixelBufferPIPViewController.swift in Sources */, E721600F28D3314B006431BD /* AlertManager.swift in Sources */, E7A49CFF29029E0000F06DD4 /* FUManager.m in Sources */, 0339D6D424E91BAA008739CD /* QuickSwitchChannelVCItem.swift in Sources */, @@ -1938,6 +1980,7 @@ E7A49CFE29029E0000F06DD4 /* FUBeautifyVC.m in Sources */, E77902672A484A8A008791AD /* KFMP4Demuxer.m in Sources */, 0385767E2521E5A0003C369A /* MediaChannelRelay.swift in Sources */, + F728B9DA2CA295D7007813BB /* CustomViewPIPViewController.swift in Sources */, 03BCEC762449EB5000ED7177 /* LogViewController.swift in Sources */, E7A49CBA29011E7500F06DD4 /* MutliCamera.swift in Sources */, 0339D6D624E91CEB008739CD /* QuickSwitchChannel.swift in Sources */, @@ -1945,6 +1988,7 @@ A7847F942458089E00469187 /* AgoraExtension.swift in Sources */, E74877BA28A23C1400CA2F58 /* JSONObject.swift in Sources */, 03414B5325546C7200AB114D /* AgoraYUVImageSourcePush.m in Sources */, + F728B9DE2CA295D7007813BB /* PixelBufferRenderView.swift in Sources */, 03BCEC50244938C500ED7177 /* BaseViewController.swift in Sources */, 67CB2F0C27EB318200CB19D2 /* SpatialAudio.swift in Sources */, ); @@ -2334,22 +2378,6 @@ name = AudioWaveform.storyboard; sourceTree = ""; }; - E728B84228B5FFCB00674A4A /* PictureInPicture.strings */ = { - isa = PBXVariantGroup; - children = ( - E728B84328B5FFCB00674A4A /* zh-Hans */, - ); - name = PictureInPicture.strings; - sourceTree = ""; - }; - E728B84528B5FFCB00674A4A /* PictureInPicture.storyboard */ = { - isa = PBXVariantGroup; - children = ( - E728B84628B5FFCB00674A4A /* Base */, - ); - name = PictureInPicture.storyboard; - sourceTree = ""; - }; E728B85328B86B0700674A4A /* CustomVideoSourcePushMulti.strings */ = { isa = PBXVariantGroup; children = ( @@ -2514,8 +2542,8 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = YS397FG5PA; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "Agora-ScreenShare-Extension/Info.plist"; @@ -2548,8 +2576,8 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = YS397FG5PA; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "Agora-ScreenShare-Extension/Info.plist"; @@ -2702,10 +2730,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = YS397FG5PA; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = APIExample/Info.plist; @@ -2774,9 +2802,9 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = YS397FG5PA; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = APIExample/Info.plist; @@ -2841,11 +2869,11 @@ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = YS397FG5PA; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -2878,11 +2906,11 @@ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = YS397FG5PA; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; diff --git a/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.strings b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.strings new file mode 100644 index 000000000..c50d8f1d5 --- /dev/null +++ b/iOS/APIExample/APIExample/Examples/Advanced/PictureInPicture/PictureInPicture.strings @@ -0,0 +1,12 @@ + +/* Class = "UINavigationItem"; title = "Join Channel"; ObjectID = "AmK-zc-ByT"; */ +"AmK-zc-ByT.title" = "加入频道"; + +/* Class = "UITextField"; placeholder = "Enter channel name"; ObjectID = "GWc-L5-fZV"; */ +"GWc-L5-fZV.placeholder" = "输入频道名"; + +/* Class = "UIViewController"; title = "Join Channel Video"; ObjectID = "cAG-6V-STC"; */ +"cAG-6V-STC.title" = "画中画"; + +/* Class = "UIButton"; normalTitle = "Join"; ObjectID = "kbN-ZR-nNn"; */ +"kbN-ZR-nNn.normalTitle" = "加入频道"; From ae09bc298b24c0f1b06998ab283e579bdf9574e6 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 25 Sep 2024 20:57:17 +0800 Subject: [PATCH 015/166] fix: audio render fixed --- .../CustomAudioRender/CustomAudioRender.swift | 97 ++++++++++++++++--- .../CustomPcmAudioSource.swift | 2 +- 2 files changed, 84 insertions(+), 15 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift index 3f7b4f5d8..0ff6e600a 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift @@ -10,6 +10,58 @@ import Foundation import AgoraRtcKit import AGEVideoLayout +private let bitsPerSample: UInt = 16 +private let samples: UInt = 441 * 10 +private let sampleRate: UInt = 44100 +private let channels: UInt = 2 + +class PCMPlayer { + private var audioEngine: AVAudioEngine + private var playerNode: AVAudioPlayerNode + private var sampleRate: Double + private var channels: AVAudioChannelCount + + init(sampleRate: Double, channels: AVAudioChannelCount) { + self.sampleRate = sampleRate + self.channels = channels + + audioEngine = AVAudioEngine() + playerNode = AVAudioPlayerNode() + + audioEngine.attach(playerNode) + + let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels) + audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: format) + + do { + try audioEngine.start() + } catch { + print("Audio Engine failed to start: \(error)") + } + } + + func playPCMData(pcmData: UnsafeMutablePointer, count: UInt) { + guard let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels), + let audioBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(count / 4)), // 16位立体声每帧4字节 + let channelData = audioBuffer.floatChannelData else { + return + } + + audioBuffer.frameLength = AVAudioFrameCount(count / 4) + + for frame in 0.. Void in LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) } } } } + + private func startPullAudio() { + DispatchQueue.global().async { + let pullMs: TimeInterval = 10 + let lengthInByte = sampleRate / 1000 * 2 * channels * UInt(pullMs) + let pointer = UnsafeMutablePointer.allocate(capacity: Int(lengthInByte)) + while self.isJoined { + let date = Date() + memset(pointer, 0, Int(lengthInByte)) + let ret = self.agoraKit.pullPlaybackAudioFrameRawData(pointer, lengthInByte: lengthInByte) + self.player.playPCMData(pcmData: pointer, count: lengthInByte) + let cost = -date.timeIntervalSinceNow * 1000 + // multiply 0.4 to make sure thread process time is less than pullMs + usleep(UInt32(max((pullMs * 1000 - cost) * 0.4, 0))) +// print("pullPlaybackAudioFrameRawData: \(ret) lengthInByte: \(lengthInByte) cost: \(-date.timeIntervalSinceNow * 1000) ms") + } + pointer.deallocate() + } + } } + /// agora rtc engine delegate events extension CustomAudioRenderMain: AgoraRtcEngineDelegate { /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out @@ -148,6 +216,7 @@ extension CustomAudioRenderMain: AgoraRtcEngineDelegate { self.audioViews[uid] = view view.setPlaceholder(text: self.getAudioLabel(uid: uid, isLocal: true)) self.container.layoutStream3x3(views: Array(self.audioViews.values)) + startPullAudio() } /// callback when a remote user is joinning the channel, note audience in live broadcast mode will NOT trigger this event diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift index 206d9a942..37c6ba0a8 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift @@ -52,7 +52,7 @@ class CustomPcmAudioSourceMain: BaseViewController { } } - let sampleRate: UInt = 44100, channel: UInt = 1, bitPerSample = 16, samples = 441 * 10 + let sampleRate: UInt = 44100, channel: UInt = 2, bitPerSample = 16, samples = 441 * 10 override func viewDidLoad() { super.viewDidLoad() From 1d65d5b429a6e61baf99227c6fa7313f8b23d675 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 25 Sep 2024 21:19:50 +0800 Subject: [PATCH 016/166] fix: optimize play audio --- .../APIExample.xcodeproj/project.pbxproj | 24 +++++++++---------- .../CustomAudioRender/CustomAudioRender.swift | 10 ++++---- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj index 2fc6d2da7..ba2c64b16 100644 --- a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj +++ b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj @@ -2542,8 +2542,8 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = YS397FG5PA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "Agora-ScreenShare-Extension/Info.plist"; @@ -2576,8 +2576,8 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = YS397FG5PA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "Agora-ScreenShare-Extension/Info.plist"; @@ -2730,10 +2730,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = YS397FG5PA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = APIExample/Info.plist; @@ -2802,9 +2802,9 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = YS397FG5PA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = APIExample/Info.plist; @@ -2869,11 +2869,11 @@ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = YS397FG5PA; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -2906,11 +2906,11 @@ CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = YS397FG5PA; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift index 0ff6e600a..1c5946b76 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift @@ -165,18 +165,20 @@ class CustomAudioRenderMain: BaseViewController { private func startPullAudio() { DispatchQueue.global().async { - let pullMs: TimeInterval = 10 + let pullMs: TimeInterval = 100 let lengthInByte = sampleRate / 1000 * 2 * channels * UInt(pullMs) let pointer = UnsafeMutablePointer.allocate(capacity: Int(lengthInByte)) + var deltaMs: TimeInterval = 0 while self.isJoined { let date = Date() memset(pointer, 0, Int(lengthInByte)) let ret = self.agoraKit.pullPlaybackAudioFrameRawData(pointer, lengthInByte: lengthInByte) self.player.playPCMData(pcmData: pointer, count: lengthInByte) let cost = -date.timeIntervalSinceNow * 1000 - // multiply 0.4 to make sure thread process time is less than pullMs - usleep(UInt32(max((pullMs * 1000 - cost) * 0.4, 0))) -// print("pullPlaybackAudioFrameRawData: \(ret) lengthInByte: \(lengthInByte) cost: \(-date.timeIntervalSinceNow * 1000) ms") + usleep(UInt32(max((pullMs - cost - deltaMs) * 1000, 0))) + // add deltaMs to ensure that the thread processing time is less than pullMs, as thread sleep may not be accurate + deltaMs = max((-date.timeIntervalSinceNow * 1000) - pullMs, 0) * 2 +// print("pullPlaybackAudioFrameRawData: \(ret) lengthInByte: \(lengthInByte) cost: \(-date.timeIntervalSinceNow * 1000) ms, deltaMs: \(deltaMs) ms") } pointer.deallocate() } From e872aab6a54236fe8c493d473e4fec9ed217f5a6 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Thu, 26 Sep 2024 10:57:24 +0800 Subject: [PATCH 017/166] perf: rename pcmplayer --- .../APIExample.xcodeproj/project.pbxproj | 4 ++ .../Common/ExternalAudio/AgoraPCMPlayer.swift | 56 +++++++++++++++++++ .../CustomAudioRender/CustomAudioRender.swift | 49 +--------------- 3 files changed, 61 insertions(+), 48 deletions(-) create mode 100644 iOS/APIExample/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift diff --git a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj index ba2c64b16..b7161cd9b 100644 --- a/iOS/APIExample/APIExample.xcodeproj/project.pbxproj +++ b/iOS/APIExample/APIExample.xcodeproj/project.pbxproj @@ -134,6 +134,7 @@ A7CA48C424553CF700507435 /* Popover.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A7CA48C224553CF600507435 /* Popover.storyboard */; }; B9C914453E92C7F49C93E1F5 /* Pods_APIExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8551A4BC255CE49B383BC575 /* Pods_APIExample.framework */; }; CBCDE23FB64E60D6A79F3723 /* Pods_Agora_ScreenShare_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09E72C5D1AABD812866E41A6 /* Pods_Agora_ScreenShare_Extension.framework */; }; + DD8A1F7C2CA5048D001CEC51 /* AgoraPCMPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8A1F7B2CA5048D001CEC51 /* AgoraPCMPlayer.swift */; }; DDFD50262C205BF20050B344 /* TransparentRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFD50252C205BF20050B344 /* TransparentRender.swift */; }; DDFD50282C205CF40050B344 /* TransparentRender.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DDFD50272C205CF40050B344 /* TransparentRender.storyboard */; }; DDFD502A2C2065D00050B344 /* yuv_limit_range_alpha_1280_540_right.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = DDFD50292C2065D00050B344 /* yuv_limit_range_alpha_1280_540_right.mp4 */; }; @@ -456,6 +457,7 @@ A7CA48C324553CF600507435 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Popover.storyboard; sourceTree = ""; }; BC25C1A6D9E6B8827D095985 /* Pods_SimpleFilter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SimpleFilter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CC6D08A23527C200339E4FD6 /* Pods-SimpleAudioFilter.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleAudioFilter.release.xcconfig"; path = "Target Support Files/Pods-SimpleAudioFilter/Pods-SimpleAudioFilter.release.xcconfig"; sourceTree = ""; }; + DD8A1F7B2CA5048D001CEC51 /* AgoraPCMPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgoraPCMPlayer.swift; sourceTree = ""; }; DDFD50252C205BF20050B344 /* TransparentRender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransparentRender.swift; sourceTree = ""; }; DDFD50272C205CF40050B344 /* TransparentRender.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TransparentRender.storyboard; sourceTree = ""; }; DDFD50292C2065D00050B344 /* yuv_limit_range_alpha_1280_540_right.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = yuv_limit_range_alpha_1280_540_right.mp4; sourceTree = ""; }; @@ -955,6 +957,7 @@ 03DF1D8E24CFC29700DF7151 /* UIView+CSshortFrame.h */, 03DF1D8A24CFC29700DF7151 /* UIView+CSshortFrame.m */, 576CA80B25AA0FA90091520B /* AgoraPcmSourcePush.swift */, + DD8A1F7B2CA5048D001CEC51 /* AgoraPCMPlayer.swift */, ); path = ExternalAudio; sourceTree = ""; @@ -1938,6 +1941,7 @@ F728B9DD2CA295D7007813BB /* PixelBufferPIPViewController.swift in Sources */, E721600F28D3314B006431BD /* AlertManager.swift in Sources */, E7A49CFF29029E0000F06DD4 /* FUManager.m in Sources */, + DD8A1F7C2CA5048D001CEC51 /* AgoraPCMPlayer.swift in Sources */, 0339D6D424E91BAA008739CD /* QuickSwitchChannelVCItem.swift in Sources */, E7163F822964149800EBBD55 /* ARKit.swift in Sources */, 036C42B624D2A3C600A59000 /* AgoraMetalShader.metal in Sources */, diff --git a/iOS/APIExample/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift b/iOS/APIExample/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift new file mode 100644 index 000000000..8f469bf54 --- /dev/null +++ b/iOS/APIExample/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift @@ -0,0 +1,56 @@ +// +// AgoraPCMPlayer.swift +// APIExample +// +// Created by wushengtao on 2024/9/26. +// Copyright © 2024 Agora Corp. All rights reserved. +// + +import Foundation + +class AgoraPCMPlayer { + private var audioEngine: AVAudioEngine + private var playerNode: AVAudioPlayerNode + private var sampleRate: Double + private var channels: AVAudioChannelCount + + init(sampleRate: Double, channels: AVAudioChannelCount) { + self.sampleRate = sampleRate + self.channels = channels + + audioEngine = AVAudioEngine() + playerNode = AVAudioPlayerNode() + + audioEngine.attach(playerNode) + + let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels) + audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: format) + + do { + try audioEngine.start() + } catch { + print("Audio Engine failed to start: \(error)") + } + } + + func playPCMData(pcmData: UnsafeMutablePointer, count: UInt) { + guard let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels), + let audioBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(count / 4)), // 16位立体声每帧4字节 + let channelData = audioBuffer.floatChannelData else { + return + } + + audioBuffer.frameLength = AVAudioFrameCount(count / 4) + + for frame in 0.., count: UInt) { - guard let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels), - let audioBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(count / 4)), // 16位立体声每帧4字节 - let channelData = audioBuffer.floatChannelData else { - return - } - - audioBuffer.frameLength = AVAudioFrameCount(count / 4) - - for frame in 0.. Date: Thu, 26 Sep 2024 13:28:48 +0800 Subject: [PATCH 018/166] fix: resolve audio render issues in objective-c --- .../APIExample-OC.xcodeproj/project.pbxproj | 12 +++- .../Common/ExternalAudio/AgoraPCMPlayer.h | 24 +++++++ .../Common/ExternalAudio/AgoraPCMPlayer.m | 58 ++++++++++++++++ .../CustomAudioRender/CustomAudioRender.m | 69 +++++++++++++------ .../CustomAudioRender/CustomAudioRender.swift | 2 +- 5 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.h create mode 100644 iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.m diff --git a/iOS/APIExample-OC/APIExample-OC.xcodeproj/project.pbxproj b/iOS/APIExample-OC/APIExample-OC.xcodeproj/project.pbxproj index 464f75615..bf5e1d2d0 100644 --- a/iOS/APIExample-OC/APIExample-OC.xcodeproj/project.pbxproj +++ b/iOS/APIExample-OC/APIExample-OC.xcodeproj/project.pbxproj @@ -3,13 +3,14 @@ archiveVersion = 1; classes = { }; - objectVersion = 53; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 749177BD2429C778B3C6D520 /* Pods_APIExample_OC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D931C433C0CD269F3C3323D /* Pods_APIExample_OC.framework */; }; 961E8DCA7B4A6B12564DDC18 /* Pods_SimpleFilter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D0773F7A8BA9611CF846635 /* Pods_SimpleFilter.framework */; }; C2C764A5CC78FAC392BE5584 /* Pods_Agora_ScreenShare_Extension_OC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27A6720DD8507EB2C642C0FD /* Pods_Agora_ScreenShare_Extension_OC.framework */; }; + DD8A1F7F2CA50749001CEC51 /* AgoraPCMPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DD8A1F7E2CA50749001CEC51 /* AgoraPCMPlayer.m */; }; E70ADDF12A5D004F009947CF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E70ADDF02A5D004F009947CF /* AppDelegate.m */; }; E70ADDF72A5D004F009947CF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E70ADDF62A5D004F009947CF /* ViewController.m */; }; E70ADDFA2A5D004F009947CF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E70ADDF82A5D004F009947CF /* Main.storyboard */; }; @@ -179,6 +180,8 @@ BBBCB16091148F518866D952 /* Pods-SimpleFilter.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleFilter.release.xcconfig"; path = "Target Support Files/Pods-SimpleFilter/Pods-SimpleFilter.release.xcconfig"; sourceTree = ""; }; C4F0E8C20AFE260912A60198 /* Pods-Agora-ScreenShare-Extension-OC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Agora-ScreenShare-Extension-OC.release.xcconfig"; path = "Target Support Files/Pods-Agora-ScreenShare-Extension-OC/Pods-Agora-ScreenShare-Extension-OC.release.xcconfig"; sourceTree = ""; }; D5882D286343E06CF635A5E6 /* Pods-Agora-ScreenShare-Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Agora-ScreenShare-Extension.debug.xcconfig"; path = "Target Support Files/Pods-Agora-ScreenShare-Extension/Pods-Agora-ScreenShare-Extension.debug.xcconfig"; sourceTree = ""; }; + DD8A1F7D2CA50749001CEC51 /* AgoraPCMPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AgoraPCMPlayer.h; sourceTree = ""; }; + DD8A1F7E2CA50749001CEC51 /* AgoraPCMPlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AgoraPCMPlayer.m; sourceTree = ""; }; E22416FC36DE1212EE1E1760 /* Pods-Agora-ScrrenShare-Extension-OC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Agora-ScrrenShare-Extension-OC.release.xcconfig"; path = "Target Support Files/Pods-Agora-ScrrenShare-Extension-OC/Pods-Agora-ScrrenShare-Extension-OC.release.xcconfig"; sourceTree = ""; }; E70ADDEC2A5D004F009947CF /* APIExample-OC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "APIExample-OC.app"; sourceTree = BUILT_PRODUCTS_DIR; }; E70ADDEF2A5D004F009947CF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -677,6 +680,8 @@ E70ADEE42A6A71FE009947CF /* ExternalAudio.mm */, E70ADEDB2A6A2D7D009947CF /* AgoraPCMSourcePush.h */, E70ADEDC2A6A2D7D009947CF /* AgoraPCMSourcePush.m */, + DD8A1F7D2CA50749001CEC51 /* AgoraPCMPlayer.h */, + DD8A1F7E2CA50749001CEC51 /* AgoraPCMPlayer.m */, ); path = ExternalAudio; sourceTree = ""; @@ -1283,6 +1288,7 @@ E70ADEF42A6A72C6009947CF /* AudioWriteToFile.m in Sources */, E72F62002A7796A200C963D2 /* SpatialAudioActionSheet.swift in Sources */, E72F61A52A710AB200C963D2 /* MediaPlayer.m in Sources */, + DD8A1F7F2CA50749001CEC51 /* AgoraPCMPlayer.m in Sources */, E7361F6B2A6E6B9F00925BD6 /* SimpleFilter.m in Sources */, E72F618D2A70F8AF00C963D2 /* AgoraCustomEncryption.mm in Sources */, E72F62042A77A63D00C963D2 /* ContentInspect.m in Sources */, @@ -1589,7 +1595,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OBJC_BRIDGING_HEADER = "APIExample-OC/APIExample-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1630,7 +1636,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OBJC_BRIDGING_HEADER = "APIExample-OC/APIExample-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.h b/iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.h new file mode 100644 index 000000000..b11f3f1aa --- /dev/null +++ b/iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.h @@ -0,0 +1,24 @@ +// +// AgoraPCMPlayer.h +// APIExample-OC +// +// Created by wushengtao on 2024/9/26. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface AgoraPCMPlayer : NSObject + +@property (nonatomic, strong) AVAudioEngine *audioEngine; +@property (nonatomic, strong) AVAudioPlayerNode *playerNode; +@property (nonatomic) double sampleRate; +@property (nonatomic) AVAudioChannelCount channels; + +- (instancetype)initWithSampleRate:(double)sampleRate channels:(AVAudioChannelCount)channels; +- (void)playPCMData:(UInt8 *)pcmData count:(NSUInteger)count; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.m b/iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.m new file mode 100644 index 000000000..67b3e22e4 --- /dev/null +++ b/iOS/APIExample-OC/APIExample-OC/Common/ExternalAudio/AgoraPCMPlayer.m @@ -0,0 +1,58 @@ +// +// AgoraPCMPlayer.m +// APIExample-OC +// +// Created by wushengtao on 2024/9/26. +// + +#import "AgoraPCMPlayer.h" +@implementation AgoraPCMPlayer + +- (instancetype)initWithSampleRate:(double)sampleRate channels:(AVAudioChannelCount)channels { + self = [super init]; + if (self) { + _sampleRate = sampleRate; + _channels = channels; + + _audioEngine = [[AVAudioEngine alloc] init]; + _playerNode = [[AVAudioPlayerNode alloc] init]; + + [_audioEngine attachNode:_playerNode]; + + // 使用 AVAudioFormat 的 init 方法 + AVAudioFormat *format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:sampleRate channels:channels]; + [_audioEngine connect:_playerNode to:_audioEngine.mainMixerNode format:format]; + + NSError *error = nil; + // 使用 start 方法的无参数版本 + [_audioEngine startAndReturnError:&error]; + if (error) { + NSLog(@"Audio Engine failed to start: %@", error); + } + } + return self; +} + +- (void)playPCMData:(UInt8 *)pcmData count:(NSUInteger)count { + AVAudioFormat *format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:self.sampleRate channels:self.channels]; + AVAudioPCMBuffer *audioBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:(AVAudioFrameCount)(count / 4)]; // 16-bit stereo, 4 bytes per frame + + if (!audioBuffer.floatChannelData) { + return; + } + + audioBuffer.frameLength = (AVAudioFrameCount)(count / 4); + + for (NSUInteger frame = 0; frame < audioBuffer.frameLength; frame++) { + int16_t leftSample = pcmData[frame * 4] | (pcmData[frame * 4 + 1] << 8); + int16_t rightSample = pcmData[frame * 4 + 2] | (pcmData[frame * 4 + 3] << 8); + + audioBuffer.floatChannelData[0][frame] = (float)leftSample / INT16_MAX; + audioBuffer.floatChannelData[1][frame] = (float)rightSample / INT16_MAX; + } + + [_playerNode scheduleBuffer:audioBuffer completionHandler:nil]; + [_playerNode play]; +} + +@end diff --git a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m index e25523865..96158f924 100644 --- a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m +++ b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m @@ -10,7 +10,13 @@ #import #import "VideoView.h" #import "APIExample_OC-swift.h" -#import "ExternalAudio.h" +#import "AgoraPCMPlayer.h" + + +const NSUInteger bitsPerSample = 16; +const NSUInteger samples = 441 * 10; +const NSUInteger sampleRate = 44100; +const NSUInteger channels = 2; @interface CustomAudioRenderEntry () @property (weak, nonatomic) IBOutlet UITextField *textField; @@ -40,17 +46,19 @@ @interface CustomAudioRender () @property (nonatomic, strong)VideoView *localView; @property (nonatomic, strong)VideoView *remoteView; @property (nonatomic, strong)AgoraRtcEngineKit *agoraKit; -@property (nonatomic, strong)ExternalAudio *exAudio; +@property (nonatomic, strong)AgoraPCMPlayer *player; +@property (assign, atomic) BOOL isJoined; @end @implementation CustomAudioRender -- (ExternalAudio *)exAudio { - if (_exAudio == nil) { - _exAudio = [ExternalAudio sharedExternalAudio]; +- (AgoraPCMPlayer*)player { + if (_player == nil) { + _player = [[AgoraPCMPlayer alloc] initWithSampleRate:sampleRate channels:channels]; } - return _exAudio; + + return _player; } - (VideoView *)localView { @@ -84,22 +92,9 @@ - (void)viewDidLoad { self.agoraKit = [AgoraRtcEngineKit sharedEngineWithConfig:config delegate:self]; NSString *channelName = [self.configs objectForKey:@"channelName"]; - // make myself a broadcaster - [self.agoraKit setClientRole:(AgoraClientRoleBroadcaster)]; // enable video module and set up video encoding configs [self.agoraKit enableAudio]; - AgoraVideoEncoderConfiguration *encoderConfig = [[AgoraVideoEncoderConfiguration alloc] initWithSize:CGSizeMake(960, 540) - frameRate:(AgoraVideoFrameRateFps15) - bitrate:15 - orientationMode:(AgoraVideoOutputOrientationModeFixedPortrait) - mirrorMode:(AgoraVideoMirrorModeAuto)]; - [self.agoraKit setVideoEncoderConfiguration:encoderConfig]; - - [self.exAudio setupExternalAudioWithAgoraKit:self.agoraKit sampleRate:44100 channels:1 audioCRMode:(AudioCRModeExterCaptureExterRender) IOType:(IOUnitTypeRemoteIO)]; - [self.agoraKit setParameters:@"{\"che.audio.external_render\": true}"]; - [self.agoraKit setParameters:@"{\"che.audio.keep.audiosession\": true}"]; - // set up local video to render your local camera preview AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init]; videoCanvas.uid = 0; @@ -118,12 +113,14 @@ - (void)viewDidLoad { // when joining channel. The channel name and uid used to calculate // the token has to match the ones used for channel join AgoraRtcChannelMediaOptions *options = [[AgoraRtcChannelMediaOptions alloc] init]; + options.publishMicrophoneTrack = NO; + options.publishCameraTrack = NO; options.autoSubscribeAudio = YES; options.autoSubscribeVideo = NO; - options.publishMicrophoneTrack = YES; - options.publishCameraTrack = NO; options.clientRoleType = AgoraClientRoleBroadcaster; + [self.agoraKit enableExternalAudioSink:YES sampleRate:sampleRate channels:channels]; + [[NetworkManager shared] generateTokenWithChannelName:channelName uid:0 success:^(NSString * _Nullable token) { int result = [self.agoraKit joinChannelByToken:token channelId:channelName uid:0 mediaOptions:options joinSuccess:nil]; if (result != 0) { @@ -141,6 +138,34 @@ - (void)viewDidDisappear:(BOOL)animated { [self.agoraKit disableAudio]; [self.agoraKit leaveChannel:nil]; [AgoraRtcEngineKit destroy]; + self.isJoined = NO; +} + +- (void)startPullAudio { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSTimeInterval pullMs = 100; + NSUInteger lengthInByte = (sampleRate / 1000) * 2 * channels * (NSUInteger)pullMs; + + UInt8 *pointer = (UInt8 *)malloc(lengthInByte); + NSTimeInterval deltaMs = 0; + + while (self.isJoined) { + NSDate *date = [NSDate date]; + memset(pointer, 0, lengthInByte); + + NSInteger ret = [self.agoraKit pullPlaybackAudioFrameRawData:pointer lengthInByte:lengthInByte]; + [self.player playPCMData:pointer count:lengthInByte]; + + NSTimeInterval cost = -[date timeIntervalSinceNow] * 1000; + usleep((useconds_t)MAX((pullMs - cost - deltaMs) * 1000, 0)); + + // Add deltaMs to ensure that the thread processing time is less than pullMs + deltaMs = MAX((- [date timeIntervalSinceNow] * 1000) - pullMs, 0) * 2; + // NSLog(@"pullPlaybackAudioFrameRawData: %ld lengthInByte: %lu cost: %f ms, deltaMs: %f ms", ret, (unsigned long)lengthInByte, -[date timeIntervalSinceNow] * 1000, deltaMs); + } + + free(pointer); + }); } /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand @@ -156,6 +181,8 @@ - (void)rtcEngine:(AgoraRtcEngineKit *)engine didOccurError:(AgoraErrorCode)erro - (void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinChannel:(NSString *)channel withUid:(NSUInteger)uid elapsed:(NSInteger)elapsed { [LogUtil log:[NSString stringWithFormat:@"Join %@ with uid %lu elapsed %ldms", channel, uid, elapsed] level:(LogLevelDebug)]; self.localView.uid = uid; + [self startPullAudio]; + self.isJoined = YES; } /// callback when a remote user is joinning the channel, note audience in live broadcast mode will NOT trigger this event diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift index 57036058e..7ea926e21 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift @@ -87,7 +87,7 @@ class CustomAudioRenderMain: BaseViewController { option.autoSubscribeAudio = true option.autoSubscribeVideo = false option.channelProfile = .liveBroadcasting - option.clientRoleType = .broadcaster //GlobalSettings.shared.getUserRole() + option.clientRoleType = .broadcaster agoraKit.enableExternalAudioSink(true, sampleRate: sampleRate, channels: channels) NetworkManager.shared.generateToken(channelName: channelName, success: { token in From e702b5034b866c7219b8075b73365c6fef4baeb7 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Thu, 26 Sep 2024 16:10:27 +0800 Subject: [PATCH 019/166] fix: pcm audio publish fixed --- .../CustomPcmAudioSource.m | 28 +++++++--------- .../CustomPcmAudioSource.storyboard | 33 +++++++++++++++++-- .../CustomPcmAudioSource.swift | 1 + 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.m b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.m index fc5f76fe2..fdd8d4141 100644 --- a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.m +++ b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.m @@ -38,6 +38,7 @@ - (IBAction)onClickJoinButton:(id)sender { @interface CustomPcmAudioSource () @property (weak, nonatomic) IBOutlet UIView *containerView; @property (weak, nonatomic) IBOutlet UISwitch *pushPcmSwitch; +@property (weak, nonatomic) IBOutlet UISwitch *pushMicrophoneSwitch; @property (nonatomic, strong)VideoView *localView; @property (nonatomic, strong)VideoView *remoteView; @property (nonatomic, strong)AgoraRtcEngineKit *agoraKit; @@ -72,7 +73,7 @@ - (void)viewDidLoad { [self.containerView layoutStream:@[self.localView, self.remoteView]]; NSString *filePath = [[NSBundle mainBundle] pathForResource:@"output.raw" ofType:nil]; - self.pcmSourcePush = [[AgoraPCMSourcePush alloc] initWithDelegate:self filePath:filePath sampleRate:44100 channelsPerFrame:1 bitPerSamples:16 samples:441 * 10]; + self.pcmSourcePush = [[AgoraPCMSourcePush alloc] initWithDelegate:self filePath:filePath sampleRate:44100 channelsPerFrame:2 bitPerSamples:16 samples:441 * 10]; // set up agora instance when view loaded AgoraRtcEngineConfig *config = [[AgoraRtcEngineConfig alloc] init]; @@ -82,18 +83,9 @@ - (void)viewDidLoad { self.agoraKit = [AgoraRtcEngineKit sharedEngineWithConfig:config delegate:self]; NSString *channelName = [self.configs objectForKey:@"channelName"]; - // make myself a broadcaster - [self.agoraKit setClientRole:(AgoraClientRoleBroadcaster)]; // enable video module and set up video encoding configs [self.agoraKit enableAudio]; - AgoraVideoEncoderConfiguration *encoderConfig = [[AgoraVideoEncoderConfiguration alloc] initWithSize:CGSizeMake(960, 540) - frameRate:(AgoraVideoFrameRateFps15) - bitrate:15 - orientationMode:(AgoraVideoOutputOrientationModeFixedPortrait) - mirrorMode:(AgoraVideoMirrorModeAuto)]; - [self.agoraKit setVideoEncoderConfiguration:encoderConfig]; - AgoraAudioTrackConfig *trackConfig = [[AgoraAudioTrackConfig alloc] init]; trackConfig.enableLocalPlayback = YES; self.trackId = [self.agoraKit createCustomAudioTrack:(AgoraAudioTrackTypeMixable) config:trackConfig]; @@ -117,12 +109,9 @@ - (void)viewDidLoad { // when joining channel. The channel name and uid used to calculate // the token has to match the ones used for channel join AgoraRtcChannelMediaOptions *options = [[AgoraRtcChannelMediaOptions alloc] init]; - options.autoSubscribeAudio = YES; options.autoSubscribeVideo = NO; - options.publishMicrophoneTrack = YES; + options.publishMicrophoneTrack = NO; options.publishCameraTrack = NO; - options.publishCustomAudioTrack = YES; - options.publishCustomAudioTrackId = self.trackId; options.clientRoleType = AgoraClientRoleBroadcaster; [[NetworkManager shared] generateTokenWithChannelName:channelName uid:0 success:^(NSString * _Nullable token) { @@ -144,6 +133,13 @@ - (IBAction)pushPCM:(UISwitch *)sender { } AgoraRtcChannelMediaOptions *mediaOption = [[AgoraRtcChannelMediaOptions alloc] init]; mediaOption.publishCustomAudioTrack = sender.isOn; + mediaOption.publishCustomAudioTrackId = self.trackId; + [self.agoraKit updateChannelWithMediaOptions:mediaOption]; +} + +- (IBAction)pushMicrophone:(UISwitch*)sender { + AgoraRtcChannelMediaOptions *mediaOption = [[AgoraRtcChannelMediaOptions alloc] init]; + mediaOption.publishMicrophoneTrack = sender.isOn; [self.agoraKit updateChannelWithMediaOptions:mediaOption]; } @@ -159,9 +155,9 @@ - (void)viewDidDisappear:(BOOL)animated { // AgoraPcmSourcePushDelegate - (void)onAudioFrame:(void *)data { [self.agoraKit pushExternalAudioFrameRawData:data - samples:441 * 10 + samples:441 * 10 * 2 sampleRate:44100 - channels:1 + channels:2 trackId:self.trackId timestamp:0]; } diff --git a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.storyboard b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.storyboard index 6a293c9ee..8af06565e 100644 --- a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.storyboard +++ b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.storyboard @@ -1,9 +1,9 @@ - + - + @@ -76,32 +76,59 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift index 37c6ba0a8..1ce0c8f82 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift @@ -96,6 +96,7 @@ class CustomPcmAudioSourceMain: BaseViewController { // when joining channel. The channel name and uid used to calculate // the token has to match the ones used for channel join let option = AgoraRtcChannelMediaOptions() + option.autoSubscribeVideo = false option.publishCameraTrack = false option.publishMicrophoneTrack = false NetworkManager.shared.generateToken(channelName: channelName, success: { token in From c09f4d9c90f5e319ac3d733b42d14a7438b0db57 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Thu, 26 Sep 2024 16:55:04 +0800 Subject: [PATCH 020/166] fix: fix: resolve audio render issues in audio only project --- .../project.pbxproj | 4 ++ .../Common/ExternalAudio/AgoraPCMPlayer.swift | 56 +++++++++++++++++++ .../CustomAudioRender/CustomAudioRender.swift | 49 ++++++++++++---- .../CustomPcmAudioSource.swift | 2 +- .../CustomAudioRender/CustomAudioRender.m | 1 + .../CustomAudioRender/CustomAudioRender.swift | 3 - 6 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 iOS/APIExample-Audio/APIExample-Audio/Common/ExternalAudio/AgoraPCMPlayer.swift diff --git a/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj b/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj index d233acb6f..2dcbff869 100644 --- a/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj +++ b/iOS/APIExample-Audio/APIExample-Audio.xcodeproj/project.pbxproj @@ -58,6 +58,7 @@ A7847F942458089E00469187 /* AgoraExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7847F932458089E00469187 /* AgoraExtension.swift */; }; A7BD7660247CC6920062A6B3 /* UITypeAlias.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7BD765F247CC6920062A6B3 /* UITypeAlias.swift */; }; A7CA48C424553CF700507435 /* Popover.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A7CA48C224553CF600507435 /* Popover.storyboard */; }; + DD8A1F812CA54F90001CEC51 /* AgoraPCMPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8A1F802CA54F90001CEC51 /* AgoraPCMPlayer.swift */; }; E70EE9E728F6A6FF00EE9E7F /* JoinChannelAudioToken.strings in Resources */ = {isa = PBXBuildFile; fileRef = E70EE9E228F6A6FF00EE9E7F /* JoinChannelAudioToken.strings */; }; E70EE9E828F6A6FF00EE9E7F /* JoinChannelAudioToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = E70EE9E428F6A6FF00EE9E7F /* JoinChannelAudioToken.swift */; }; E70EE9E928F6A6FF00EE9E7F /* JoinChannelAudioToken.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E70EE9E528F6A6FF00EE9E7F /* JoinChannelAudioToken.storyboard */; }; @@ -184,6 +185,7 @@ A7CA48C324553CF600507435 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Popover.storyboard; sourceTree = ""; }; BC25C1A6D9E6B8827D095985 /* Pods_SimpleFilter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SimpleFilter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CC6D08A23527C200339E4FD6 /* Pods-SimpleAudioFilter.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleAudioFilter.release.xcconfig"; path = "Target Support Files/Pods-SimpleAudioFilter/Pods-SimpleAudioFilter.release.xcconfig"; sourceTree = ""; }; + DD8A1F802CA54F90001CEC51 /* AgoraPCMPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AgoraPCMPlayer.swift; sourceTree = ""; }; E70EE9E328F6A6FF00EE9E7F /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/JoinChannelAudioToken.strings"; sourceTree = ""; }; E70EE9E428F6A6FF00EE9E7F /* JoinChannelAudioToken.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JoinChannelAudioToken.swift; sourceTree = ""; }; E70EE9E628F6A6FF00EE9E7F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/JoinChannelAudioToken.storyboard; sourceTree = ""; }; @@ -374,6 +376,7 @@ 03DF1D8424CFC29700DF7151 /* ExternalAudio */ = { isa = PBXGroup; children = ( + DD8A1F802CA54F90001CEC51 /* AgoraPCMPlayer.swift */, 03DF1D8524CFC29700DF7151 /* AudioOptions.h */, 03DF1D8C24CFC29700DF7151 /* AudioWriteToFile.h */, 03DF1D8624CFC29700DF7151 /* AudioWriteToFile.m */, @@ -689,6 +692,7 @@ 03BEED08251C35E7005E78F4 /* AudioMixing.swift in Sources */, E74877B728A23B8B00CA2F58 /* NetworkManager.swift in Sources */, 03DF1D9424CFC29700DF7151 /* AudioController.m in Sources */, + DD8A1F812CA54F90001CEC51 /* AgoraPCMPlayer.swift in Sources */, 03DF1D9024CFC29700DF7151 /* AudioWriteToFile.m in Sources */, E72055EC28F94C400030E6D1 /* Util.swift in Sources */, 0339BE6D251DEAFC007D4FDD /* PrecallTest.swift in Sources */, diff --git a/iOS/APIExample-Audio/APIExample-Audio/Common/ExternalAudio/AgoraPCMPlayer.swift b/iOS/APIExample-Audio/APIExample-Audio/Common/ExternalAudio/AgoraPCMPlayer.swift new file mode 100644 index 000000000..94fdff3fe --- /dev/null +++ b/iOS/APIExample-Audio/APIExample-Audio/Common/ExternalAudio/AgoraPCMPlayer.swift @@ -0,0 +1,56 @@ +// +// AgoraPCMPlayer.swift +// APIExample +// +// Created by wushengtao on 2024/9/26. +// Copyright © 2024 Agora Corp. All rights reserved. +// + +import AVFoundation + +class AgoraPCMPlayer { + private var audioEngine: AVAudioEngine + private var playerNode: AVAudioPlayerNode + private var sampleRate: Double + private var channels: AVAudioChannelCount + + init(sampleRate: Double, channels: AVAudioChannelCount) { + self.sampleRate = sampleRate + self.channels = channels + + audioEngine = AVAudioEngine() + playerNode = AVAudioPlayerNode() + + audioEngine.attach(playerNode) + + let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels) + audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: format) + + do { + try audioEngine.start() + } catch { + print("Audio Engine failed to start: \(error)") + } + } + + func playPCMData(pcmData: UnsafeMutablePointer, count: UInt) { + guard let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels), + let audioBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(count / 4)), // 16位立体声每帧4字节 + let channelData = audioBuffer.floatChannelData else { + return + } + + audioBuffer.frameLength = AVAudioFrameCount(count / 4) + + for frame in 0.. Void in LogUtils.log(message: "left channel, duration: \(stats.duration)", level: .info) } } } } + + private func startPullAudio() { + DispatchQueue.global().async { + let pullMs: TimeInterval = 100 + let lengthInByte = sampleRate / 1000 * 2 * channels * UInt(pullMs) + let pointer = UnsafeMutablePointer.allocate(capacity: Int(lengthInByte)) + var deltaMs: TimeInterval = 0 + while self.isJoined { + let date = Date() + memset(pointer, 0, Int(lengthInByte)) + let ret = self.agoraKit.pullPlaybackAudioFrameRawData(pointer, lengthInByte: lengthInByte) + self.player.playPCMData(pcmData: pointer, count: lengthInByte) + let cost = -date.timeIntervalSinceNow * 1000 + usleep(UInt32(max((pullMs - cost - deltaMs) * 1000, 0))) + // add deltaMs to ensure that the thread processing time is less than pullMs, as thread sleep may not be accurate + deltaMs = max((-date.timeIntervalSinceNow * 1000) - pullMs, 0) * 2 +// print("pullPlaybackAudioFrameRawData: \(ret) lengthInByte: \(lengthInByte) cost: \(-date.timeIntervalSinceNow * 1000) ms, deltaMs: \(deltaMs) ms") + } + pointer.deallocate() + } + } } /// agora rtc engine delegate events @@ -147,6 +175,7 @@ extension CustomAudioRenderMain: AgoraRtcEngineDelegate { self.audioViews[uid] = view view.setPlaceholder(text: self.getAudioLabel(uid: uid, isLocal: true)) self.container.layoutStream3x3(views: Array(self.audioViews.values)) + startPullAudio() } /// callback when a remote user is joinning the channel, note audience in live broadcast mode will NOT trigger this event diff --git a/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift b/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift index fc8151330..46c2b0a96 100644 --- a/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift +++ b/iOS/APIExample-Audio/APIExample-Audio/Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift @@ -51,7 +51,7 @@ class CustomPcmAudioSourceMain: BaseViewController { } } - let sampleRate:UInt = 44100, channel:UInt = 1, bitPerSample = 16, samples = 441 * 10 + let sampleRate:UInt = 44100, channel:UInt = 2, bitPerSample = 16, samples = 441 * 10 override func viewDidLoad(){ super.viewDidLoad() diff --git a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m index 96158f924..85989534d 100644 --- a/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m +++ b/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/CustomAudioRender/CustomAudioRender.m @@ -137,6 +137,7 @@ - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.agoraKit disableAudio]; [self.agoraKit leaveChannel:nil]; + [self.agoraKit enableExternalAudioSink:NO sampleRate:sampleRate channels:channels]; [AgoraRtcEngineKit destroy]; self.isJoined = NO; } diff --git a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift index 7ea926e21..8cbadf815 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift @@ -66,9 +66,6 @@ class CustomAudioRenderMain: BaseViewController { guard let channelName = configs["channelName"] as? String else {return} - // make myself a broadcaster - agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) - // disable video module agoraKit.disableVideo() agoraKit.enableAudio() From 714b79dd81fbce610fde1e90f116819a78bf3ee6 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Thu, 26 Sep 2024 17:08:23 +0800 Subject: [PATCH 021/166] fix: resolve audio render issues in mac --- macOS/APIExample.xcodeproj/project.pbxproj | 4 ++ .../Common/ExternalAudio/AgoraPCMPlayer.swift | 56 +++++++++++++++++++ .../CustomAudioRender/CustomAudioRender.swift | 53 +++++++++++++----- .../CustomAudioSource/CustomAudioSource.swift | 4 +- 4 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 macOS/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift diff --git a/macOS/APIExample.xcodeproj/project.pbxproj b/macOS/APIExample.xcodeproj/project.pbxproj index 8bc7e7700..e1a687d0c 100644 --- a/macOS/APIExample.xcodeproj/project.pbxproj +++ b/macOS/APIExample.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 8BD4AE73272513FF00E95B87 /* SimpleFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BD4AE72272513FF00E95B87 /* SimpleFilter.swift */; }; 8BE63B4227253CB000597DB1 /* SimpleFilter.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8BE63B4427253CB000597DB1 /* SimpleFilter.storyboard */; }; 8BF2243B275F82CF00B65EF8 /* SimpleFilter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8BD4AE79272518D600E95B87 /* SimpleFilter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + DD8A1F922CA55AA4001CEC51 /* AgoraPCMPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8A1F912CA55AA4001CEC51 /* AgoraPCMPlayer.swift */; }; E702C1E728B4DB4800D7C7ED /* LiveStreaming.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E702C1E328B4DB4800D7C7ED /* LiveStreaming.storyboard */; }; E702C1E828B4DB4800D7C7ED /* LiveStreaming.swift in Sources */ = {isa = PBXBuildFile; fileRef = E702C1E528B4DB4800D7C7ED /* LiveStreaming.swift */; }; E71E7B0B289B7D7900B846C7 /* SimpleFilter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BD4AE79272518D600E95B87 /* SimpleFilter.framework */; }; @@ -271,6 +272,7 @@ 8BD4AE72272513FF00E95B87 /* SimpleFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleFilter.swift; sourceTree = ""; }; 8BD4AE79272518D600E95B87 /* SimpleFilter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleFilter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8BE63B4527253CD900597DB1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/SimpleFilter.storyboard; sourceTree = ""; }; + DD8A1F912CA55AA4001CEC51 /* AgoraPCMPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AgoraPCMPlayer.swift; sourceTree = ""; }; E702C1E528B4DB4800D7C7ED /* LiveStreaming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveStreaming.swift; sourceTree = ""; }; E71E7B0D289B96FA00B846C7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/VideoProcess.storyboard; sourceTree = ""; }; E71E7B12289B971900B846C7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/VideoProcess.strings; sourceTree = ""; }; @@ -381,6 +383,7 @@ 0336A1BB25034F4600D61B7F /* ExternalAudio */ = { isa = PBXGroup; children = ( + DD8A1F912CA55AA4001CEC51 /* AgoraPCMPlayer.swift */, 0336A1BC25034F4600D61B7F /* AudioOptions.h */, 0336A1C325034F4700D61B7F /* AudioWriteToFile.h */, 0336A1BD25034F4600D61B7F /* AudioWriteToFile.m */, @@ -1192,6 +1195,7 @@ E7883AE22B046CB8003CCF44 /* FaceCapture.swift in Sources */, 0336A1CA25034F4700D61B7F /* ExternalAudio.mm in Sources */, E779025B2A482CFC008791AD /* KFMP4Demuxer.m in Sources */, + DD8A1F922CA55AA4001CEC51 /* AgoraPCMPlayer.swift in Sources */, 033A9FA1252EA86A00BC26E1 /* CustomAudioRender.swift in Sources */, 034C627C2526C43900296ECF /* ScreenShare.swift in Sources */, 034C62712525A35800296ECF /* StreamEncryption.swift in Sources */, diff --git a/macOS/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift b/macOS/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift new file mode 100644 index 000000000..8f469bf54 --- /dev/null +++ b/macOS/APIExample/Common/ExternalAudio/AgoraPCMPlayer.swift @@ -0,0 +1,56 @@ +// +// AgoraPCMPlayer.swift +// APIExample +// +// Created by wushengtao on 2024/9/26. +// Copyright © 2024 Agora Corp. All rights reserved. +// + +import Foundation + +class AgoraPCMPlayer { + private var audioEngine: AVAudioEngine + private var playerNode: AVAudioPlayerNode + private var sampleRate: Double + private var channels: AVAudioChannelCount + + init(sampleRate: Double, channels: AVAudioChannelCount) { + self.sampleRate = sampleRate + self.channels = channels + + audioEngine = AVAudioEngine() + playerNode = AVAudioPlayerNode() + + audioEngine.attach(playerNode) + + let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels) + audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: format) + + do { + try audioEngine.start() + } catch { + print("Audio Engine failed to start: \(error)") + } + } + + func playPCMData(pcmData: UnsafeMutablePointer, count: UInt) { + guard let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: channels), + let audioBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(count / 4)), // 16位立体声每帧4字节 + let channelData = audioBuffer.floatChannelData else { + return + } + + audioBuffer.frameLength = AVAudioFrameCount(count / 4) + + for frame in 0...allocate(capacity: Int(lengthInByte)) + var deltaMs: TimeInterval = 0 + while self.isJoined { + let date = Date() + memset(pointer, 0, Int(lengthInByte)) + let ret = self.agoraKit.pullPlaybackAudioFrameRawData(pointer, lengthInByte: lengthInByte) + self.player.playPCMData(pcmData: pointer, count: lengthInByte) + let cost = -date.timeIntervalSinceNow * 1000 + usleep(UInt32(max((pullMs - cost - deltaMs) * 1000, 0))) + // add deltaMs to ensure that the thread processing time is less than pullMs, as thread sleep may not be accurate + deltaMs = max((-date.timeIntervalSinceNow * 1000) - pullMs, 0) * 2 +// print("pullPlaybackAudioFrameRawData: \(ret) lengthInByte: \(lengthInByte) cost: \(-date.timeIntervalSinceNow * 1000) ms, deltaMs: \(deltaMs) ms") + } + pointer.deallocate() + } + } } /// agora rtc engine delegate events @@ -259,7 +286,7 @@ extension CustomAudioRender: AgoraRtcEngineDelegate { let localVideo = videos[0] localVideo.uid = uid LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info) - exAudio.startWork() + startPullAudio() } /// callback when a remote user is joinning the channel, note audience in live broadcast mode will NOT trigger this event diff --git a/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift b/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift index 112c45266..5a4764be8 100644 --- a/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift +++ b/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift @@ -164,7 +164,7 @@ class CustomAudioSource: BaseViewController { agoraKit.updateChannel(with: mediaOption) } - let sampleRate:UInt = 44100, audioChannel:UInt = 1, bitPerSample = 16, samples = 441 * 10 + let sampleRate:UInt = 44100, audioChannel:UInt = 2, bitPerSample = 16, samples = 441 * 10 @IBAction func onJoinPressed(_ sender:Any) { if !isJoined { // check configuration @@ -336,7 +336,7 @@ extension CustomAudioSource: AgoraRtcEngineDelegate { extension CustomAudioSource: AgoraPcmSourcePushDelegate { func onAudioFrame(data: UnsafeMutablePointer) { agoraKit.pushExternalAudioFrameRawData(data, - samples: samples, + samples: samples*Int(audioChannel), sampleRate: Int(sampleRate), channels: Int(audioChannel), trackId: Int(trackId), From a8db7ad8a1d9bc7fa211eb88132c4992ad18e6a8 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Mon, 30 Sep 2024 14:36:30 +0800 Subject: [PATCH 022/166] feat: add makeup & face shape --- .../Base.lproj/VideoProcess.storyboard | 74 ++- .../Advanced/VideoProcess/VideoProcess.swift | 496 ++++++++++++++++++ .../zh-Hans.lproj/VideoProcess.strings | 6 + .../zh-Hans.lproj/Localizable.strings | 57 ++ 4 files changed, 610 insertions(+), 23 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard index 3c367780c..a8bd90dbb 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard +++ b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard @@ -1,9 +1,9 @@ - + - + @@ -18,7 +18,7 @@ - + @@ -44,13 +44,13 @@ - + @@ -87,14 +87,14 @@ - + - + - + @@ -124,7 +124,7 @@ - + @@ -133,13 +133,13 @@ - + @@ -148,13 +148,13 @@ - + @@ -163,7 +163,7 @@ - + - + - + - + - + - + + - + @@ -344,11 +357,23 @@ + @@ -360,6 +385,7 @@ + @@ -378,9 +404,11 @@ + + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift index f1b6c7ca3..ec94abd41 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift @@ -54,6 +54,11 @@ class VideoProcessMain: BaseViewController { var beautifyOption = AgoraBeautyOptions() var skinProtect = 0.5 var strength = 0.5 + + private var makeupParams = [String: Any]() + private var enableFaceShape: Bool = false + private lazy var faceshapeOption = AgoraFaceShapeBeautyOptions() + private var beautyShapeParames = [String: Float]() override func viewDidLoad() { super.viewDidLoad() @@ -368,3 +373,494 @@ extension VideoProcessMain: AgoraRtcEngineDelegate { remoteVideo.statsInfo?.updateAudioStats(stats) } } + +private let makeupList = [ + [ + "name": "Makeup_enable_mu".localized, + "key": "enable_mu", + "type": "switch" + ], [ + "name": "Makeup_browStyle".localized, + "key": "browStyle", + "type": "segment", + "value": ["Makeup_browStyle_value1".localized, "Makeup_browStyle_value2".localized, "Makeup_browStyle_value3".localized] + ], [ + "name": "Makeup_browColor".localized, + "key": "browColor", + "type": "segment", + "value": ["Makeup_browColor_value1".localized, "Makeup_browColor_value2".localized, "Makeup_browColor_value3".localized] + ], [ + "name": "Makeup_browStrength".localized, + "key": "browStrength", + "type": "slider", + "value": [0, 1] + ], [ + "name": "Makeup_lashStyle".localized, + "key": "lashStyle", + "type": "segment", + "value": ["Makeup_browStyle_value1".localized, "Makeup_browStyle_value2".localized, "Makeup_browStyle_value3".localized] + ], [ + "name": "Makeup_lashColor".localized, + "key": "lashColor", + "type": "segment", + "value": ["Makeup_browColor_value1".localized, "Makeup_browColor_value2".localized, "Makeup_browColor_value3".localized] + ], [ + "name": "Makeup_lashStrength".localized, + "key": "lashStrength", + "type": "slider", + "value": [0, 1] + ], [ + "name": "Makeup_shadowStyle".localized, + "key": "shadowStyle", + "type": "segment", + "value": ["Makeup_browStyle_value1".localized, "Makeup_browStyle_value2".localized, "Makeup_browStyle_value3".localized] + ], + // ["name": "Makeup_shadowColor".localized, "key": "shadowColor"], + [ + "name": "Makeup_shadowStrength".localized, + "key": "shadowStrength", + "type": "slider", + "value": [0, 1] + ], [ + "name": "Makeup_pupilStyle".localized, + "key": "pupilStyle", + "type": "segment", + "value": ["Makeup_browStyle_value1".localized, "Makeup_browStyle_value2".localized, "Makeup_browStyle_value3".localized] + ], + // ["name": "Makeup_pupilColor".localized, "key": "pupilColor"], + [ + "name": "Makeup_pupilStrength".localized, + "key": "pupilStrength", + "type": "slider", + "value": [0, 1] + ], [ + "name": "Makeup_blushStyle".localized, + "key": "blushStyle", + "type": "segment", + "value": ["Makeup_browStyle_value1".localized, "Makeup_browStyle_value2".localized, "Makeup_browStyle_value3".localized] + ], [ + "name": "Makeup_blushColor".localized, + "key": "blushColor", + "type": "segment", + "value": [ + "Makeup_blushColor_value1".localized, + "Makeup_blushColor_value2".localized, + "Makeup_blushColor_value3".localized, + "Makeup_blushColor_value4".localized, + "Makeup_blushColor_value5".localized + ] + ], [ + "name": "Makeup_blushStrength".localized, + "key": "blushStrength", + "type": "slider", + "value": [0, 1] + ], [ + "name": "Makeup_lipStyle".localized, + "key": "lipStyle", + "type": "segment", + "value": ["Makeup_browColor_value1".localized, "Makeup_browColor_value2".localized, "Makeup_browColor_value3".localized] + ], [ + "name": "Makeup_lipColor".localized, + "key": "lipColor", + "type": "segment", + "value": [ + "Makeup_blushColor_value1".localized, + "Makeup_blushColor_value2".localized, + "Makeup_blushColor_value3".localized, + "Makeup_blushColor_value4".localized, + "Makeup_blushColor_value5".localized + ] + ], [ + "name": "Makeup_lipStrength".localized, + "key": "lipStrength", + "type": "slider", + "value": [0, 1] + ] +] + +// MARK: make up setting +extension VideoProcessMain { + @IBAction func onShowMakeUpAction() { + // 创建自定义视图控制器 + let customAlertVC = UIViewController() + customAlertVC.modalPresentationStyle = .overFullScreen + customAlertVC.view.backgroundColor = .clear + + // 自定义内容视图 + let alertView = UIView() + alertView.translatesAutoresizingMaskIntoConstraints = false + alertView.backgroundColor = UIColor.white + alertView.layer.shadowColor = UIColor.black.cgColor + alertView.layer.shadowOpacity = 0.2 + alertView.layer.shadowOffset = CGSize(width: 0, height: 2) + alertView.layer.shadowRadius = 4 + + customAlertVC.view.addSubview(alertView) + + // 设置 alertView 的约束 + NSLayoutConstraint.activate([ + alertView.centerXAnchor.constraint(equalTo: customAlertVC.view.centerXAnchor), + alertView.centerYAnchor.constraint(equalTo: customAlertVC.view.centerYAnchor), + alertView.widthAnchor.constraint(equalTo: customAlertVC.view.widthAnchor, constant: -20), + alertView.heightAnchor.constraint(equalToConstant: 300) + ]) + + // 创建 scrollView + let scrollView = UIScrollView() + scrollView.translatesAutoresizingMaskIntoConstraints = false + alertView.addSubview(scrollView) + + NSLayoutConstraint.activate([ + scrollView.topAnchor.constraint(equalTo: alertView.topAnchor), + scrollView.leadingAnchor.constraint(equalTo: alertView.leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: alertView.trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: alertView.bottomAnchor, constant: -50) // 留出按钮位置 + ]) + + let contentView = UIView() + contentView.translatesAutoresizingMaskIntoConstraints = false + scrollView.addSubview(contentView) + + NSLayoutConstraint.activate([ + contentView.topAnchor.constraint(equalTo: scrollView.topAnchor), + contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), + contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), + contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor) + ]) + + + // 添加 UILabels 和 UISliders 到 contentView + var lastLabel: UILabel? + for i in 0.. Date: Mon, 30 Sep 2024 15:41:53 +0800 Subject: [PATCH 023/166] fix: update face shape fixed --- .../Examples/Advanced/VideoProcess/VideoProcess.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift index ec94abd41..800aec983 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift @@ -852,12 +852,12 @@ extension VideoProcessMain { @objc func beautyShapeSwitchAction(_ view: UISwitch) { enableFaceShape = view.isOn - updateMakeup() + updateFaceShape() } @objc func beautyShapeSegmentAction(_ view: UISegmentedControl) { faceshapeOption.shapeStyle = AgoraFaceShapeStyle(rawValue: UInt(view.selectedSegmentIndex)) ?? .female - updateMakeup() + updateFaceShape() } private func updateFaceShape() { From 1bbcc6123b7724dd5833b9bd7bc8669d0d0918c7 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Mon, 30 Sep 2024 17:47:21 +0800 Subject: [PATCH 024/166] feat: mac makeup & beauty shape fixed --- .../Advanced/VideoProcess/VideoProcess.swift | 4 +- .../Base.lproj/VideoProcess.storyboard | 100 ++-- .../Advanced/VideoProcess/VideoProcess.swift | 473 ++++++++++++++++++ .../en.lproj/VideoProcess.strings | 6 + .../zh-Hans.lproj/VideoProcess.strings | 6 + .../zh-Hans.lproj/Localizable.strings | 57 +++ 6 files changed, 605 insertions(+), 41 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift index 800aec983..8fe61f3cc 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift @@ -547,10 +547,10 @@ extension VideoProcessMain { if type == "slider" { let value = makeupList[i]["value"] as? [Float] ?? [] let sliderView = UISlider() - sliderView.value = makeupParams[key] as? Float ?? 0 label.text = String(format: "%@[%.f]", label.text ?? "none", sliderView.value) sliderView.minimumValue = value.first ?? 0 sliderView.maximumValue = value.last ?? 1 + sliderView.value = makeupParams[key] as? Float ?? 0 sliderView.addTarget(self, action: #selector(makeupSliderAction(_:)), for: .valueChanged) valueView = sliderView } else if type == "switch" { @@ -779,10 +779,10 @@ extension VideoProcessMain { if type == "slider" { let value = makeupList[i]["value"] as? [Float] ?? [] let sliderView = UISlider() - sliderView.value = beautyShapeParames[key] ?? 0 label.text = String(format: "%@[%.f]", label.text ?? "none", sliderView.value) sliderView.minimumValue = value.first ?? 0 sliderView.maximumValue = value.last ?? 100 + sliderView.value = beautyShapeParames[key] ?? 0 sliderView.addTarget(self, action: #selector(beautyShapeSliderAction(_:)), for: .valueChanged) valueView = sliderView } else if type == "switch" { diff --git a/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard b/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard index 18a36327d..0b96de735 100644 --- a/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard +++ b/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard @@ -1,8 +1,8 @@ - + - + @@ -29,34 +29,34 @@ - + - + - + - + - + - + - - + + @@ -65,14 +65,14 @@ - + - - + + @@ -81,14 +81,14 @@ - + - - + + @@ -97,22 +97,22 @@ - + - + - - + + @@ -121,15 +121,15 @@ - + - - + + @@ -137,8 +137,8 @@ - - + + @@ -147,14 +147,14 @@ - + - - + + @@ -163,15 +163,15 @@ - + - - + + @@ -180,15 +180,15 @@ - + - - + + @@ -196,8 +196,8 @@ - - + + @@ -206,7 +206,7 @@ - + @@ -214,13 +214,35 @@ - + + + @@ -230,7 +252,7 @@ - + + + + + + + + + + + + + + + + + + @@ -430,15 +449,16 @@ - + + @@ -450,6 +470,7 @@ + @@ -459,6 +480,7 @@ + @@ -476,6 +498,8 @@ + + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift index dca80ec67..ce9199629 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift @@ -177,6 +177,8 @@ class LiveStreamingMain: BaseViewController { @IBOutlet weak var centerStageContainerView: UIView! @IBOutlet weak var CameraFocalButton: UIButton! @IBOutlet weak var cameraStabilizationButton: UIButton? + @IBOutlet weak var localRenderTextField: UITextField? + @IBOutlet weak var remoteRenderTextField: UITextField? var remoteUid: UInt? { didSet { foregroundVideoContainer.isHidden = !(role == .broadcaster && remoteUid != nil) @@ -219,6 +221,9 @@ class LiveStreamingMain: BaseViewController { foregroundVideo.bindFrameToSuperviewBounds() backgroundVideo.bindFrameToSuperviewBounds() + localRenderTextField?.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged) + remoteRenderTextField?.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged) + let modeKey = stabilizationModeParams.first?.keys.first ?? "" cameraStabilizationButton?.setTitle("\("CameraStabilizationMode".localized) \(modeKey)", for: .normal) @@ -494,6 +499,24 @@ class LiveStreamingMain: BaseViewController { } } } + + @objc func textFieldDidChange(_ textField: UITextField) { + if let text = textField.text, let number = Int(text) { + if number > 60 { + textField.text = "60" + } else if number == 0 { + textField.text = "" + } + } else { + textField.text = "" + } + + if textField == localRenderTextField { + agoraKit.setLocalRenderTargetFps(.camera, targetFps: Int32(textField.text ?? "") ?? 15) + } else { + agoraKit.setRemoteRenderTargetFps(Int32(textField.text ?? "") ?? 15) + } + } } /// agora rtc engine delegate events diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings index d8bf37071..119273a49 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings @@ -20,3 +20,6 @@ "8kn-Rl-VMd.text" = "垫片推流"; "dZm-Rf-imt.normalTitle" = "相机对焦"; "ug1-fz-GYz.normalTitle" = "相机对焦"; + +"tOf-AP-HSe.placeholder"="本地渲染帧率(1-60),默认15"; +"UFF-wU-Wze.placeholder"="远端渲染帧率(1-60),默认15"; From 26a62d5c273e422f4f468c2067f8721935ee44da Mon Sep 17 00:00:00 2001 From: wushengtao Date: Tue, 8 Oct 2024 15:58:15 +0800 Subject: [PATCH 027/166] feat: add update render fps feature to Mac --- .../Base.lproj/LiveStreaming.storyboard | 4 +- .../Base.lproj/LiveStreaming.storyboard | 96 ++++++++++++++----- .../LiveStreaming/LiveStreaming.swift | 41 +++++++- .../zh-Hans.lproj/LiveStreaming.strings | 3 + 4 files changed, 115 insertions(+), 29 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard index 3462d5e3e..8fdf0555e 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard @@ -423,7 +423,7 @@ - + @@ -432,7 +432,7 @@ - + diff --git a/macOS/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard b/macOS/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard index 3d12b4a0c..58680debc 100644 --- a/macOS/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard +++ b/macOS/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard @@ -1,8 +1,8 @@ - + - + @@ -30,43 +30,43 @@ - + - + - + - + - + - + - + - + - + - + @@ -76,8 +76,8 @@ - - + + @@ -89,7 +89,7 @@ - + @@ -149,6 +149,15 @@ + + + + + + + + + @@ -159,11 +168,11 @@ - + - + @@ -191,6 +200,7 @@ + @@ -200,7 +210,7 @@ - + @@ -227,7 +237,7 @@ - + @@ -255,7 +265,7 @@ - + @@ -283,7 +293,7 @@ - + @@ -311,7 +321,7 @@ - + @@ -325,24 +335,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -350,6 +390,8 @@ + + @@ -360,6 +402,8 @@ + + diff --git a/macOS/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift b/macOS/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift index dbcf75bda..e78e460ab 100644 --- a/macOS/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift +++ b/macOS/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift @@ -322,7 +322,7 @@ class LiveStreamingMain: BaseViewController { Util.configPrivatization(agoraKit: agoraKit) agoraKit.enableVideo() - scrollView.documentView?.setFrameSize(CGSizeMake(314, 645)) + scrollView.documentView?.setFrameSize(CGSizeMake(314, 720)) initSelectCameraPicker() initSelectResolutionPicker() @@ -488,6 +488,14 @@ class LiveStreamingMain: BaseViewController { functionVC?.clickEncoderSegmentSwitch = { [weak self] s in self?.onTapEncoderSegment(s) } + + functionVC?.onChangeLocalRenderFps = { [weak self] fps in + self?.agoraKit.setLocalRenderTargetFps(.camera, targetFps: fps) + } + + functionVC?.onChangeRemoteRenderFps = { [weak self] fps in + self?.agoraKit.setRemoteRenderTargetFps(fps) + } } private func onTakeSnapshot() { @@ -568,6 +576,8 @@ class LiveStreamingMain: BaseViewController { encoderConfig.advancedVideoOptions = advancedOptions agoraKit.setVideoEncoderConfiguration(encoderConfig) } + + } class LiveStreamingRTCFunctionVC: BaseViewController { @@ -578,6 +588,8 @@ class LiveStreamingRTCFunctionVC: BaseViewController { var clickVideoImageSwitch: ((NSSwitch) -> Void)? var clickBFrameSwitch: ((NSSwitch) -> Void)? var clickEncoderSegmentSwitch: ((NSSegmentedControl) -> Void)? + var onChangeRemoteRenderFps: ((Int32)->())? + var onChangeLocalRenderFps: ((Int32)->())? @IBOutlet weak var snapShot: NSButton! @IBAction func onTakeSnapshot(_ sender: Any) { clickTakeSnapshotClosure?() @@ -613,6 +625,33 @@ class LiveStreamingRTCFunctionVC: BaseViewController { @IBAction func onTapEncoderSegment(_ sender: NSSegmentedControl) { clickEncoderSegmentSwitch?(sender) } + + // lcoal render fps editor + @IBOutlet weak var localRenderTextField: NSTextField? + + // remote render fps editor + @IBOutlet weak var remoteRenderTextField: NSTextField? +} + +extension LiveStreamingRTCFunctionVC: NSTextFieldDelegate { + func controlTextDidChange(_ obj: Notification) { + guard let textField = obj.object as? NSTextField else {return} + if let number = Int(textField.stringValue) { + if number > 60 { + textField.stringValue = "60" + } else if number == 0 { + textField.stringValue = "" + } + } else { + textField.stringValue = "" + } + + if textField == localRenderTextField { + self.onChangeLocalRenderFps?(Int32(textField.stringValue) ?? 15) + } else { + self.onChangeRemoteRenderFps?(Int32(textField.stringValue) ?? 15) + } + } } /// agora rtc engine delegate events diff --git a/macOS/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings b/macOS/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings index 764753351..71691c316 100644 --- a/macOS/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings +++ b/macOS/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings @@ -38,3 +38,6 @@ "gCs-hv-sr4.title" = "预加载"; "gBn-zJ-ZES.title" = "垫片推流"; + +"JyF-xa-die.placeholderString"="远端渲染帧率(1-60),默认15"; +"Ddt-E2-7gz.placeholderString"="本地渲染帧率(1-60),默认15"; From 0def999d66fcac869534d3b73b6d99a1dd4bd0cd Mon Sep 17 00:00:00 2001 From: wushengtao Date: Tue, 8 Oct 2024 17:06:06 +0800 Subject: [PATCH 028/166] feat: add set video scenario to iOS --- .../APIExample/Common/AgoraExtension.swift | 12 ++++++++++ .../APIExample/Common/AlertManager.swift | 22 +++++++++++++++++-- .../Base.lproj/LiveStreaming.storyboard | 17 +++++++++++--- .../LiveStreaming/LiveStreaming.swift | 19 ++++++++++++++++ .../zh-Hans.lproj/LiveStreaming.strings | 6 +++-- .../zh-Hans.lproj/Localizable.strings | 5 +++++ 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/iOS/APIExample/APIExample/Common/AgoraExtension.swift b/iOS/APIExample/APIExample/Common/AgoraExtension.swift index 7a3cf088e..e876879e8 100644 --- a/iOS/APIExample/APIExample/Common/AgoraExtension.swift +++ b/iOS/APIExample/APIExample/Common/AgoraExtension.swift @@ -327,3 +327,15 @@ extension AgoraFocalLengthInfo { } } } + +extension AgoraApplicationScenarioType { + func description() -> String { + switch self { + case .applicationGeneralScenario: return "General".localized + case .applicationMeetingScenario: return "Meeting".localized + case .application1V1Scenario: return "1v1".localized + case .applicationLiveShowScenario: return "Live Show".localized + @unknown default: return "" + } + } +} diff --git a/iOS/APIExample/APIExample/Common/AlertManager.swift b/iOS/APIExample/APIExample/Common/AlertManager.swift index 6a2cd0499..be3c8930e 100644 --- a/iOS/APIExample/APIExample/Common/AlertManager.swift +++ b/iOS/APIExample/APIExample/Common/AlertManager.swift @@ -8,8 +8,26 @@ import UIKit import AVFoundation -let cl_screenWidht = UIScreen.main.bounds.width -let cl_screenHeight = UIScreen.main.bounds.height +extension UIScreen { + static var currentScreenSize: CGSize { + // Get the main window's available size + guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { + return CGSize.zero + } + + // Calculate available width and height + let bounds = window.bounds + let insets = window.safeAreaInsets + + let width = bounds.width - insets.left - insets.right + let height = bounds.height - insets.top - insets.bottom + + return CGSize(width: width, height: height) + } +} + +let cl_screenWidht = UIScreen.currentScreenSize.width +let cl_screenHeight = UIScreen.currentScreenSize.height class AlertManager: NSObject { private struct AlertViewCache { var view: UIView? diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard index 8fdf0555e..19232d1ac 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard @@ -65,10 +65,10 @@ + @@ -88,11 +96,14 @@ + + + @@ -111,7 +122,7 @@ - + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift index ce9199629..09b18e334 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift @@ -14,6 +14,7 @@ class LiveStreamingEntry: UIViewController { @IBOutlet weak var preloadButton: UIButton! @IBOutlet weak var channelTextField: UITextField! @IBOutlet weak var cameraButton: UIButton? + @IBOutlet weak var videoScenarioButton: UIButton? let identifier = "LiveStreaming" var role: AgoraClientRole = .broadcaster private var isFirstFrame: Bool = false @@ -130,6 +131,24 @@ class LiveStreamingEntry: UIViewController { } } + @IBAction func onTapVideoScenarioButton(_ sender: UIButton) { + let pickerView = PickerView() + pickerView.dataArray = [ + AgoraApplicationScenarioType.applicationGeneralScenario.description(), + AgoraApplicationScenarioType.applicationMeetingScenario.description(), + AgoraApplicationScenarioType.application1V1Scenario.description(), + AgoraApplicationScenarioType.applicationLiveShowScenario.description() + ] + AlertManager.show(view: pickerView, alertPostion: .bottom) + pickerView.pickerViewSelectedValueClosure = { [weak self, weak pickerView] key in + guard let self = self else { return } + let idx = pickerView?.dataArray?.firstIndex(where: { $0 == key}) ?? 0 + let type = AgoraApplicationScenarioType(rawValue: idx) ?? .applicationGeneralScenario + self.agoraKit.setVideoScenario(type) + self.videoScenarioButton?.setTitle(key, for: .normal) + } + } + func doJoin() { guard let channelName = channelTextField.text else { return } let storyBoard: UIStoryboard = UIStoryboard(name: identifier, bundle: nil) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings index 119273a49..e9ffb68b1 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings @@ -21,5 +21,7 @@ "dZm-Rf-imt.normalTitle" = "相机对焦"; "ug1-fz-GYz.normalTitle" = "相机对焦"; -"tOf-AP-HSe.placeholder"="本地渲染帧率(1-60),默认15"; -"UFF-wU-Wze.placeholder"="远端渲染帧率(1-60),默认15"; +"ZB2-jf-zOV.normalTitle" = "视频业务场景"; + +"tOf-AP-HSe.placeholder" = "本地渲染帧率(1-60),默认15"; +"UFF-wU-Wze.placeholder" = "远端渲染帧率(1-60),默认15"; diff --git a/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings b/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings index ca0d9725a..23bc23d0a 100644 --- a/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings +++ b/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings @@ -185,6 +185,11 @@ "The camera has changed:" = "摄像头已改变:"; "CameraStabilizationMode" = "防抖:"; +"General"="通用场景"; +"Meeting"="会议场景"; +"1v1"="1v1 视频通话"; +"Live Show"="秀场直播"; + "Set_Voice_AI_Tuner"="设置AI调音器"; "AI_Tunner_Mature_Male"="大叔声"; "AI_Tunner_Fresh_Male"="清新男音"; From f23df2dcbc2cd32df9972bed1a727523c0db887b Mon Sep 17 00:00:00 2001 From: wushengtao Date: Tue, 8 Oct 2024 18:32:24 +0800 Subject: [PATCH 029/166] feat: add take local snapshot to iOS --- .../APIExample/Common/AgoraExtension.swift | 12 +++++ .../Base.lproj/LiveStreaming.storyboard | 44 ++++++++++++++----- .../LiveStreaming/LiveStreaming.swift | 26 ++++++++++- .../zh-Hans.lproj/LiveStreaming.strings | 3 +- 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/iOS/APIExample/APIExample/Common/AgoraExtension.swift b/iOS/APIExample/APIExample/Common/AgoraExtension.swift index e876879e8..a8be4e36d 100644 --- a/iOS/APIExample/APIExample/Common/AgoraExtension.swift +++ b/iOS/APIExample/APIExample/Common/AgoraExtension.swift @@ -339,3 +339,15 @@ extension AgoraApplicationScenarioType { } } } + +extension AgoraVideoModulePosition { + func description() -> String { + switch self { + case .postCapture: return "Post Capture".localized + case .preRenderer: return "PreRenderer".localized + case .preEncoder: return "PreEncoder".localized + case .postCaptureOrigin: return "Post Capture Origin".localized + @unknown default: return "" + } + } +} diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard index 19232d1ac..b56f3a06b 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard @@ -318,16 +318,14 @@ - + + + + - + + @@ -467,6 +489,7 @@ + @@ -486,10 +509,11 @@ - + + diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift index 09b18e334..04b3c45ef 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift @@ -144,7 +144,8 @@ class LiveStreamingEntry: UIViewController { guard let self = self else { return } let idx = pickerView?.dataArray?.firstIndex(where: { $0 == key}) ?? 0 let type = AgoraApplicationScenarioType(rawValue: idx) ?? .applicationGeneralScenario - self.agoraKit.setVideoScenario(type) + let ret = self.agoraKit.setVideoScenario(type) + print("setVideoScenario[\(type.rawValue)] ret = \(ret)") self.videoScenarioButton?.setTitle(key, for: .normal) } } @@ -458,6 +459,29 @@ class LiveStreamingMain: BaseViewController { agoraKit.takeSnapshot(Int(remoteUid), filePath: path) showAlert(title: "Screenshot successful".localized, message: path) } + + @IBAction func onTakeLocalSnapshot(_ sender: Any) { + let pickerView = PickerView() + let values: [AgoraVideoModulePosition] = [ +// .postCapture, + .preRenderer, + .preEncoder, + .postCaptureOrigin + ] + pickerView.dataArray = values.map({ $0.description()}) + AlertManager.show(view: pickerView, alertPostion: .bottom) + pickerView.pickerViewSelectedValueClosure = { [weak self, weak pickerView] key in + guard let self = self else { return } + let idx = pickerView?.dataArray?.firstIndex(where: { $0 == key}) ?? 0 + let position = values[idx] + let config = AgoraSnapshotConfig() + config.position = position + config.filePath = NSTemporaryDirectory().appending("local_\(position.rawValue).png") + let ret = agoraKit.takeSnapshotWithConfig(0, config: config) + print("takeSnapshot ret: \(ret) path: \(config.filePath ?? "")") + showAlert(title: "Screenshot successful".localized, message: config.filePath ?? "") + } + } @IBAction func onTapForegroundVideo(_ sender: UIGestureRecognizer) { isLocalVideoForeground = !isLocalVideoForeground let localVideoCanvas = AgoraRtcVideoCanvas() diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings index e9ffb68b1..0ff252ddd 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings @@ -9,7 +9,8 @@ /* Class = "UIButton"; normalTitle = "Join"; ObjectID = "kbN-ZR-nNn"; */ "kbN-ZR-nNn.normalTitle" = "加入频道"; -"w4q-aT-JBc.normalTitle" = "截图"; +"w4q-aT-JBc.normalTitle" = "本地截图"; +"lpn-6Z-VV3.normalTitle" = "远端截图"; "ohV-am-Acd.text" = "首帧出图"; From 1628cc2684f64cee3b97d911065349b73faa7353 Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 9 Oct 2024 12:19:07 +0800 Subject: [PATCH 030/166] feat: add record before join channel --- .../zh-Hans.lproj/LiveStreaming.strings | 1 - .../JoinChannelVideoRecorder.storyboard | 19 ++++++- .../JoinChannelVideoRecorder.swift | 50 +++++++++++++++++-- .../zh-Hans.lproj/Localizable.strings | 2 + 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings index 0ff252ddd..07532f2d2 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings +++ b/iOS/APIExample/APIExample/Examples/Advanced/LiveStreaming/zh-Hans.lproj/LiveStreaming.strings @@ -17,7 +17,6 @@ "Q0N-nV-bez.normalTitle" = "默认背景色"; "S19-UR-C2c.normalTitle" = "预加载"; -"S19-UR-C2c.selectTitle" = "取消预加载"; "8kn-Rl-VMd.text" = "垫片推流"; "dZm-Rf-imt.normalTitle" = "相机对焦"; "ug1-fz-GYz.normalTitle" = "相机对焦"; diff --git a/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/Base.lproj/JoinChannelVideoRecorder.storyboard b/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/Base.lproj/JoinChannelVideoRecorder.storyboard index ad4c20098..5fa45d957 100644 --- a/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/Base.lproj/JoinChannelVideoRecorder.storyboard +++ b/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/Base.lproj/JoinChannelVideoRecorder.storyboard @@ -1,9 +1,9 @@ - + - + @@ -76,17 +76,32 @@ + + + + diff --git a/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift b/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift index cb92323ef..ec2d1d5ad 100644 --- a/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift +++ b/iOS/APIExample/APIExample/Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift @@ -105,6 +105,8 @@ class JoinChannelVideoRecorderEntry: UIViewController { } class JoinChannelVideoRecorder: BaseViewController { + private var channelName: String? + @IBOutlet var joinOrLeaveButton: UIButton? private lazy var localRecordButton: UIButton = { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false @@ -144,6 +146,16 @@ class JoinChannelVideoRecorder: BaseViewController { remoteRecordButton.isHidden = remoteUid == 0 } } + private lazy var localPreviewRecord: AgoraMediaRecorder? = { + let streamInfo = AgoraRecorderStreamInfo() + streamInfo.channelId = title ?? "" + streamInfo.uid = localUid + streamInfo.type = .preview + let record = agoraKit.createMediaRecorder(withInfo: streamInfo) + record?.setMediaRecorderDelegate(self) + return record + }() + private lazy var localRecord: AgoraMediaRecorder? = { let streamInfo = AgoraRecorderStreamInfo() streamInfo.channelId = title ?? "" @@ -188,6 +200,9 @@ class JoinChannelVideoRecorder: BaseViewController { remoteRecordButton.widthAnchor.constraint(equalToConstant: 70).isActive = true remoteRecordButton.heightAnchor.constraint(equalToConstant: 30).isActive = true + joinOrLeaveButton?.setTitle("Leave Channel".localized, for: .selected) + joinOrLeaveButton?.setTitle("Join Channel".localized, for: .normal) + setupRTC() } @@ -208,6 +223,7 @@ class JoinChannelVideoRecorder: BaseViewController { let resolution = configs["resolution"] as? CGSize, let fps = configs["fps"] as? Int, let orientation = configs["orientation"] as? AgoraVideoOutputOrientationMode else {return} + self.channelName = channelName // make myself a broadcaster agoraKit.setClientRole(GlobalSettings.shared.getUserRole()) @@ -232,6 +248,10 @@ class JoinChannelVideoRecorder: BaseViewController { // Set audio route to speaker agoraKit.setDefaultAudioRouteToSpeakerphone(true) +// joinChannel(channelName: channelName) + } + + private func joinChannel(channelName: String) { // start joining channel // 1. Users can only see each other after they join the // same channel successfully using the same app id. @@ -276,16 +296,28 @@ class JoinChannelVideoRecorder: BaseViewController { @objc private func onTapLocalRecordButton(sender: UIButton) { sender.isSelected = !sender.isSelected - let path = storagePath + "/\(localUid).mp4" + var path: String? = nil + var recorder: AgoraMediaRecorder? = nil + if joinOrLeaveButton?.isSelected ?? false == true { + path = storagePath + "/\(localUid).mp4" + recorder = localRecord + } else { + path = storagePath + "/preview_\(localUid).mp4" + recorder = localPreviewRecord + agoraKit.startRecordingDeviceTest(500) + } + guard let path = path, let recorder = recorder else {return} if sender.isSelected { let config = AgoraMediaRecorderConfiguration() config.storagePath = path config.containerFormat = .MP4 config.maxDurationMs = 10 * 1000 - localRecord?.startRecording(config) + let ret = recorder.startRecording(config) + print("startRecording: \(ret)") } else { - localRecord?.stopRecording() + let ret = recorder.stopRecording() ToastView.show(text: path) + print("stopRecording: \(ret) path = \(path)") } } @objc @@ -307,6 +339,18 @@ class JoinChannelVideoRecorder: BaseViewController { deinit { AgoraRtcEngineKit.destroy() } + + @IBAction func onJoinOrLeave(sender: UIButton) { + sender.isSelected.toggle() + + if sender.isSelected { + print("join channel") + joinChannel(channelName: channelName ?? "") + } else { + print("leave channel") + agoraKit.leaveChannel() + } + } } extension JoinChannelVideoRecorder: AgoraMediaRecorderDelegate { diff --git a/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings b/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings index 23bc23d0a..017fec63f 100644 --- a/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings +++ b/iOS/APIExample/APIExample/zh-Hans.lproj/Localizable.strings @@ -156,6 +156,8 @@ "Tap to place remote video canvas" = "点击屏幕以放置视频画布"; "Recording" = "开始录制"; "Stop Recording" = "停止录制"; +"Join Channel" = "加入频道"; +"Leave Channel" = "离开频道"; "PIP Support iOS 15+" = "画中画只支持iOS15及以上版本"; "Red" = "红色"; "Blue" = "蓝色"; From a38228f7137930aacbd25d0ebca45734e7f1a86c Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 9 Oct 2024 16:11:52 +0800 Subject: [PATCH 031/166] feat: add whitening process to iOS --- .../Base.lproj/VideoProcess.storyboard | 270 ++++++++++-------- .../Advanced/VideoProcess/VideoProcess.swift | 33 ++- .../zh-Hans.lproj/VideoProcess.strings | 3 + .../Base.lproj/LiveStreaming.storyboard | 18 +- 4 files changed, 194 insertions(+), 130 deletions(-) diff --git a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard index a8bd90dbb..58b662400 100644 --- a/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard +++ b/iOS/APIExample/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard @@ -94,82 +94,149 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + @@ -305,28 +368,26 @@ - + - + @@ -359,7 +359,7 @@ - + From 3ba5623a59527ebbe6b6112cc543eea9f9f88e3b Mon Sep 17 00:00:00 2001 From: wushengtao Date: Wed, 9 Oct 2024 16:28:04 +0800 Subject: [PATCH 032/166] feat: add whitening process to Mac --- .../Base.lproj/VideoProcess.storyboard | 100 +++++++++++------- .../Advanced/VideoProcess/VideoProcess.swift | 17 ++- .../en.lproj/VideoProcess.strings | 5 +- .../zh-Hans.lproj/VideoProcess.strings | 2 + 4 files changed, 79 insertions(+), 45 deletions(-) diff --git a/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard b/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard index 18a36327d..88dd0a683 100644 --- a/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard +++ b/macOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard @@ -1,8 +1,8 @@ - + - + @@ -29,34 +29,34 @@ - + - + - + - + - + - + - - + + @@ -65,14 +65,14 @@ - + - - + + @@ -81,14 +81,14 @@ - + - - + + @@ -97,22 +97,22 @@ - + - + - - + + @@ -121,15 +121,15 @@ - + - - + + @@ -137,8 +137,8 @@ - - + + @@ -147,14 +147,14 @@ - + - - + + @@ -163,15 +163,15 @@ - + - + - - + + @@ -180,15 +180,15 @@ - + - - + + @@ -196,8 +196,8 @@ - - + + @@ -206,7 +206,7 @@ - + @@ -214,13 +214,30 @@ - + + + + + + + + + + + + + + + + + + @@ -230,7 +247,7 @@ - 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