mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-17 20:08:31 +00:00
Add a screen-sharing video preview to the call view
This commit is contained in:
parent
127e12b384
commit
9524c6f2f3
6 changed files with 140 additions and 66 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
public enum AppGitInfo {
|
||||
public static let branch = "master"
|
||||
public static let commit = "b84bd1faf"
|
||||
public static let branch = "feature/screen_sharing"
|
||||
public static let commit = "1dc5dec22"
|
||||
public static let tag = "6.1.0-alpha"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,22 +167,24 @@ class TelecomManager: ObservableObject {
|
|||
}
|
||||
|
||||
func doCallOrJoinConf(address: Address, isVideo: Bool = false, isConference: Bool = false) {
|
||||
if address.asStringUriOnly().hasPrefix("sip:conference-focus@sip.linphone.org") {
|
||||
do {
|
||||
let meetingAddress = try Factory.Instance.createAddress(addr: address.asStringUriOnly())
|
||||
|
||||
DispatchQueue.main.async {
|
||||
withAnimation {
|
||||
self.meetingWaitingRoomDisplayed = true
|
||||
self.meetingWaitingRoomSelected = meetingAddress
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
} else {
|
||||
doCallWithCore(
|
||||
addr: address, isVideo: isVideo, isConference: isConference
|
||||
)
|
||||
}
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
if let _ = core.findConferenceInformationFromUri(uri: address) {
|
||||
do {
|
||||
let meetingAddress = try Factory.Instance.createAddress(addr: address.asStringUriOnly())
|
||||
|
||||
DispatchQueue.main.async {
|
||||
withAnimation {
|
||||
self.meetingWaitingRoomDisplayed = true
|
||||
self.meetingWaitingRoomSelected = meetingAddress
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
} else {
|
||||
self.doCallWithCore(
|
||||
addr: address, isVideo: isVideo, isConference: isConference
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doCallWithCore(addr: Address, isVideo: Bool, isConference: Bool) {
|
||||
|
|
|
|||
|
|
@ -607,9 +607,9 @@ struct CallView: View {
|
|||
}
|
||||
} else if callViewModel.isConference && !telecomManager.outgoingCallStarted && callViewModel.activeSpeakerParticipant != nil {
|
||||
let heightValue = (fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom)
|
||||
if optionsChangeLayout == 1 && callViewModel.participantList.count <= 5 {
|
||||
if optionsChangeLayout == 1 && callViewModel.participantList.count <= 5 && callViewModel.activeSpeakerParticipant?.isScreenSharing == false {
|
||||
mosaicMode(geometry: geometry, height: heightValue)
|
||||
} else if optionsChangeLayout == 3 {
|
||||
} else if optionsChangeLayout == 3 && callViewModel.activeSpeakerParticipant?.isScreenSharing == false {
|
||||
audioOnlyMode(geometry: geometry, height: heightValue)
|
||||
} else {
|
||||
activeSpeakerMode(geometry: geometry)
|
||||
|
|
@ -990,7 +990,7 @@ struct CallView: View {
|
|||
.cornerRadius(20)
|
||||
|
||||
ForEach(0..<callViewModel.participantList.count, id: \.self) { index in
|
||||
if callViewModel.activeSpeakerParticipant != nil && !callViewModel.participantList[index].address.equal(address2: callViewModel.activeSpeakerParticipant!.address) {
|
||||
if callViewModel.activeSpeakerParticipant != nil && (!callViewModel.participantList[index].address.weakEqual(address2: callViewModel.activeSpeakerParticipant!.address) || callViewModel.activeSpeakerParticipant!.isScreenSharing) {
|
||||
ZStack {
|
||||
if callViewModel.participantList[index].isJoining {
|
||||
VStack {
|
||||
|
|
@ -1040,7 +1040,7 @@ struct CallView: View {
|
|||
LinphoneVideoViewHolder { view in
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if index < callViewModel.participantList.count {
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.equal(address2: callViewModel.participantList[index].address)})
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.weakEqual(address2: callViewModel.participantList[index].address)})
|
||||
if participantVideo != nil && participantVideo!.devices.first != nil {
|
||||
participantVideo!.devices.first!.nativeVideoWindowId = UnsafeMutableRawPointer(Unmanaged.passRetained(view).toOpaque())
|
||||
}
|
||||
|
|
@ -1160,7 +1160,7 @@ struct CallView: View {
|
|||
.cornerRadius(20)
|
||||
|
||||
ForEach(0..<callViewModel.participantList.count, id: \.self) { index in
|
||||
if callViewModel.activeSpeakerParticipant != nil && !callViewModel.participantList[index].address.equal(address2: callViewModel.activeSpeakerParticipant!.address) {
|
||||
if callViewModel.activeSpeakerParticipant != nil && (!callViewModel.participantList[index].address.weakEqual(address2: callViewModel.activeSpeakerParticipant!.address) || callViewModel.activeSpeakerParticipant!.isScreenSharing) {
|
||||
ZStack {
|
||||
if callViewModel.participantList[index].isJoining {
|
||||
VStack {
|
||||
|
|
@ -1210,7 +1210,7 @@ struct CallView: View {
|
|||
LinphoneVideoViewHolder { view in
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if index < callViewModel.participantList.count {
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.equal(address2: callViewModel.participantList[index].address)})
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.weakEqual(address2: callViewModel.participantList[index].address)})
|
||||
if participantVideo != nil && participantVideo!.devices.first != nil {
|
||||
participantVideo!.devices.first!.nativeVideoWindowId = UnsafeMutableRawPointer(Unmanaged.passRetained(view).toOpaque())
|
||||
}
|
||||
|
|
@ -1466,7 +1466,7 @@ struct CallView: View {
|
|||
LinphoneVideoViewHolder { view in
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if index < callViewModel.participantList.count {
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.equal(address2: callViewModel.participantList[index].address)})
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.weakEqual(address2: callViewModel.participantList[index].address)})
|
||||
if participantVideo != nil && participantVideo!.devices.first != nil {
|
||||
participantVideo!.devices.first!.nativeVideoWindowId = UnsafeMutableRawPointer(Unmanaged.passRetained(view).toOpaque())
|
||||
}
|
||||
|
|
@ -1707,7 +1707,7 @@ struct CallView: View {
|
|||
LinphoneVideoViewHolder { view in
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if index < callViewModel.participantList.count {
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.equal(address2: callViewModel.participantList[index].address)})
|
||||
let participantVideo = core.currentCall?.conference?.participantList.first(where: {$0.address!.weakEqual(address2: callViewModel.participantList[index].address)})
|
||||
if participantVideo != nil && participantVideo!.devices.first != nil {
|
||||
participantVideo!.devices.first!.nativeVideoWindowId = UnsafeMutableRawPointer(Unmanaged.passRetained(view).toOpaque())
|
||||
}
|
||||
|
|
@ -2218,28 +2218,37 @@ struct CallView: View {
|
|||
}
|
||||
.frame(width: geo.size.width * 0.24, height: geo.size.width * 0.24)
|
||||
} else {
|
||||
VStack {
|
||||
Button {
|
||||
changeLayoutSheet = true
|
||||
} label: {
|
||||
HStack {
|
||||
Image("layout")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 32, height: 32)
|
||||
}
|
||||
}
|
||||
.buttonStyle(PressedButtonStyle(buttonSize: buttonSize))
|
||||
.frame(width: buttonSize, height: buttonSize)
|
||||
.background(Color.gray500)
|
||||
.cornerRadius(40)
|
||||
|
||||
Text("call_action_change_layout")
|
||||
.foregroundStyle(.white)
|
||||
.default_text_style(styleSize: 15)
|
||||
}
|
||||
.frame(width: geo.size.width * 0.24, height: geo.size.width * 0.24)
|
||||
ZStack {
|
||||
VStack {
|
||||
Button {
|
||||
changeLayoutSheet = true
|
||||
} label: {
|
||||
HStack {
|
||||
Image("layout")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 32, height: 32)
|
||||
}
|
||||
}
|
||||
.buttonStyle(PressedButtonStyle(buttonSize: buttonSize))
|
||||
.frame(width: buttonSize, height: buttonSize)
|
||||
.background(Color.gray500)
|
||||
.cornerRadius(40)
|
||||
.disabled(callViewModel.activeSpeakerParticipant?.isScreenSharing == true)
|
||||
|
||||
Text("call_action_change_layout")
|
||||
.foregroundStyle(.white)
|
||||
.default_text_style(styleSize: 15)
|
||||
}
|
||||
.frame(width: geo.size.width * 0.24, height: geo.size.width * 0.24)
|
||||
|
||||
if callViewModel.activeSpeakerParticipant?.isScreenSharing == true {
|
||||
Color.gray600.opacity(0.8)
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
}
|
||||
.frame(width: geo.size.width * 0.24, height: geo.size.width * 0.24)
|
||||
}
|
||||
}
|
||||
.frame(height: geo.size.height * 0.15)
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ class ParticipantModel: ObservableObject {
|
|||
@Published var isMuted: Bool
|
||||
@Published var isAdmin: Bool
|
||||
@Published var isSpeaking: Bool
|
||||
@Published var isScreenSharing: Bool
|
||||
|
||||
init(address: Address, isJoining: Bool = false, onPause: Bool = false, isMuted: Bool = false, isAdmin: Bool = false, isSpeaking: Bool = false) {
|
||||
init(address: Address, isJoining: Bool = false, onPause: Bool = false, isMuted: Bool = false, isAdmin: Bool = false, isSpeaking: Bool = false, isScreenSharing: Bool = false) {
|
||||
self.address = address
|
||||
|
||||
self.sipUri = address.asStringUriOnly()
|
||||
|
|
@ -49,6 +50,7 @@ class ParticipantModel: ObservableObject {
|
|||
self.isMuted = isMuted
|
||||
self.isAdmin = isAdmin
|
||||
self.isSpeaking = isSpeaking
|
||||
self.isScreenSharing = isScreenSharing
|
||||
|
||||
ContactsManager.shared.getFriendWithAddressInCoreQueue(address: self.address) { friendResult in
|
||||
if let addressFriend = friendResult {
|
||||
|
|
|
|||
|
|
@ -458,9 +458,9 @@ class CallViewModel: ObservableObject {
|
|||
|
||||
var myParticipantModelTmp: ParticipantModel?
|
||||
if conf.me?.address != nil {
|
||||
myParticipantModelTmp = ParticipantModel(address: conf.me!.address!, isJoining: false, onPause: false, isMuted: false, isAdmin: conf.me!.isAdmin)
|
||||
myParticipantModelTmp = ParticipantModel(address: conf.me!.address!, isJoining: false, onPause: false, isMuted: false, isAdmin: conf.me!.isAdmin, isScreenSharing: false)
|
||||
} else if self.currentCall?.callLog?.localAddress != nil {
|
||||
myParticipantModelTmp = ParticipantModel(address: self.currentCall!.callLog!.localAddress!, isJoining: false, onPause: false, isMuted: false, isAdmin: conf.me!.isAdmin)
|
||||
myParticipantModelTmp = ParticipantModel(address: self.currentCall!.callLog!.localAddress!, isJoining: false, onPause: false, isMuted: false, isAdmin: conf.me!.isAdmin, isScreenSharing: false)
|
||||
}
|
||||
|
||||
var activeSpeakerParticipantTmp: ParticipantModel?
|
||||
|
|
@ -469,21 +469,24 @@ class CallViewModel: ObservableObject {
|
|||
address: conf.activeSpeakerParticipantDevice!.address!,
|
||||
isJoining: conf.activeSpeakerParticipantDevice!.state == .Joining || conf.activeSpeakerParticipantDevice!.state == .Alerting,
|
||||
onPause: conf.activeSpeakerParticipantDevice!.state == .OnHold,
|
||||
isMuted: conf.activeSpeakerParticipantDevice!.isMuted
|
||||
isMuted: conf.activeSpeakerParticipantDevice!.isMuted,
|
||||
isScreenSharing: conf.activeSpeakerParticipantDevice!.screenSharingEnabled
|
||||
)
|
||||
} else if conf.participantList.first?.address != nil && conf.participantList.first!.address!.clone()!.equal(address2: (conf.me?.address)!) {
|
||||
activeSpeakerParticipantTmp = ParticipantModel(
|
||||
address: conf.participantDeviceList.first!.address!,
|
||||
isJoining: conf.participantDeviceList.first!.state == .Joining || conf.participantDeviceList.first!.state == .Alerting,
|
||||
onPause: conf.participantDeviceList.first!.state == .OnHold,
|
||||
isMuted: conf.participantDeviceList.first!.isMuted
|
||||
isMuted: conf.participantDeviceList.first!.isMuted,
|
||||
isScreenSharing: conf.participantDeviceList.first!.screenSharingEnabled
|
||||
)
|
||||
} else if conf.participantList.last?.address != nil {
|
||||
activeSpeakerParticipantTmp = ParticipantModel(
|
||||
address: conf.participantDeviceList.last!.address!,
|
||||
isJoining: conf.participantDeviceList.last!.state == .Joining || conf.participantDeviceList.last!.state == .Alerting,
|
||||
onPause: conf.participantDeviceList.last!.state == .OnHold,
|
||||
isMuted: conf.participantDeviceList.last!.isMuted
|
||||
isMuted: conf.participantDeviceList.last!.isMuted,
|
||||
isScreenSharing: conf.participantDeviceList.last!.screenSharingEnabled
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -514,7 +517,8 @@ class CallViewModel: ObservableObject {
|
|||
isJoining: participantDevice.state == .Joining || participantDevice.state == .Alerting,
|
||||
onPause: participantDevice.state == .OnHold,
|
||||
isMuted: participantDevice.isMuted,
|
||||
isAdmin: isAdmin ?? false
|
||||
isAdmin: isAdmin ?? false,
|
||||
isScreenSharing: participantDevice.screenSharingEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -572,7 +576,8 @@ class CallViewModel: ObservableObject {
|
|||
isJoining: pDevice.state == .Joining || pDevice.state == .Alerting,
|
||||
onPause: pDevice.state == .OnHold,
|
||||
isMuted: pDevice.isMuted,
|
||||
isAdmin: isAdmin ?? false
|
||||
isAdmin: isAdmin ?? false,
|
||||
isScreenSharing: pDevice.screenSharingEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -588,21 +593,24 @@ class CallViewModel: ObservableObject {
|
|||
address: conference.activeSpeakerParticipantDevice!.address!,
|
||||
isJoining: conference.activeSpeakerParticipantDevice!.state == .Joining || conference.activeSpeakerParticipantDevice!.state == .Alerting,
|
||||
onPause: conference.activeSpeakerParticipantDevice!.state == .OnHold,
|
||||
isMuted: conference.activeSpeakerParticipantDevice!.isMuted
|
||||
isMuted: conference.activeSpeakerParticipantDevice!.isMuted,
|
||||
isScreenSharing: conference.activeSpeakerParticipantDevice!.screenSharingEnabled
|
||||
)
|
||||
} else if conference.participantList.first?.address != nil && conference.participantList.first!.address!.clone()!.equal(address2: (conference.me?.address)!) {
|
||||
activeSpeakerParticipantTmp = ParticipantModel(
|
||||
address: conference.participantDeviceList.first!.address!,
|
||||
isJoining: conference.participantDeviceList.first!.state == .Joining || conference.participantDeviceList.first!.state == .Alerting,
|
||||
onPause: conference.participantDeviceList.first!.state == .OnHold,
|
||||
isMuted: conference.participantDeviceList.first!.isMuted
|
||||
isMuted: conference.participantDeviceList.first!.isMuted,
|
||||
isScreenSharing: conference.participantDeviceList.first!.screenSharingEnabled
|
||||
)
|
||||
} else if conference.participantList.last?.address != nil {
|
||||
activeSpeakerParticipantTmp = ParticipantModel(
|
||||
address: conference.participantDeviceList.last!.address!,
|
||||
isJoining: conference.participantDeviceList.last!.state == .Joining || conference.participantDeviceList.last!.state == .Alerting,
|
||||
onPause: conference.participantDeviceList.last!.state == .OnHold,
|
||||
isMuted: conference.participantDeviceList.last!.isMuted
|
||||
isMuted: conference.participantDeviceList.last!.isMuted,
|
||||
isScreenSharing: conference.participantDeviceList.last!.screenSharingEnabled
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -648,7 +656,8 @@ class CallViewModel: ObservableObject {
|
|||
isJoining: pDevice.state == .Joining || pDevice.state == .Alerting,
|
||||
onPause: pDevice.state == .OnHold,
|
||||
isMuted: pDevice.isMuted,
|
||||
isAdmin: isAdmin ?? false
|
||||
isAdmin: isAdmin ?? false,
|
||||
isScreenSharing: pDevice.screenSharingEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -697,7 +706,57 @@ class CallViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
})
|
||||
}, onParticipantDeviceIsSpeakingChanged: { (_: Conference, device: ParticipantDevice, isSpeaking: Bool) in
|
||||
}, onParticipantDeviceScreenSharingChanged: { (_: Conference, device: ParticipantDevice, enabled: Bool) in
|
||||
self.toggleVideoMode(isAudioOnlyMode: false)
|
||||
|
||||
let activeSpeakerParticipantTmp = ParticipantModel(
|
||||
address: device.address!,
|
||||
isJoining: device.state == .Joining || device.state == .Alerting,
|
||||
onPause: device.state == .OnHold,
|
||||
isMuted: device.isMuted,
|
||||
isScreenSharing: device.screenSharingEnabled
|
||||
)
|
||||
|
||||
var activeSpeakerNameTmp = ""
|
||||
let friend = ContactsManager.shared.getFriendWithAddress(address: activeSpeakerParticipantTmp.address)
|
||||
if friend != nil && friend!.address != nil && friend!.address!.displayName != nil {
|
||||
activeSpeakerNameTmp = friend!.address!.displayName!
|
||||
} else {
|
||||
if activeSpeakerParticipantTmp.address.displayName != nil {
|
||||
activeSpeakerNameTmp = activeSpeakerParticipantTmp.address.displayName!
|
||||
} else if activeSpeakerParticipantTmp.address.username != nil {
|
||||
activeSpeakerNameTmp = activeSpeakerParticipantTmp.address.username!
|
||||
} else {
|
||||
activeSpeakerNameTmp = String(activeSpeakerParticipantTmp.address.asStringUriOnly().dropFirst(4))
|
||||
}
|
||||
}
|
||||
|
||||
var participantListTmp: [ParticipantModel] = []
|
||||
conference.participantDeviceList.forEach({ pDevice in
|
||||
if pDevice.address != nil && !conference.isMe(uri: pDevice.address!.clone()!) {
|
||||
if !conference.isMe(uri: pDevice.address!.clone()!) {
|
||||
let isAdmin = conference.participantList.first(where: {$0.address!.equal(address2: pDevice.address!.clone()!)})?.isAdmin
|
||||
|
||||
participantListTmp.append(
|
||||
ParticipantModel(
|
||||
address: pDevice.address!,
|
||||
isJoining: pDevice.state == .Joining || pDevice.state == .Alerting,
|
||||
onPause: pDevice.state == .OnHold,
|
||||
isMuted: pDevice.isMuted,
|
||||
isAdmin: isAdmin ?? false,
|
||||
isScreenSharing: pDevice.screenSharingEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.activeSpeakerParticipant = activeSpeakerParticipantTmp
|
||||
self.activeSpeakerName = activeSpeakerNameTmp
|
||||
self.participantList = participantListTmp
|
||||
}
|
||||
} , onParticipantDeviceIsSpeakingChanged: { (_: Conference, device: ParticipantDevice, isSpeaking: Bool) in
|
||||
let isSpeaking = device.isSpeaking
|
||||
if self.myParticipantModel != nil && self.myParticipantModel!.address.clone()!.equal(address2: device.address!) {
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -732,7 +791,8 @@ class CallViewModel: ObservableObject {
|
|||
address: participantDevice!.address!,
|
||||
isJoining: participantDevice!.state == .Joining || participantDevice!.state == .Alerting,
|
||||
onPause: participantDevice!.state == .OnHold,
|
||||
isMuted: participantDevice!.isMuted
|
||||
isMuted: participantDevice!.isMuted,
|
||||
isScreenSharing: participantDevice!.screenSharingEnabled
|
||||
)
|
||||
|
||||
var activeSpeakerNameTmp = ""
|
||||
|
|
@ -763,7 +823,8 @@ class CallViewModel: ObservableObject {
|
|||
isJoining: pDevice.state == .Joining || pDevice.state == .Alerting,
|
||||
onPause: pDevice.state == .OnHold,
|
||||
isMuted: pDevice.isMuted,
|
||||
isAdmin: isAdmin ?? false
|
||||
isAdmin: isAdmin ?? false,
|
||||
isScreenSharing: pDevice.screenSharingEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@
|
|||
"location" : "https://gitlab.linphone.org/BC/public/linphone-sdk-swift-ios.git",
|
||||
"state" : {
|
||||
"branch" : "beta",
|
||||
"revision" : "5c2b2f448fbbd0326d01116227c7f5bda8e277c6"
|
||||
"revision" : "2444acf4b34629fc229435895750f3784e52b5d9"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -149,8 +149,8 @@
|
|||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||
"state" : {
|
||||
"revision" : "5596511fce902e649c403cd4d6d5da1254f142b7",
|
||||
"version" : "1.35.1"
|
||||
"revision" : "a008af1a102ff3dd6cc3764bb69bf63226d0f5f6",
|
||||
"version" : "1.36.1"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue