问题描述
我正在尝试为4人一组创建一个android语音聊天应用,4人可以互相交谈。这可以使用android web RTC中的网格架构来完成。我已经创建了所有先决条件,即设置了转弯服务器,信令服务器和android应用程序代码。这里的问题是我不能使它适用于两个以上的人。在s what
发生的情况下,最初,用户(A)加入了一个房间。然后另一个用户(B)加入该房间。 SDP提供,应答和ICE候选人成功交换并建立连接。 A 和 B 都可以互相交谈。当第三个用户(C)加入会议室时,问题开始。 C 进入会议室后,SDP报价,答案和ICE候选人将与 A , B 和 C ,在 B 和 C 成功连接后,他们都可以互相交谈,而 B 与 A 断开连接>,表示 A 听不到 B 和 B 听不到 A ,尽管它们在开始时已成功连接,然后用户 A 以单向连接到 C ,这意味着 C 可以听 A 而 A 无法听 C 。
我无法弄清楚。任何帮助都非常有用。
class RTcclient(context: Application,mSocketId: String) {
val socketId: String = mSocketId
private val listofServers = ArrayList<IceServer>()
init {
initPeerConnectionFactory(context)
createServeList()
}
private fun createServeList() {
listofServers.add(IceServer.builder("stun:stun.services.mozilla.com").createIceServer())
listofServers.add(IceServer.builder("stun:stun.l.google.com:19302").createIceServer())
listofServers.add(
IceServer.builder("turn:ip:port").setUsername("usernmae")
.setPassword("password").createIceServer()
)
}
private val peerConnectionFactory by lazy { buildPeerConnectionFactory() }
private val localAudioSource by lazy { peerConnectionFactory.createAudioSource(MediaConstraints()) }
private val peerConnection by lazy { buildPeerConnection(peerConnectionObserver) }
private fun initPeerConnectionFactory(context: Application) {
val options = PeerConnectionFactory.Initializationoptions.builder(context)
.setEnableInternalTracer(true)
.setFieldTrials("WebRTC-H264HighProfile/Enabled/")
.createInitializationoptions()
PeerConnectionFactory.initialize(options)
}
private fun buildPeerConnectionFactory(): PeerConnectionFactory {
return PeerConnectionFactory
.builder()
.setoptions(PeerConnectionFactory.Options().apply {
disableEncryption = true
disableNetworkMonitor = true
})
.createPeerConnectionFactory()
}
private fun buildPeerConnection(observer: PeerConnection.Observer) =
peerConnectionFactory.createPeerConnection(
listofServers,observer
)
fun startLocalAudioSource(): ConnectionFactory {
val audioTrack = peerConnectionFactory.createAudioTrack("ARdamSa0",localAudioSource)
val localMediaStream = peerConnectionFactory.createLocalMediaStream("ARdamS")
localMediaStream.addTrack(audioTrack)
peerConnection?.addStream(localMediaStream)
return ConnectionFactory(peerConnectionFactory,peerConnection)
}
private fun PeerConnection.call(sdpObserver: SdpObserver) {
val constraints = MediaConstraints().apply {
mandatory.add(MediaConstraints.keyvaluePair("OfferToReceiveVideo","false"))
}
createOffer(object : SdpObserver by sdpObserver {
override fun onCreateSuccess(desc: SessionDescription?) {
setLocalDescription(object : SdpObserver {
override fun onSetFailure(p0: String?) {
}
override fun onSetSuccess() {
}
override fun onCreateSuccess(p0: SessionDescription?) {
}
override fun onCreateFailure(p0: String?) {
}
},desc)
sdpObserver.onCreateSuccess(desc)
}
},constraints)
}
private fun PeerConnection.answer(sdpObserver: SdpObserver) {
val constraints = MediaConstraints().apply {
mandatory.add(MediaConstraints.keyvaluePair("OfferToReceiveVideo","false"))
}
createAnswer(object : SdpObserver by sdpObserver {
override fun onCreateSuccess(p0: SessionDescription?) {
setLocalDescription(object : SdpObserver {
override fun onSetFailure(p0: String?) {
}
override fun onSetSuccess() {
}
override fun onCreateSuccess(p0: SessionDescription?) {
}
override fun onCreateFailure(p0: String?) {
}
},p0)
sdpObserver.onCreateSuccess(p0)
}
},constraints)
}
fun call(sdpObserver: SdpObserver) = peerConnection?.call(sdpObserver)
fun answer(sdpObserver: SdpObserver) = peerConnection?.answer(sdpObserver)
fun onRemoteSessionReceived(sessionDescription: SessionDescription) {
peerConnection?.setRemoteDescription(object : SdpObserver {
override fun onSetFailure(p0: String?) {
}
override fun onSetSuccess() {
}
override fun onCreateSuccess(p0: SessionDescription?) {
}
override fun onCreateFailure(p0: String?) {
}
},sessionDescription)
}
fun addIceCandidate(iceCandidate: IceCandidate?) {
peerConnection?.addIceCandidate(iceCandidate)
}
val sdpObserver = object : AppSdpObserver() {
override fun onCreateSuccess(p0: SessionDescription?) {
super.onCreateSuccess(p0)
SocketConnection.socket.emit("offer",BaseClass.gSon.toJson(p0),socketId)
}
}
private val peerConnectionObserver = object : PeerConnectionObserver() {
override fun onIceCandidate(p0: IceCandidate?) {
super.onIceCandidate(p0)
SocketConnection.socket.emit("ice",socketId)
}
}
}
这是我的片段代码。
class VoiceChatFragment : Fragment(),UsersAdapter.OnItemClickListener,SocketConnection.socketCallbacks,EasyPermissions.PermissionCallbacks {
private var doubleBackToExitpressedOnce: Boolean = false
private lateinit var joinResponse: Roomresponse
private var rtcclientList = ArrayList<RtcclientModel>()
private val hashMapCallSetUp = HashMap<String,Boolean>()
private lateinit var loginResponse: Response
private lateinit var binding: VoiceChatBinding
private val userAdapter = UsersAdapter(this)
private lateinit var me: Users
private var usersList: ArrayList<Users> = ArrayList()
companion object {
const val RC_CAMERA_PERM = 100
}
//other code.
override fun onJoin(params: String) {
Timber.d("On user joined. $params")
joinResponse = gSon.fromJson(params,Roomresponse::class.java)
if (joinResponse.result == true) {
setVisibility(joinResponse.result ?: false)
initCall()
} else {
loginResponse.message = joinResponse.message
loginResponse.result = joinResponse.result
activity?.runOnUiThread { joinResponse.message?.toast() }
}
}
private fun initCall() {
val mRoomData = joinResponse.roomData?.users
val reqTime = mRoomData?.filterIndexed { _,element ->
element?.userId == me.userId
}?.firstOrNull()?.reqTime ?: 0
me.reqTime = reqTime
val roomData = mRoomData?.filterIndexed { _,element ->
element?.userId != me.userId
}
activity?.runOnUiThread { mRoomData?.size?.toast() }
roomData?.forEach { roomUser ->
if (hashMapCallSetUp[roomUser?.userId] == null) {
Timber.d("creating call setup process for ${roomUser?.userNick}")
hashMapCallSetUp[roomUser?.userId.orEmpty()] = true
initRtcclient(roomUser?.userId.orEmpty(),roomUser?.socketId.orEmpty())
if (me.reqTime > roomUser?.reqTime!!) {
Timber.d("creating offer for ${roomUser.userNick}")
val client = rtcclientList.filterIndexed { _,item ->
item.userId == roomUser.userId
}.firstOrNull()?.rtcclient
client?.call(client.sdpObserver)
Timber.d("created call offer for ${roomUser.userNick}")
}
}
}
}
private fun initRtcclient(userId: String,socketId: String) {
val rtcclient = RTcclient(activity?.application!!,socketId)
val connectionFactory = rtcclient.startLocalAudioSource()
val rtcObject = RtcclientModel(userId,socketId,rtcclient,connectionFactory)
rtcclientList.add(rtcObject)
}
override fun onOfferReceived(
description: SessionDescription,user: Roomresponse.RoomData.User
) {
Timber.d("Override onOfferReceived ${user.userId}")
val client = rtcclientList.filterIndexed { _,rtcclientModel ->
rtcclientModel.userId == user.userId
}.firstOrNull()?.rtcclient
Timber.d("setting remote description for ${user.userId}")
client?.onRemoteSessionReceived(description)
Timber.d("creating answer for ${user.userId}")
client?.answer(client.sdpObserver)
}
override fun onAnswerReceived(
description: SessionDescription,user: Roomresponse.RoomData.User
) {
Timber.d("Override onAnswerReceived ${user.userId}")
val client = rtcclientList.filterIndexed { _,rtcclientModel ->
rtcclientModel.userId == user.userId
}.firstOrNull()?.rtcclient
Timber.d("setting remote description for ${user.userId}")
client?.onRemoteSessionReceived(description)
}
override fun onIceCandidateReceived(
iceCandidate: IceCandidate,user: Roomresponse.RoomData.User
) {
Timber.d("Override onICE candidates received for ${user.userId}")
val client = rtcclientList.filterIndexed { _,rtcclientModel ->
rtcclientModel.userId == user.userId
}.firstOrNull()?.rtcclient
Timber.d("setting ice candidates for ${user.userId}")
client?.addIceCandidate(iceCandidate)
}
}
SDp观察器界面
open class AppSdpObserver : SdpObserver {
override fun onSetFailure(p0: String?) {
Timber.tag("VoiceChatFragment").d("On set failure. Reason $p0")
}
override fun onSetSuccess() {
Timber.tag("VoiceChatFragment").d("On set success")
}
override fun onCreateSuccess(p0: SessionDescription?) {
Timber.tag("VoiceChatFragment").d("On create success")
}
override fun onCreateFailure(p0: String?) {
Timber.tag("VoiceChatFragment").d("On create failure. Reason $p0")
}
}
这是对等连接观察者类
open class PeerConnectionObserver : PeerConnection.Observer {
override fun onIceCandidate(p0: IceCandidate?) {
Timber.tag("VoiceChatFragment").d("On ice candidates")
}
override fun onDataChannel(p0: DataChannel?) {
Timber.tag("VoiceChatFragment").d("On Data Channel")
}
override fun onIceConnectionReceivingChange(p0: Boolean) {
Timber.tag("VoiceChatFragment").d("On Ice connection receiving change")
}
override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
Timber.tag("VoiceChatFragment").d("On ice connection change")
}
override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) {
Timber.tag("VoiceChatFragment").d("On ice gathering change")
}
override fun onAddStream(p0: MediaStream?) {
Timber.tag("VoiceChatFragment").d("On Add stream")
}
override fun onSignalingChange(p0: PeerConnection.SignalingState?) {
Timber.tag("VoiceChatFragment").d("On Signaling change")
}
override fun onIceCandidatesRemoved(p0: Array<out IceCandidate>?) {
Timber.tag("VoiceChatFragment").d("On ice candidates removed")
}
override fun onRemoveStream(p0: MediaStream?) {
Timber.tag("VoiceChatFragment").d("On remove stream")
}
override fun onRenegotiationNeeded() {
Timber.tag("VoiceChatFragment").d("On renegotiation needed")
}
override fun onAddTrack(p0: RtpReceiver?,p1: Array<out MediaStream>?) {
Timber.tag("VoiceChatFragment").d("On add track")
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)