问题描述
我正在尝试将视频聊天和 Agora 媒体播放器套件集成到一个应用程序中(使用 API-Examples 项目作为起点),但我遇到了一个我无法解决的错误:通话开始后,没有可用的麦克风音频。其他非媒体播放器功能仍然有效,但奇怪的是,如果选择了 MediaPlayer,则所有视图/功能的音频都将被禁用,直到应用程序关闭并重新打开。除了将视频添加到环境中之外,我没有做任何更改。媒体音频仍然有效,因此所有音频都不会丢失(只是没有麦克风音频,该应用甚至会要求麦克风许可)。
import UIKit
import AGEVideoLayout
import AgoraRtcKit
import AgoraMediaPlayer
class MediaPlayerEntry : UIViewController
{
@IBOutlet weak var joinButton: UIButton!
@IBOutlet weak var channelTextField: UITextField!
let identifier = "MediaPlayer"
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func doJoinpressed(sender: UIButton) {
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]
self.navigationController?.pushViewController(newViewController,animated: true)
}
}
class MediaPlayerMain: BaseViewController {
var localVideo = Bundle.loadView(fromNib: "VideoView",withType: VideoView.self)
var remoteVideo = Bundle.loadView(fromNib: "VideoView",withType: VideoView.self)
var localMedia = Bundle.loadView(fromNib: "VideoView",withType: VideoView.self)
@IBOutlet weak var container: AGEVideoContainer!
@IBOutlet weak var mediaUrlField: UITextField!
@IBOutlet weak var playerControlStack: UIStackView!
@IBOutlet weak var playerProgressSlider: UiSlider!
@IBOutlet weak var playerVolumeSlider: UiSlider!
@IBOutlet weak var playerDurationLabel: UILabel!
var agoraKit: AgoraRtcEngineKit!
var mediaPlayerKit: AgoraMediaPlayer!
var timer:Timer?
// indicate if current instance has joined channel
var isJoined: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// layout render view
localVideo.setPlaceholder(text: "No Player Loaded")
remoteVideo.setPlaceholder(text: "Remote Host".localized)
container.layoutStream1x2(views: [localVideo,remoteVideo])
// set up agora instance when view loadedlet config = AgoraRtcEngineConfig()
let config = AgoraRtcEngineConfig()
config.appId = KeyCenter.AppId
config.areaCode = GlobalSettings.shared.area.rawValue
// setup log file path
let logConfig = AgoraLogConfig()
logConfig.level = .info
config.logConfig = logConfig
agoraKit = AgoraRtcEngineKit.sharedEngine(with: config,delegate: self)
// 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}
// become a live broadcaster
agoraKit.setChannelProfile(.livebroadcasting)
agoraKit.setClientRole(.broadcaster)
// enable video module and set up video encoding configs
agoraKit.enableAudio()
agoraKit.enableVideo()
agoraKit.setVideoEncoderConfiguration(AgoravideoEncoderConfiguration(size: resolution,frameRate: fps,bitrate: AgoravideoBitrateStandard,orientationMode: orientation))
// prepare media player
mediaPlayerKit = AgoraMediaPlayer(delegate: self)
// attach player to agora rtc kit,so that the media stream can be published
AgoraRtcChannelPublishHelper.shareInstance().attachPlayer(toRtc: mediaPlayerKit,rtcEngine: agoraKit,enableVideoSource: true)
AgoraRtcChannelPublishHelper.shareInstance().register(self)
// set media local play view
mediaPlayerKit.setView(localMedia.videoView)
// 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()
let result = agoraKit.joinChannel(byToken: KeyCenter.Token,channelId: channelName,info: nil,uid: 0,options: option)
if result != 0 {
// Usually happens with invalid parameters
// Error code description can be found at:
// en: https://docs.agora.io/en/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
self.showAlert(title: "Error",message: "joinChannel call Failed: \(result),please check your params")
}
}
@IBAction func doOpenMediaUrl(sender: UIButton) {
guard let url = mediaUrlField.text else {return}
//resign text field
mediaUrlField.resignFirstResponder()
mediaPlayerKit.open(url,startPos: 0)
}
@IBAction func doPlay(sender: UIButton) {
mediaPlayerKit.play()
}
@IBAction func doStop(sender: UIButton) {
mediaPlayerKit.stop()
}
@IBAction func doPause(sender: UIButton) {
mediaPlayerKit.pause()
}
@IBAction func doPublish(sender: UIButton) {
AgoraRtcChannelPublishHelper.shareInstance().publishVideo()
AgoraRtcChannelPublishHelper.shareInstance().publishAudio()
}
@IBAction func doUnpublish(sender: UIButton) {
AgoraRtcChannelPublishHelper.shareInstance().unpublishVideo()
AgoraRtcChannelPublishHelper.shareInstance().unpublishAudio()
}
@IBAction func doSeek(sender: UiSlider) {
mediaPlayerKit.seek(toPosition: Int(sender.value * Float(mediaPlayerKit.getDuration())))
}
@IBAction func doAdjustPlayoutVolume(sender: UiSlider) {
AgoraRtcChannelPublishHelper.shareInstance().adjustPlayoutSignalVolume(Int32(Int(sender.value)))
}
@IBAction func doAdjustPublishVolume(sender: UiSlider) {
AgoraRtcChannelPublishHelper.shareInstance().adjustPublishSignalVolume(Int32(Int(sender.value)))
}
func startProgresstimer() {
// begin timer to update progress
if(timer == nil) {
timer = Timer.scheduledTimer(withTimeInterval: 0.5,repeats: true,block: { [weak self](timer:Timer) in
guard let weakself = self else {return}
let progress = Float(weakself.mediaPlayerKit.getPlayPosition()) / Float(weakself.mediaPlayerKit.getDuration())
if(!weakself.playerProgressSlider.isTouchInside) {
weakself.playerProgressSlider.setValue(progress,animated: true)
}
})
}
}
func stopProgresstimer() {
// stop timer
if(timer != nil) {
timer?.invalidate()
timer = nil
}
}
override func willMove(toParent parent: UIViewController?) {
if parent == nil {
// leave channel when exiting the view
// deregister packet processing
AgoraCustomEncryption.deregisterPacketProcessing(agoraKit)
if isJoined {
agoraKit.leaveChannel { (stats) -> Void in
LogUtils.log(message: "left channel,duration: \(stats.duration)",level: .info)
}
}
}
}
}
/// agora rtc engine delegate events
extension MediaPlayerMain: 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://docs.agora.io/en/Voice/API%20Reference/oc/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://docs.agora.io/en/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
/// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
/// @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)
// 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 = remoteVideo.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)
}
}
extension MediaPlayerMain: AgoraMediaPlayerDelegate
{
}
extension MediaPlayerMain: AgoraRtcChannelPublishHelperDelegate
{
func agoraRtcChannelPublishHelperDelegate(_ playerKit: AgoraMediaPlayer,didChangedTo state: AgoraMediaPlayerState,error: AgoraMediaPlayerError) {
LogUtils.log(message: "player rtc channel publish helper state changed to: \(state.rawValue),error: \(error.rawValue)",level: .info)
dispatchQueue.main.async {[weak self] in
guard let weakself = self else {return}
switch state {
case .Failed:
weakself.showAlert(message: "media player error: \(error.rawValue)")
break
case .openCompleted:
let duration = weakself.mediaPlayerKit.getDuration()
weakself.playerControlStack.isHidden = false
weakself.playerDurationLabel.text = "\(String(format: "%02d",duration / 60)) : \(String(format: "%02d",duration % 60))"
break
case .stopped:
weakself.playerControlStack.isHidden = true
weakself.stopProgresstimer()
break
case .idle: break
case .opening: break
case .playing:
weakself.startProgresstimer()
break
case .paused:
weakself.stopProgresstimer()
break;
case .playBackCompleted:
weakself.stopProgresstimer()
break
default: break
}
}
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)