uniapp Vue 使用 sip.js进行语音通话视频通话

这篇具有很好参考价值的文章主要介绍了uniapp Vue 使用 sip.js进行语音通话视频通话。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

下载或者安装 sip.js 到 uniapp 项目,APP 端在 menifest.json 中配置麦克风权限
menifest.json 中 app 权限配置选中:
android.permission.RECORD_AUDIO
android.permission.MODIFY_AUDIO_SETTINGS

sip.js 低版本 如 V0.13.0 版本的写法

<template>
	<view class="container">
		<view class="top-box">
			<button type="primary" @click="handleRegister">注册</button>
			<button type="primary" plain @click="handleUnRegister">取消注册</button>
		</view>
		<view class="top-box">
			<uni-easyinput class="margr" v-model="outGoingNumber" placeholder="SIP URL"></uni-easyinput>
			<button type="primary" @click="handleCall">呼叫</button>
		</view>
		<view class="top-box">
			<audio ref="remoteAudio" id="remoteAudio"></audio>
			<audio ref="localAudio" id="localAudio"></audio>
			<audio ref="bell" id="bell" src="~/static/music.mp3"></audio>
		</view>
		
		<uni-popup ref="popup" type="center">
			<view class="popup-box">
				<view class="flex-box fs-36 fw-600">{{isInOut?inComingNumber:outGoingNumber}}</view>
				<template v-if="isConnected">
					<view class="flex-box">通话中...</view>
					<view class="flex-box">
						<uni-tag text="挂断" type="error" @click="handleCacel"></uni-tag>
					</view>
				</template>
				<template v-else>
					<view v-if="isInOut">
						<view class="flex-box">呼入...</view>
						<view class="flex-box">
							<uni-tag text="接听" type="success" @click="handleAccept"></uni-tag>
							<uni-tag text="拒绝" type="error" @click="handleTerminate"></uni-tag>
						</view>
					</view>
					<view v-else>
						<view class="flex-box">呼出...</view>
						<view class="flex-box">
							<uni-tag text="挂断" type="error" @click="handleTerminate"></uni-tag>
						</view>
					</view>

				</template>
			</view>
		</uni-popup>
		
	</view>
	
</template>

<script>
	import * as sip from "@/common/js/sip-0.13.0.min.js"

	let ua;

	export default {
		name: "VoiceIntercom",
		props: {},
		data() {
			return {
				configuration: {},
				outGoingNumber: '02700002',
				baseUrl: 'web.domain.com', // sipurl格式: "sip:02700001@web.domain.com:7065",
				port: '7065',
				user: {
					number: '02700001',
					name: 'test',
					password: '123456'
				},
				server: 'wss://web.domain.com:7067',
				currentSession: null,
				inComingNumber: null,
				isRegistered: false,
				isConnected: false, // 是否接通
				isInOut: true, // true 被呼, false 呼出
			}
		},
		onLoad() {
			this.handleRegister()
		},
		beforeDestroy() {
			this.handleUnRegister()
		},
		methods: {
			// 登录
			handleRegister() {
				this.configuration = {
					uri: `sip:${this.user.number}@${this.baseUrl}:${this.port}`,
					displayName: this.user.name,
					password: this.user.password,
					transportOptions: {
						wsServers: [this.server],
						traceSip: true
					},
				}
				ua = new sip.UA(this.configuration)
				ua.on('registered', (resp) => {
					this.showTishi('【' + this.user.number + '】语音登录成功')
					this.isRegistered = true
				})
				ua.on('registrationFailed', (resp) => {
					if (resp.statusCode == 503) {
						this.showTishi('【' + this.user.number + '】服务不可用')
					} else {
						this.showTishi('【' + this.user.number + '】语音登录失败:' + resp.reasonPhrase)
					}
					this.isRegistered = false
					console.log(resp, '语音登录失败')
				})
				ua.on('unregistered', (response, cause) => {
					this.showTishi('【' + this.user.number + '】取消语音登录成功')
					console.log(response, cause, '取消语音登录')
				})
				ua.on('invite', (session) => {
					this.currentSession = session
					this.inComingNumber = session.remoteIdentity.uri.user

					this.isInOut = true

					this.$refs.popup.open()
					this.$nextTick(() => {
						this.$refs.bell.$refs.audio.play()
						this.$refs.bell.$refs.audio.currentTime = 0
					})
					this.sessionEvent(session)
				})
				ua.on('message', (message)=>{
					console.log(message,'ua-message')
				})
				ua.start()
			},
			// 退出登录
			handleUnRegister() {
				if (ua) {
					ua.unregister()
					this.isRegistered = false
				}
			},
			// session 处理
			sessionEvent(session) {
				session.on('rejected', () => {
					console.log('inComing挂断')
				})
				session.on('cancel', () => {
					console.log('outgoing挂断')
				})
				session.on('terminated', (message, cause) => {
					console.log(message, cause, 'session-terminated')
					if (cause == 'Rejected') {
						if (message.reasonPhrase == 'Decline') {
							this.showTishi('您的拨号暂时无人接听!')
						} else {
							this.showTishi('对方拒接了!')
						}
					} else if (cause == 'BYE') {
						this.showTishi('对方已挂机!')
					} else if (cause == 'Canceled') {
						this.showTishi('对方已取消!')
					}

					this.$refs.bell.$refs.audio.pause()
					this.$refs.popup.close()
				})
				session.on('accepted', (resp) => {
					this.$refs.bell.$refs.audio.pause()
					this.isConnected = true
					console.log(resp, '接受了')
				})
				session.on('trackAdded', () => {
					const pc = session.sessionDescriptionHandler.peerConnection
					const remoteStream = new MediaStream()
					pc.getReceivers().forEach((receiver) => {
						if (receiver.track) {
							remoteStream.addTrack(receiver.track)
							this.$refs.remoteAudio.$refs.audio.srcObject = remoteStream
							this.$refs.remoteAudio.$refs.audio.play()
						}
					})

				})
				session.on('bye', (resp, cause) => {
					console.log(resp, cause, 'session-bye')
					if ((resp && resp.method == 'BYE') || cause == 'BYE') {
						this.isConnected = false
						this.$refs.popup.close()
						this.$refs.remoteAudio.$refs.audio.pause()
						this.showTishi('【' + this.user.number + '】通话已结束!')
					}
				})
				session.on('failed', () => {
					console.log('session-failed')
				})
			},
			// 接听
			handleAccept() {
				const option = {
					sessionDescriptionHandlerOptions: {
						constraints: {
							audio: true,
							video: false
						}
					}
				}
				this.currentSession.accept(option)
			},
			// 拒接
			handleTerminate() {
				this.currentSession.terminate()
				this.$refs.popup.close()
				this.isConnected = false
			},
			// 挂断
			handleCacel() {
				if (this.isInOut) {
					this.currentSession.reject()
				} else {
					this.currentSession.terminate()
				}
				this.$refs.popup.close()
				this.isConnected = false
			},
			// 拨打
			handleCall(number) {
				number = this.outGoingNumber
				if (this.isRegistered) {
					this.isInOut = false
					const sipUrl = `sip:${number}@${this.baseUrl}:${this.port}`
					this.currentSession = ua.invite(sipUrl, {
						sessionDescriptionHandlerOptions: {
							constraints: {
								audio: true,
								video: false
							}
						}
					})
					this.$refs.popup.open()
					this.sessionEvent(this.currentSession)
				} else {
					this.showTishi('请先登录语音用户')
				}
			},
			showTishi(title){
				uni.showToast({
					title: title,
					icon: 'none'
				})
			},

		}
	}
</script>

<style scoped lang="scss">
	.container {
		font-size: 30rpx;
	}

	.top-box {
		padding: 30rpx;
		display: flex;
	}

	.popup-box {
		background: #ffffff;
		width: 80vw;
		padding: 40rpx;
		border-radius: 20rpx;
		line-height: 80rpx;
	}

	.flex-box {
		display: flex;
		justify-content: space-around;

		.uni-tag {
			font-size: 30rpx;
			padding: 16rpx 28rpx;
		}
	}
	.fs-36{
		font-size: 36rpx;
		font-weight: bold;
	}
</style>

sip.js 高版本如 V0.21.2 用法(参数同上,只列出 methods 里的部分)

<script>
import { UserAgentOptions, UserAgent, Registerer, Invitation, Inviter, Session, SessionState, InvitationAcceptOptions, InviterOptions, Messager, URI, RegistererState,  } from '@/common/js/sip-0.21.2.min.js'

let userAgent, registerer;
const target = UserAgent.makeURI(`sip:${this.outGoingNumber}@${this.baseUrl}:${this.port}`);

methods: {
	handleRegister() {
	    const uri = UserAgent.makeURI(`sip:${this.user.number}@${this.baseUrl}:${this.port}`)
	    if(!uri){
	        console.log('创建URI失败')
	    }
	    const transportOptions = {
	        server: this.server
	    }
	    const userAgentOptions = {
	        authorizationUsername: this.user.number,
	        authorizationPassword: this.user.password,
	        displayName: this.user.name,
	        transportOptions,
	        uri,
	        delegate: {
	            onInvite
	        }
	    } 
	    userAgent = new UserAgent(userAgentOptions) 
	    registerer = new Registerer(userAgent)
	    userAgent.start().then(()=>{
	        registerer.register({
	            requestDelegate: {
	                onReject: (resp)=>{
	                    console.log(resp, 'onReject')
	                },
	                onAccept: (resp)=>{
	                    console.log(resp, 'onAccept')
	                },
	                onProgress: (resp) => {
	                    console.log(resp, 'onProgress')
	                },
	                onRedirect: (resp) => {
	                    console.log(resp, 'onRedirect')
	                },
	                onTrying: (resp) => {
	                    console.log(resp, 'onTrying')
	                },
	            }
	        }).catch((e: Error) => {
	            console.log(e, "Register failed")
	        })
	    }).catch((err:any)=>{
	        console.log(err,'start-err')
	    }) 
	    registerer.stateChange.addListener((newState)=>{
	        switch (newState) {
	            case RegistererState.Unregistered:
	                console.log('退出登录')
	                break;
	            case RegistererState.Registered :
	                break;
	            case RegistererState.Initial :
	                console.log('语音用户登录Initial')
	                break;
	            case RegistererState.Terminated :
	                console.log('语音用户登录Terminated')
	                break;
	        }
	    })
	
	    function onInvite(invitation){
	        this.currentSession = invitation
	        this.inComingNumber = invitation.remoteIdentity.uri.user
	        this.$refs.popup.open()
	        invitation.stateChange.addListener((state)=>{
	            this.sessionStateEvent(state, invitation)
	        })
	    }
	}

	handleAccept(){
	    let constrainsDefault = {
	        audio: true,
	        video: false,
	    }
	    const options = {
	        sessionDescriptionHandlerOptions: {
	            constraints: constrainsDefault
	        }
	    }
	    this.currentSession.accept(options)
	    this.isConnected = true
	}
	handleReject(){
	    this.currentSession.reject()
	    this.$refs.popup.close()
	}
	
	sessionStateEvent(state, session){
	    switch(state){
	        case SessionState.Initial:
	            console.log('SessionState.Initial')
	        case SessionState.Establishing:
	            console.log('SessionState.Establishing')
	            break;
	        case SessionState.Established:
	            console.log('SessionState.Established')
	            this.isConnected = true
	            this.setupRemoteMedia(session)
	            break;
	        case SessionState.Terminating:
	            console.log('SessionState.Terminating')
	            break;
	        case SessionState.Terminated:
	            console.log('SessionState.Terminated')
	            this.clearupMedia(session)
	            break;     
	    } 
	}
	setupRemoteMedia(session){
	    const remoteStream = new MediaStream()
	    // console.log(session.sessionDescriptionHandler, 'sessionDescriptionHandler')
	    session.sessionDescriptionHandler.peerConnection.getReceiver().forEach((receiver)=>{
	        if(receiver.track){
	            remoteStream.addTrack(receiver.track)
	        }
	    })
	    this.$refs.remoteAudio.$refs.audio.srcObject = remoteStream
	    this.$refs.remoteAudio.$refs.audio.play()
	}
	clearupMedia(session){
	    if(this.isCallIn){
	        if(session.isCanceled){
	            console.log('对方已挂机')
	        }
	    }else{
	        if(!session.isCanceled){
	            // console.log('对方已挂机')
	        }
	    }
	   	this.$refs.remoteAudio.$refs.audio.srcObject = null
	    this.$refs.remoteAudio.$refs.audio.pause()
	    this.endCall()
	}
	
	handleCall(){
	    this.isCallIn = false
	    this.$refs.popup.open()
	    const inviterOptions = {
	        sessionDescriptionHandlerOptions: {
	            constraints: { audio: true, video: false }
	        }
	    }
	    if(target){
	        const inviter = new Inviter(userAgent, target, inviterOptions)
	        this.currentSession = inviter
	
	        inviter.invite({
	            requestDelegate: {
	                onReject: (resp)=>{
	                    console.log(resp, 'inviter-onReject')
	                    if(resp.statusCode == 500){
	                        console.log('对方不在线')
	                    }else{
	                        console.log('对方拒接了')
	                    }
	                },
	                onAccept: (resp)=>{
	                    console.log(resp, 'inviter-onAccept')
	                },
	                onProgress: (resp) => {
	                    console.log(resp, 'inviter-onProgress')
	                },
	                onRedirect: (resp) => {
	                    console.log(resp, 'inviter-onRedirect')
	                },
	                onTrying: (resp) => {
	                    console.log(resp, 'inviter-onTrying')
	                },
	                
	            }
	        })
	        inviter.stateChange.addListener((state)=>{
	            this.sessionStateEvent(state, inviter)
	        })
	    } 
	}
	
	handleURegister(){
	    if(userAgent){
	        this.isRegistered = false
	        registerer.unregister()
	    }
	}
	
	sendMessage(){
	    if(target && this.isRegistered){
	        const messager = new Messager(userAgent, target, '你好')
	        messager.message()
	    }
	}
	endCall(){
	    this.isConnected = false
	    this.$refs.popup.close()
	    switch(this.currentSession.state){
	        case SessionState.Initial:
	        case SessionState.Establishing:
	            if(this.currentSession instanceof Inviter){
	                // incoming session
	                this.currentSession.cancel()
	            }else{
	                // outgoing session
	                this.currentSession.reject()
	            }
	            break;
	        case SessionState.Established:
	            this.currentSession.bye()
	            break;
	        case SessionState.Terminating:
	            break;
	        case SessionState.Terminated:
	            console.log(SessionState,'Terminated-endCall')
	            break;     
	    }
	}
}

</script>

APP模式下检测麦克风权限,permission.js可从插件市场直接下载,使用页面import引入。文章来源地址https://www.toymoban.com/news/detail-648577.html

getPermission(){
	let env = uni.getSystemInfoSync().platform
	if (env === 'android') {permission.requestAndroidPermission('android.permission.RECORD_AUDIO').then((e) => {
			if (e === -1) {
				uni.showToast({
					title: '您已经拒绝录音权限,请在应用设置中手动打开',
					icon: 'none',
				})
			} else if (e === 0) {
				uni.showToast({
					title: '您拒绝了录音授权',
					icon: 'none',
				})
			} else if (e === 1) {
				console.log('已授权')
			} else {
				uni.showToast({
					title: '授权返回值错误',
					icon: 'none',
				})
			}
		}).catch((err) => {
			uni.showToast({
				title: '拉起录音授权失败',
				icon: 'none',
			})
		})
	} else if (env === 'ios') {
		if (permission.judgeIosPermission("record")){
			console.log('已授权')
		}else{
			uni.showToast({
				title: '您拒绝了录音授权,请在应用设置中手动打开',
				icon: 'none',
			})
		}	
	}
}

到了这里,关于uniapp Vue 使用 sip.js进行语音通话视频通话的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • web网页端使用webSocket实现语音通话功能(SpringBoot+VUE)

    最近在写一个web项目,需要实现web客户端之间的语音通话,期望能够借助webSocket全双工通信的方式来实现,但是网上没有发现可以正确使用的代码。网上能找到的一个代码使用之后 只能听到“嘀嘀嘀”的杂音 解决方案: 使用Json来传递数据代替原有的二进制输入输出流 技术

    2024年02月02日
    浏览(122)
  • uniapp实现视频通话功能

    需求:接入即构SDK实现RTC视频通话 提示:此处功能需求运用在window和安卓设备: uniapp接入即构,快速实现实时音视频通话功能。接入ZEGO Express SDK:由 ZEGO 提供的实时音视频 SDK,能够为开发者提供便捷接入、高清流畅、多平台互通、低延迟、高并发的音视频服务。 关于SDK的

    2024年02月03日
    浏览(28)
  • WebSocket+Vue+SpringBoot实现语音通话

    参考文章 整体思路 前端点击开始对话按钮后,将监听麦克风,获取到当前的音频,将其装化为二进制数据,通过websocket发送到webscoket服务端,服务端在接收后,将消息写入给指定客户端,客户端拿到发送过来的二进制音频后再转化播放 注意事项 由于音频转化后的二进制数据

    2024年02月06日
    浏览(47)
  • SpringBoot+WebSocket+Vue+PeerJs实现WebRTC视频通话功能,Vue视频通话,web视频通话,webrtc视频通话

    博主正在担任一款电商app的全栈开发,其中涉及到一个 视频通话 功能。但是由于业务需求及成本考虑,不能使用第三方提供的SDK进行开发。所以博主选择使用PeerJs+WebSocket来实现这个功能。 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定

    2024年02月08日
    浏览(49)
  • Java代码实现SIP通话

    在 Java 中实现 SIP 通话可以使用 SIP API,比如 SIP API for Java (SIPServer API) 或者 MJSip。 使用 SIP API for Java (SIPServer API) 可以这样写代码: ``` import java.io.IOException; import java.net.InetAddress; import javax.sip.ClientTransaction; import javax.sip.Dialog; import javax.sip.DialogState; import javax.sip.DialogTerminatedEv

    2024年02月16日
    浏览(33)
  • 解决苹果Safari 浏览器下html不能自动播放声音和视频的问题-实时语音通话功能【唯一客服】...

    在实现我的客服系统中,实时语音通话功能的时候,如果想自动播放音视频流,在苹果设备上遇到了问题。 苹果浏览器(Safari)在默认情况下不允许声音在背景里自动播放。这是出于用户体验和隐私方面的考虑,避免在用户没有意识到的情况下自动播放声音。 解决办法是 iOS

    2024年02月12日
    浏览(132)
  • 网站在线客服系统实时语音视频聊天实战开发,利用peerjs vue.js实现webRTC网页音视频客服系统...

    webRTC机制和peerjs库的介绍在其他博客中已经有了很多介绍,这里我直接搬运过来 WebRTC(Web Real-Time Communication)即:网页即时通信。 简单点讲,它可以实现浏览器网页与网页之间的音视频实时通信(或传输其它任何数据),目前主流浏览器都支持该API,WebRTC现在已经纳入W3C标准。

    2024年02月04日
    浏览(59)
  • vue3的Uniapp用renderjs 进行视频切图操作

    首先,在项目中安装 RenderJS 在 Vue3 的 UniApp 中引入 RenderJS: 创建一个 RenderJS 实例,并将其绑定到一个视频元素上 在 initRenderJS() 方法中编写 RenderJS 的代码,实现视频切图功能

    2024年01月22日
    浏览(25)
  • unity 使用声网(Agora)实现语音通话

    第一步、先申请一个声网账号 [Agora官网链接](https://console.shengwang.cn/) 第二步在官网创建项目 ,选择无证书模式,证书模式需要tokenh和Appld才能通话 第三步 官网下载SDK 然后导入到unity,也可以直接在unity商店里下载,Agora官网下载链接 第四步 运行官方Demo 1、导入后会有这些

    2024年04月25日
    浏览(42)
  • uni-app使用vue语法进行开发注意事项

    目录 uni-app 项目目录结构 生命周期 路由 路由跳转 页面栈 条件编译 文本渲染 样式渲染 条件渲染 遍历渲染 事件处理 事件修饰符 组件/标签 使用(类似)小程序 语法/结构 使用vue 具体项目目录如下: uni-app 支持如下应用生命周期函数: 函数名 说明 onLaunch 当 uni-app  初始化

    2024年02月13日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包