Merge branch 'develop' of http://25.13.9.101:9000/K17_AITS/tra-app into develop
This commit is contained in:
+4
-180
@@ -1,182 +1,6 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<button @click="startPush" v-if="!isPushing">开始语音推流</button>
|
||||
<button @click="stopPush" v-else>停止语音推流</button>
|
||||
</view>
|
||||
<talkCom/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isPushing: false, // 推流状态
|
||||
pusher: null, // 推流实例
|
||||
currentWebview: null // 当前 Webview 实例
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
// 改用 onReady(页面渲染完成) + 延迟
|
||||
if (uni.getSystemInfoSync().platform === 'android') {
|
||||
// 安卓端延迟 1000ms,且重试 3 次,确保获取到 Webview
|
||||
let retryCount = 0
|
||||
const getWebview = () => {
|
||||
this.currentWebview = this.$mp.page.$getAppWebview()
|
||||
if (this.currentWebview) {
|
||||
console.log('Webview 获取成功:', this.currentWebview)
|
||||
return
|
||||
}
|
||||
retryCount++
|
||||
if (retryCount < 3) {
|
||||
setTimeout(getWebview, 500) // 每次重试间隔 500ms
|
||||
} else {
|
||||
uni.showToast({ title: 'Webview 初始化失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
setTimeout(getWebview, 1000) // 初始延迟 1 秒
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// // 仅 App 端初始化 Webview
|
||||
// if (uni.getSystemInfoSync().platform !== 'app-plus') {
|
||||
// uni.showToast({ title: '仅支持 App 端推流', icon: 'none' });
|
||||
// return;
|
||||
// }
|
||||
// this.currentWebview = this.$mp.page.$getAppWebview();
|
||||
},
|
||||
onUnload() {
|
||||
// 页面销毁时停止推流并销毁组件
|
||||
this.stopPush()
|
||||
},
|
||||
methods: {
|
||||
// 申请麦克风权限
|
||||
async requestMicPermission() {
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.android.requestPermissions(
|
||||
['android.permission.RECORD_AUDIO'], // Android 权限
|
||||
res => {
|
||||
const granted = res.filter(item => item.granted).length === 1
|
||||
granted ? resolve() : reject('麦克风权限申请失败')
|
||||
},
|
||||
err => reject(err)
|
||||
)
|
||||
// iOS 权限由系统自动弹窗,无需手动申请,此处可统一处理
|
||||
})
|
||||
},
|
||||
async startPush() {
|
||||
if (uni.getSystemInfoSync().platform !== 'app-plus') return
|
||||
|
||||
try {
|
||||
await this.requestMicPermission()
|
||||
|
||||
// 优先用原生 API 获取 Webview(兜底)
|
||||
this.currentWebview = plus.webview.currentWebview() || this.$mp.page.$getAppWebview()
|
||||
if (!this.currentWebview) {
|
||||
throw new Error('无法获取页面 Webview 实例')
|
||||
}
|
||||
|
||||
// 后续创建 pusher + append 逻辑
|
||||
this.pusher = plus.video.createLivePusher('', {
|
||||
/* 配置 */
|
||||
})
|
||||
this.currentWebview.append(this.pusher) // 此时不会再为 null
|
||||
// ... 启动推流
|
||||
} catch (err) {
|
||||
console.error('推流启动失败:', err)
|
||||
}
|
||||
},
|
||||
// 开始推流
|
||||
async startPush2() {
|
||||
console.log('11', uni.getSystemInfoSync().platform)
|
||||
// 1. 端判断
|
||||
if (uni.getSystemInfoSync().platform !== 'android') return
|
||||
console.log('22')
|
||||
try {
|
||||
// 2. 申请麦克风权限
|
||||
// await this.requestMicPermission();
|
||||
console.log('33')
|
||||
// 3. 创建 LivePusher 实例(仅音频,隐藏组件)
|
||||
this.pusher = plus.video.createLivePusher('', {
|
||||
url: 'rtmp://25.18.122.148:9605/voice_in/aa', // 你的 RTMP 推流地址
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
width: '1px', // 隐藏组件(仅音频无需显示)
|
||||
height: '1px',
|
||||
position: 'static',
|
||||
// 核心:仅音频配置
|
||||
video: {
|
||||
enable: false // 关闭视频采集
|
||||
},
|
||||
audio: {
|
||||
enable: true, // 开启音频采集
|
||||
sampleRate: 16000, // 采样率(AI 语音识别常用 16k)
|
||||
bitrate: 64000, // 音频码率
|
||||
codec: 'aac' // 编码格式(RTMP 主流)
|
||||
},
|
||||
// 推流模式:仅音频直播
|
||||
mode: 'rtmp',
|
||||
autopush: false // 不自动推流,手动控制
|
||||
})
|
||||
console.log('44')
|
||||
// 4. 挂载到 Webview
|
||||
this.currentWebview.append(this.pusher)
|
||||
|
||||
// 5. 监听推流状态
|
||||
this.pusher.addEventListener('statechange', e => {
|
||||
console.log('推流状态变化:', e)
|
||||
switch (e.state) {
|
||||
case 'connecting':
|
||||
uni.showToast({ title: '正在连接推流服务器', icon: 'none' })
|
||||
break
|
||||
case 'connected':
|
||||
this.isPushing = true
|
||||
uni.showToast({ title: '推流成功', icon: 'success' })
|
||||
break
|
||||
case 'disconnected':
|
||||
this.isPushing = false
|
||||
uni.showToast({ title: '推流断开', icon: 'none' })
|
||||
break
|
||||
case 'error':
|
||||
this.isPushing = false
|
||||
uni.showToast({ title: `推流错误:${e.error}`, icon: 'none' })
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
// 6. 启动预览 + 推流
|
||||
this.pusher.startPreview() // 启动音视频采集(必须调用)
|
||||
this.pusher.start() // 开始推流
|
||||
} catch (err) {
|
||||
uni.showToast({ title: err, icon: 'none' })
|
||||
console.error('推流启动失败:', err)
|
||||
}
|
||||
},
|
||||
|
||||
// 停止推流
|
||||
stopPush() {
|
||||
if (!this.pusher) return
|
||||
// 停止推流 + 预览
|
||||
this.pusher.stop()
|
||||
this.pusher.stopPreview()
|
||||
// 销毁组件
|
||||
this.pusher.close()
|
||||
this.pusher = null
|
||||
this.isPushing = false
|
||||
uni.showToast({ title: '推流已停止', icon: 'none' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
button {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
import talkCom from './talkCom.vue'
|
||||
</script>
|
||||
@@ -1,131 +0,0 @@
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<video :is-live="true" :src="videoSrc" :autoplay="true" @error="error"></video>
|
||||
<view id="pusher-box"></view>
|
||||
<button class="btn" @click="start">开始推流</button>
|
||||
<button class="btn" @click="pause">暂停推流</button>
|
||||
<button class="btn" @click="resume">预热</button>
|
||||
<button class="btn" @click="stop">停止推流</button>
|
||||
<button class="btn" @click="snapshot">快照</button>
|
||||
<button class="btn" @click="startPreview">开启摄像头预览1</button>
|
||||
<button class="btn" @click="stopPreview">关闭摄像头预览</button>
|
||||
<button class="btn" @click="switchCamera">切换摄像头</button>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { prepareApi } from "@/api/talk.js"
|
||||
var pusher;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
baseName: 'zhangsan',
|
||||
context: null
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
videoSrc(){
|
||||
return 'rtmp://25.18.122.148:9605/voice_out/' + this.baseName
|
||||
},
|
||||
},
|
||||
onReady() {
|
||||
},
|
||||
methods: {
|
||||
statechange(e) {
|
||||
console.log('statechange:', e, JSON.stringify(e))
|
||||
},
|
||||
netstatus(e) {
|
||||
console.log('netstatus:' + JSON.stringify(e))
|
||||
},
|
||||
error(e) {
|
||||
console.log('error:' + JSON.stringify(e))
|
||||
},
|
||||
start: function () {
|
||||
console.log('start')
|
||||
console.log('start',pusher.start)
|
||||
pusher.start(a => {
|
||||
console.log('livePusher.start:')
|
||||
},b=>{
|
||||
console.log('livePusher.start.err:' )
|
||||
})
|
||||
},
|
||||
close: function () {
|
||||
pusher.close({
|
||||
success: a => {
|
||||
console.log('livePusher.close:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
snapshot: function () {
|
||||
pusher.snapshot({
|
||||
success: e => {
|
||||
console.log(JSON.stringify(e))
|
||||
}
|
||||
})
|
||||
},
|
||||
resume: function () {
|
||||
prepareApi(this.baseName).then(res=>{
|
||||
console.log(res)
|
||||
}).catch(err=>{
|
||||
console.log(err)
|
||||
if(err === 'prepare'){
|
||||
this.initPusher()
|
||||
}
|
||||
})
|
||||
},
|
||||
pause: function () {
|
||||
pusher.pause({
|
||||
success: a => {
|
||||
console.log('livePusher.pause:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
stop: function () {
|
||||
pusher.stop({
|
||||
success: a => {
|
||||
console.log(JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
switchCamera: function () {
|
||||
pusher.switchCamera({
|
||||
success: a => {
|
||||
console.log('livePusher.switchCamera:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
startPreview: function () {
|
||||
pusher.startPreview({
|
||||
success: a => {
|
||||
console.log('livePusher.startPreview:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
stopPreview: function () {
|
||||
pusher.stopPreview({
|
||||
success: a => {
|
||||
console.log('livePusher.stopPreview:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
initPusher(){
|
||||
console.log(1)
|
||||
pusher = new plus.video.LivePusher('pusher-box',{
|
||||
url: 'rtmp://25.18.122.148:9605/voice_in/' + this.baseName,
|
||||
"enable-camera": false
|
||||
})
|
||||
pusher.addEventListener('statechange', this.statechange)
|
||||
pusher.addEventListener('netstatus', this.netstatus)
|
||||
pusher.addEventListener('error', this.error)
|
||||
console.log(pusher)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
#pusher-box{
|
||||
width: 100vw;
|
||||
height: 400rpx;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<button @click="startPush" v-if="!isPushing">开始语音推流</button>
|
||||
<button @click="stopPush" v-else>停止语音推流</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isPushing: false, // 推流状态
|
||||
pusher: null, // 推流实例
|
||||
currentWebview: null // 当前 Webview 实例
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
// 改用 onReady(页面渲染完成) + 延迟
|
||||
if (uni.getSystemInfoSync().platform === 'android') {
|
||||
// 安卓端延迟 1000ms,且重试 3 次,确保获取到 Webview
|
||||
let retryCount = 0
|
||||
const getWebview = () => {
|
||||
this.currentWebview = this.$mp.page.$getAppWebview()
|
||||
if (this.currentWebview) {
|
||||
console.log('Webview 获取成功:', this.currentWebview)
|
||||
return
|
||||
}
|
||||
retryCount++
|
||||
if (retryCount < 3) {
|
||||
setTimeout(getWebview, 500) // 每次重试间隔 500ms
|
||||
} else {
|
||||
uni.showToast({ title: 'Webview 初始化失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
setTimeout(getWebview, 1000) // 初始延迟 1 秒
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// // 仅 App 端初始化 Webview
|
||||
// if (uni.getSystemInfoSync().platform !== 'app-plus') {
|
||||
// uni.showToast({ title: '仅支持 App 端推流', icon: 'none' });
|
||||
// return;
|
||||
// }
|
||||
// this.currentWebview = this.$mp.page.$getAppWebview();
|
||||
},
|
||||
onUnload() {
|
||||
// 页面销毁时停止推流并销毁组件
|
||||
this.stopPush()
|
||||
},
|
||||
methods: {
|
||||
// 申请麦克风权限
|
||||
async requestMicPermission() {
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.android.requestPermissions(
|
||||
['android.permission.RECORD_AUDIO'], // Android 权限
|
||||
res => {
|
||||
const granted = res.filter(item => item.granted).length === 1
|
||||
granted ? resolve() : reject('麦克风权限申请失败')
|
||||
},
|
||||
err => reject(err)
|
||||
)
|
||||
// iOS 权限由系统自动弹窗,无需手动申请,此处可统一处理
|
||||
})
|
||||
},
|
||||
async startPush() {
|
||||
if (uni.getSystemInfoSync().platform !== 'app-plus') return
|
||||
|
||||
try {
|
||||
await this.requestMicPermission()
|
||||
|
||||
// 优先用原生 API 获取 Webview(兜底)
|
||||
this.currentWebview = plus.webview.currentWebview() || this.$mp.page.$getAppWebview()
|
||||
if (!this.currentWebview) {
|
||||
throw new Error('无法获取页面 Webview 实例')
|
||||
}
|
||||
|
||||
// 后续创建 pusher + append 逻辑
|
||||
this.pusher = plus.video.createLivePusher('', {
|
||||
/* 配置 */
|
||||
})
|
||||
this.currentWebview.append(this.pusher) // 此时不会再为 null
|
||||
// ... 启动推流
|
||||
} catch (err) {
|
||||
console.error('推流启动失败:', err)
|
||||
}
|
||||
},
|
||||
// 开始推流
|
||||
async startPush2() {
|
||||
console.log('11', uni.getSystemInfoSync().platform)
|
||||
// 1. 端判断
|
||||
if (uni.getSystemInfoSync().platform !== 'android') return
|
||||
console.log('22')
|
||||
try {
|
||||
// 2. 申请麦克风权限
|
||||
// await this.requestMicPermission();
|
||||
console.log('33')
|
||||
// 3. 创建 LivePusher 实例(仅音频,隐藏组件)
|
||||
this.pusher = plus.video.createLivePusher('', {
|
||||
url: 'rtmp://25.18.122.148:9605/voice_in/aa', // 你的 RTMP 推流地址
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
width: '1px', // 隐藏组件(仅音频无需显示)
|
||||
height: '1px',
|
||||
position: 'static',
|
||||
// 核心:仅音频配置
|
||||
video: {
|
||||
enable: false // 关闭视频采集
|
||||
},
|
||||
audio: {
|
||||
enable: true, // 开启音频采集
|
||||
sampleRate: 16000, // 采样率(AI 语音识别常用 16k)
|
||||
bitrate: 64000, // 音频码率
|
||||
codec: 'aac' // 编码格式(RTMP 主流)
|
||||
},
|
||||
// 推流模式:仅音频直播
|
||||
mode: 'rtmp',
|
||||
autopush: false // 不自动推流,手动控制
|
||||
})
|
||||
console.log('44')
|
||||
// 4. 挂载到 Webview
|
||||
this.currentWebview.append(this.pusher)
|
||||
|
||||
// 5. 监听推流状态
|
||||
this.pusher.addEventListener('statechange', e => {
|
||||
console.log('推流状态变化:', e)
|
||||
switch (e.state) {
|
||||
case 'connecting':
|
||||
uni.showToast({ title: '正在连接推流服务器', icon: 'none' })
|
||||
break
|
||||
case 'connected':
|
||||
this.isPushing = true
|
||||
uni.showToast({ title: '推流成功', icon: 'success' })
|
||||
break
|
||||
case 'disconnected':
|
||||
this.isPushing = false
|
||||
uni.showToast({ title: '推流断开', icon: 'none' })
|
||||
break
|
||||
case 'error':
|
||||
this.isPushing = false
|
||||
uni.showToast({ title: `推流错误:${e.error}`, icon: 'none' })
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
// 6. 启动预览 + 推流
|
||||
this.pusher.startPreview() // 启动音视频采集(必须调用)
|
||||
this.pusher.start() // 开始推流
|
||||
} catch (err) {
|
||||
uni.showToast({ title: err, icon: 'none' })
|
||||
console.error('推流启动失败:', err)
|
||||
}
|
||||
},
|
||||
|
||||
// 停止推流
|
||||
stopPush() {
|
||||
if (!this.pusher) return
|
||||
// 停止推流 + 预览
|
||||
this.pusher.stop()
|
||||
this.pusher.stopPreview()
|
||||
// 销毁组件
|
||||
this.pusher.close()
|
||||
this.pusher = null
|
||||
this.isPushing = false
|
||||
uni.showToast({ title: '推流已停止', icon: 'none' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
button {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<view>
|
||||
<video :is-live="true" :src="videoSrc" :autoplay="true" @error="error"></video>
|
||||
<view id="pusher-box" class="pusher-box"></view>
|
||||
<button class="btn" @click="start">开始推流1</button>
|
||||
<button class="btn" @click="pause">暂停推流</button>
|
||||
<button class="btn" @click="resume">预热</button>
|
||||
<button class="btn" @click="stop">停止推流</button>
|
||||
<button class="btn" @click="snapshot">快照</button>
|
||||
<button class="btn" @click="startPreview">开启摄像头预览1</button>
|
||||
<button class="btn" @click="stopPreview">关闭摄像头预览</button>
|
||||
<button class="btn" @click="switchCamera">切换摄像头</button>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
// import {
|
||||
// prepareApi
|
||||
// } from "@/api/talk.js";
|
||||
// var pusher;
|
||||
// export default ({
|
||||
// data() {
|
||||
// return {
|
||||
// baseName: 'zhangsan',
|
||||
// context: null
|
||||
// }
|
||||
// },
|
||||
// computed: {
|
||||
// videoSrc() {
|
||||
// return 'rtmp://25.18.122.148:9605/voice_out/' + this.baseName;
|
||||
// },
|
||||
// },
|
||||
// onReady() {},
|
||||
// methods: {
|
||||
// statechange(e) {
|
||||
// console.log('statechange:', e, JSON.stringify(e));
|
||||
// },
|
||||
// netstatus(e) {
|
||||
// console.log('netstatus:' + JSON.stringify(e));
|
||||
// },
|
||||
// error(e) {
|
||||
// console.log('error:' + JSON.stringify(e));
|
||||
// },
|
||||
// start: function() {
|
||||
// console.log('start');
|
||||
// console.log('start', pusher.start);
|
||||
// pusher.start(a => {
|
||||
// console.log('livePusher.start:');
|
||||
// }, b => {
|
||||
// console.log('livePusher.start.err:');
|
||||
// });
|
||||
// },
|
||||
// close: function() {
|
||||
// pusher.close({
|
||||
// success: a => {
|
||||
// console.log('livePusher.close:' + JSON.stringify(a));
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// snapshot: function() {
|
||||
// pusher.snapshot({
|
||||
// success: e => {
|
||||
// console.log(JSON.stringify(e));
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// resume: function() {
|
||||
// prepareApi(this.baseName).then(res => {
|
||||
// console.log(res)
|
||||
// }).catch(err => {
|
||||
// console.log(err)
|
||||
// if (err === 'prepare') {
|
||||
// this.initPusher()
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// pause: function() {
|
||||
// pusher.pause({
|
||||
// success: a => {
|
||||
// console.log('livePusher.pause:' + JSON.stringify(a))
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// stop: function() {
|
||||
// pusher.stop({
|
||||
// success: a => {
|
||||
// console.log(JSON.stringify(a))
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// switchCamera: function() {
|
||||
// pusher.switchCamera({
|
||||
// success: a => {
|
||||
// console.log('livePusher.switchCamera:' + JSON.stringify(a))
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// startPreview: function() {
|
||||
// pusher.startPreview({
|
||||
// success: a => {
|
||||
// console.log('livePusher.startPreview:' + JSON.stringify(a))
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// stopPreview: function() {
|
||||
// pusher.stopPreview({
|
||||
// success: a => {
|
||||
// console.log('livePusher.stopPreview:' + JSON.stringify(a))
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// initPusher() {
|
||||
// console.log(1)
|
||||
// pusher = new plus.video.LivePusher('pusher-box', {
|
||||
// url: 'rtmp://25.18.122.148:9605/voice_in/' + this.baseName,
|
||||
// "enable-camera": false
|
||||
// })
|
||||
// pusher.addEventListener('statechange', this.statechange)
|
||||
// pusher.addEventListener('netstatus', this.netstatus)
|
||||
// pusher.addEventListener('error', this.error)
|
||||
// console.log(pusher)
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
</script>
|
||||
@@ -227,7 +227,7 @@
|
||||
// #endif
|
||||
}
|
||||
const toTalking = () => {
|
||||
common.navigateTo('/pages/sparring/talk?traId=' + traId.value + '&chaId=' + chaId)
|
||||
common.navigateTo('/pages/sparring/talk?traId=' + traId.value + '&chaId=' + chaId.value)
|
||||
}
|
||||
const activeVoiceTalkingItemId = ref('')
|
||||
// 关闭播放状态
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 369 KiB After Width: | Height: | Size: 301 KiB |
Reference in New Issue
Block a user