-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
qinhui
committed
Oct 9, 2024
1 parent
61a95a4
commit 97f7c01
Showing
6 changed files
with
236 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
...le-SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() | ||
} |
143 changes: 143 additions & 0 deletions
143
...SwiftUI/APIExample-SwiftUI/Examples/Advanced/CustomAudioRender/CustomAudioRenderRTC.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters