Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions EaseCallUIKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'EaseCallUIKit'
s.version = '4.16.0'
s.version = '4.17.0'
s.summary = 'A short description of EaseCallUIKit.'

# This description is used to generate tags and improve search results.
Expand Down Expand Up @@ -42,6 +42,6 @@ TODO: Add long description of the pod here.
# s.public_header_files = 'Pod/Classes/**/*.h'
s.frameworks = 'UIKit', 'Foundation', 'Combine', 'AudioToolbox', 'AVFoundation','AVKit', 'CoreMedia', 'CoreVideo', 'CoreGraphics'

s.dependency 'HyphenateChat','>= 4.16.0'
s.dependency 'AgoraRtcEngine_iOS/RtcBasic', '~> 4.5.0'
s.dependency 'HyphenateChat','>= 4.17.0'
s.dependency 'AgoraRtcEngine_iOS/RtcBasic', '~> 4.6.0'
end
Original file line number Diff line number Diff line change
Expand Up @@ -638,24 +638,16 @@ extension CallKitManager: AgoraRtcEngineDelegate {
}

public func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) {//On audio volume indication change of speakers
if let call = self.callInfo {
if call.type == .groupCall {// Only handle audio volume indication in multi call
var speakerInfos = [UInt:UInt]()
for speaker in speakers {
speakerInfos[speaker.uid] = speaker.volume
}
let uids = speakers.map { NSNumber(value: $0.uid != 0 ? UInt32($0.uid):self.currentUserRTCUID) }
ChatClient.shared().getUserId(byRTCUIds: uids) { [weak self] relations, error in
guard let `self` = self else { return }
if error == nil {
let relationships = relations ?? [:]
for ship in relationships {
if let streamView = self.canvasCache[ship.value],streamView.item.uid == UInt32(truncating: ship.key) {
streamView.updateAudioVolume(speakerInfos[UInt(streamView.item.uid)] ?? 0)
DispatchQueue.main.async {
if let call = self.callInfo {
if call.type == .groupCall {// Only handle audio volume indication in multi call
for speaker in speakers {
if let item = self.itemsCache.values.first(where: { $0.uid == speaker.uid }) {
let streamView = self.canvasCache[item.userId]
if item.uid == speaker.uid {
streamView?.updateAudioVolume(speaker.volume)
}
}
} else {
consoleLogInfo("Failed to get userId by RTC UIDs: \(error?.errorDescription ?? "Unknown error")", type: .error)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public let CallKitVersion = "1.0.0"
}
self.engine?.enableAudio()
self.engine?.enable(inEarMonitoring: true)
self.engine?.enableAudioVolumeIndication(618, smooth: 10, reportVad: true)
self.engine?.enableAudioVolumeIndication(618, smooth: 5, reportVad: true)
self.engine?.setDefaultAudioRouteToSpeakerphone(true)
self.engine?.setVideoFrameDelegate(self)
return nil
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ import UIKit
self.nickName.text = nickName
self.nickName.font = UIFont.callTheme.labelLarge
self.avatar.image(with: profile.avatarURL, placeHolder: CallAppearance.avatarPlaceHolder)
self.checkbox.image = UIImage(named: profile.selected ? "select":"unselect", in: .callBundle, compatibleWith: nil)
if let user = CallKitManager.shared.itemsCache[profile.id] {
self.checkbox.image = UIImage(named: "already_seleted", in: .callBundle, compatibleWith: nil)
} else {
self.checkbox.image = UIImage(named: profile.selected ? "select":"unselect", in: .callBundle, compatibleWith: nil)
}
self.separatorLine.backgroundColor = Theme.style == .dark ? UIColor.callTheme.neutralColor2:UIColor.callTheme.neutralColor9
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ extension Call1v1VideoViewController: AVPictureInPictureControllerDelegate {
UIApplication.shared.call.keyWindow?.rootViewController?.present(existingVC, animated: true) {
// 将floatView恢复到existingVC
existingVC.ensureFloatViewVisible()
existingVC.floatViewClicked(dragView: existingVC.floatView)
completionHandler(true)
}
} else {
Expand All @@ -683,6 +684,7 @@ extension Call1v1VideoViewController: AVPictureInPictureControllerDelegate {
UIApplication.shared.call.keyWindow?.rootViewController?.present(self, animated: true) {
// 恢复floatView
self.ensureFloatViewVisible()
self.floatViewClicked(dragView: self.floatView)
completionHandler(true)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ import UIKit
}))
}
self.participants.removeAll { $0.id == ChatClient.shared().currentUsername ?? "" }
self.participants.removeAll { self.excludeUsers.contains($0.id) }
DispatchQueue.main.async {
self.participantsList.reloadData()
}
Expand Down Expand Up @@ -202,6 +201,9 @@ extension MultiCallParticipantsController: UITableViewDelegate,UITableViewDataSo

@objc open func didSelectRowAt(indexPath: IndexPath) {
if let profile = self.participants[safely: indexPath.row] {
if let user = CallKitManager.shared.itemsCache[profile.id] {
return
}
profile.selected = !profile.selected
self.participantsList.reloadData()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ public class Call1v1BottomView: UIView {
// MARK: - Actions
private func handleButtonTap(_ sender: CallButtonView) {
// Haptic feedback
UIImpactFeedbackGenerator.impactOccurred(style: .light)
UIImpactFeedbackGenerator.impactOccurred(style: .medium)
print("tag: \(sender.buttonTag)")

guard let data = sender.data, let buttonType = self.getActionType(for: data, button: sender) else { return }
Expand Down
103 changes: 71 additions & 32 deletions Sources/EaseCallUIKit/Classes/UI/Views/CallStreamView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class CallStreamView: UIImageView {
private let loadingView = UIImageView().contentMode(.scaleAspectFit)
public let userInfoView = UserInfoView()

var displayMode: UserInfoDisplayMode = .all {
var displayMode: UserInfoDisplayMode = .nameOnly {
didSet {
userInfoView.displayMode = displayMode
if self.item.isExpanded {
Expand Down Expand Up @@ -215,7 +215,26 @@ public class CallStreamView: UIImageView {
}

func updateAudioVolume(_ volume: UInt) {
self.userInfoView.isSpeaking = volume > 10 // Adjust threshold as needed
if self.item.waiting {
return
}
// 设置说话状态
self.userInfoView.isSpeaking = volume > 0

// 根据音量动态调整显示模式
if volume > 0 && !self.item.audioMuted {
// 有音量且未静音时,显示音频图标
if self.userInfoView.displayMode == .nameOnly {
self.userInfoView.displayMode = .all
}
} else if volume == 0 && !self.item.audioMuted {
// 无音量且未静音时,隐藏音频图标(仅显示昵称)
if self.userInfoView.displayMode == .all {
self.userInfoView.displayMode = .nameOnly
}
}

// 清理覆盖视图
coverView.isHidden = true
coverView.removeFromSuperview()
}
Expand Down Expand Up @@ -289,6 +308,15 @@ public class CallStreamItem: NSObject {
}

}
// MARK: - User Info Component
// MARK: - Display Mode
public enum UserInfoDisplayMode {
case all // 显示昵称和按钮
case nameOnly // 只显示昵称
case buttonsOnly // 只显示按钮
case hidden // 完全隐藏
}

// MARK: - User Info Component
public class UserInfoView: UIView {

Expand All @@ -300,7 +328,7 @@ public class UserInfoView: UIView {
private var containerTrailingConstraint: NSLayoutConstraint?
private var nicknameLabelWidthConstraint: NSLayoutConstraint?

var displayMode: UserInfoDisplayMode = .all {
var displayMode: UserInfoDisplayMode = .nameOnly {
didSet {
updateDisplayMode()
}
Expand All @@ -318,13 +346,35 @@ public class UserInfoView: UIView {
}
}

var isSpeaking: Bool = false {
@MainActor var isSpeaking: Bool = false {
didSet {
if isSpeaking,!isAudioMuted {
if isSpeaking && !isAudioMuted {
// 正在说话且未静音时显示说话图标
audioButton.setImage(UIImage(named: "speaking", in: .callBundle, with: nil), for: .normal)
audioButton.isHidden = false

// 动态更新约束以显示音频按钮
containerStackView.spacing = 6
setNeedsUpdateConstraints()

} else if !isSpeaking && !isAudioMuted {
// 不说话且未静音时清空图标
audioButton.setImage(nil, for: .normal)
audioButton.isHidden = true

// 动态更新约束以隐藏音频按钮
containerStackView.spacing = 0
setNeedsUpdateConstraints()

} else {
// 静音状态保持原有逻辑
updateAudioButton()
}

// 触发布局更新
invalidateIntrinsicContentSize()
setNeedsLayout()
layoutIfNeeded()
}
}

Expand Down Expand Up @@ -405,7 +455,7 @@ public class UserInfoView: UIView {
if isAudioMuted {
audioButton.setImage(UIImage(systemName: "mic.slash.fill"), for: .normal)
} else {
audioButton.setImage(UIImage(systemName: "mic.fill"), for: .normal)
audioButton.setImage(nil, for: .normal)
}
}

Expand All @@ -421,6 +471,16 @@ public class UserInfoView: UIView {
containerStackView.spacing = 6
nicknameLabelWidthConstraint?.constant = 80

case .nameOnly:
// 只显示昵称,隐藏音频按钮
nicknameLabel.isHidden = false
audioButton.isHidden = true
self.isHidden = false

// 移除间距,因为没有按钮
containerStackView.spacing = 0
nicknameLabelWidthConstraint?.constant = 80

case .buttonsOnly:
// 只显示按钮
nicknameLabel.isHidden = true
Expand All @@ -438,7 +498,6 @@ public class UserInfoView: UIView {
// 触发布局更新
setNeedsLayout()
layoutIfNeeded()

}

// 重写 intrinsicContentSize 以支持自动布局
Expand All @@ -460,13 +519,6 @@ public class UserInfoView: UIView {
}
}

// MARK: - Display Mode
public enum UserInfoDisplayMode {
case all // 显示昵称和按钮
case buttonsOnly // 只显示按钮
case hidden // 完全隐藏
}

// MARK: - 便利方法
extension UserInfoView {

Expand All @@ -485,6 +537,11 @@ extension UserInfoView {
let nicknameWidth = min(nicknameLabel.intrinsicContentSize.width, 80)
return 6 + nicknameWidth + 6 + 16 + 6 // padding + nickname + spacing + button + padding

case .nameOnly:
// 只有昵称,没有音频按钮
let nicknameWidth = min(nicknameLabel.intrinsicContentSize.width, 80)
return 6 + nicknameWidth + 6 // padding + nickname + padding

case .buttonsOnly:
return 6 + 16 + 6 // padding + button + padding

Expand All @@ -505,21 +562,3 @@ extension UserInfoView {
})
}
}

// MARK: - 调试辅助
#if DEBUG
extension UserInfoView {

/// 添加边框以便调试
public func enableDebugMode() {
layer.borderWidth = 1
layer.borderColor = UIColor.red.cgColor

nicknameLabel.layer.borderWidth = 0.5
nicknameLabel.layer.borderColor = UIColor.green.cgColor

audioButton.layer.borderWidth = 0.5
audioButton.layer.borderColor = UIColor.blue.cgColor
}
}
#endif
Loading