- 发布:2023-05-28 18:56
- 更新:2024-01-26 11:12
- 阅读:398
产品分类: uniapp/App
PC开发环境操作系统: Windows
PC开发环境操作系统版本号: Windows10
HBuilderX类型: 正式
HBuilderX版本号: 3.8.3
手机系统: 全部
页面类型: nvue
vue版本: vue2
打包方式: 云端
项目创建方式: HBuilderX
测试过的手机:
示例代码:
<template>
<view>
<live-pusher @click="pusherClick" id='livePusher' ref="livePusher" :style="'height:'+winHeight+'px;'" style="width: 750rpx;"
url="url" :mode="mode" :muted="muted" :enable-camera="enableCamera" :auto-focus="autofocus"
beauty="beauty" :whiteness="whiteness" :aspect="aspect" :orientation="orientation"
min-bitrate="minBitrate" :max-bitrate="maxBitrate" :audio-quality="audioQuality"
waiting-image="waitingImage" :waiting-image-hash="waitingImageHash" :zoom="zoom"
device-position="devicePosition" :background-mute="backgroundMute" :remote-mirror="remoteMirror"
local-mirror="localMirror" :audio-reverb-type="audioReverbType" :enable-mic="enableMic"
enable-agc="enableAgc" :enable-ans="enableAns" :audio-volume-type="audioVolumeType"
@statechange="statechange" @netstatus="netstatus" @error="error">
</live-pusher>
<view class=""
style="position: fixed;right: 0;width: 750rpx;right: 0;align-items: center;justify-content: center;"
style="'top:'+barH+'px;'">
<view class=""
style="height: 250rpx;width: 720rpx;background-color: rgba(0, 0, 0, .389);border-radius: 50rpx;padding: 25rpx;flex-direction: row;align-items: center;justify-content: center;">
<view class="" style="position: relative;width: 150rpx;height: 150rpx;border-radius: 10rpx;">
<image
style="position: absolute;left: 0;right: 0;bottom: 0;right: 0;width: 150rpx;height: 150rpx;border-radius: 10rpx;"
src="../../static/logo.png" mode=""></image>
<view class=""
style="width: 150rpx;height: 40rpx;background-color: rgba(0, 0, 0, .389);bottom: 0;right: 0;left: 0;position: absolute;justify-content: center;align-items: center;">
<text style="font-size: 13px;color: #fff;text-align: center;">{{push_cover}}</text>
</view>
</view>
<view class="" style="flex: 1;margin-left: 25rpx;width: 515rpx;">
<view class="" style="flex-direction: row;" @click="popOpen">
<text style="color: #fff;font-size: 13px;">{{push_roomType}}:</text>
<text style="color: #9d65e1;font-size: 13px;">{{radiovalue7}}</text>
</view>
<view class="" style="flex-direction: row;align-items: center;margin-top: 20rpx;"
v-if="roomType == 2">
<text style="color: #fff;font-size: 13px;">{{push_roomPass}}:</text>
<view class="u-demo-block__content">
<u-code-input v-model="value3" :space="0" :maxlength="4" :size="25" color="#9d65e1" hairline borderColor="#9d65e1"></u-code-input>
</view>
</view>
<view class="" style="flex-direction: row;align-items: center;margin-top: 20rpx;"
v-if="roomType == 1">
<text style="color: #fff;font-size: 13px;">{{push_roomMoney}}:</text>
<u-number-box color="#fff" iconStyle="color: #fff" min="1" max="100" step="0.01" bgColor="#9d65e1" :buttonSize="25" v-model="value" @change="valChange"></u-number-box>
</view>
</view>
</view>
</view>
<view class="" style="width: 750rpx;position: fixed;flex-direction: row;" :style="'top:'+(barH+getPx(250))+'px;height:'+(winHeight - barH - getPx(250) - 100)+'px;'">
<view class="" style="width: 550rpx;">
</view>
<view class="" style="width: 200rpx;">
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/camera.png" :label="push_reversal" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/clarity.png" :label="push_quality" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/beauty.png" :label="push_beauty" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/whitening.png" :label="push_whitening" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon @click="backPage" name="close-circle-fill" color="#fff" label="退出直播" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
</view>
</view>
<view class="" style="width: 750rpx;position: fixed;bottom: 0;height: 100px;align-items: center;justify-content: center;flex-direction: row;">
<view class="" style="width: 500rpx;">
<u-button @click="start" text="开始直播" color="linear-gradient(to right, rgb(66, 83, 216), rgb(213, 51, 186))" shape="circle" iconColor="#fff" icon="camera-fill"></u-button>
</view>
</view>
<u-popup :show="show" @close="close1" bgColor="transparent" round='15'>
<view :style="'height: '+(winHeight/2)+'px;'" :class="['bgPage'+theme]" style="border-radius: 15px;">
<view class="" style="margin-top: 35rpx;align-items: center;justify-content: center;">
<text :style="theme == '_light' ?'color:#000;':'color:#fff;'" style="font-size: 14px;">类型选择</text>
</view>
<view class="" style="margin: 20rpx;">
<view>
<view class="u-page__radio-item">
<u-radio-group @change="roomTypeChange" v-model="radiovalue7" :borderBottom="true"
placement="column" iconPlacement="right">
<u-radio :labelColor="theme == '_light' ? '#000':'#fff'"
customStyle="{marginBottom: '16px'}" v-for="(item, index) in radiolist7"
key="index" :label="item.name" :name="item.name">
</u-radio>
</u-radio-group>
</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import $t from '@/i18n/index.js';
import {
mapGetters
} from 'vuex';
export default {
data() {
return {
url: "rtmp://192.168.31.96/live/livestream?token=1234566&sign=123", //推流地址
mode: "", //推流视频模式,可取值:SD(标清), HD(高清), FHD(超清)。
aspect: "9:16", //宽高比
muted: false, //是否静音
enableCamera: true, //是否开启摄像头
autofocus: true, //自动聚焦
beauty: 0, //美颜,取值范围 0-9(iOS取值范围为1即0-0.9-1) ,0 表示关闭。
whiteness: 0, //美白,取值范围 0-9(iOS取值范围为1) ,0 表示关闭。同上
orientation: "vertical", //vertical竖屏horizontal横屏
minBitrate: 200, //最小码率
maxBitrate: 1000, //最大码率
audioQuality: "high", //高音质(48KHz)或低音质(16KHz),值为high, low
waitingImage: "../../static/push/leave.png", //进入后台时推流的等待画面
waitingImageHash: "3c846863a47d2656cc5ad7326f6aee03", //等待画面资源的MD5值
zoom: false, //调整焦距
devicePosition: "front", //前置或后置,值为front, back
backgroundMute: false, //进入后台时是否静音
remoteMirror: false, //推流是否镜像
localMirror: "disable", //auto前置摄像头镜像,后置摄像头不镜像,enable前后置摄像头均镜像,disable前后置摄像头均不镜像
audioReverbType: 0, //0关闭1KTV2小房间3大会堂4低沉5洪亮6金属声7磁性
enableMic: false, //开启或关闭麦克风
enableAgc: false, //是否开启音频自动增益
enableAns: false, //是否开启音频噪声抑制
audioVolumeType: "media", //media 媒体音量 voicecall 通话音量
winHeight: 0, //系统高度
context: null, //推流上下文
barH: 0, //状态栏高度
show: false,
//横向两端排列形式数据
radiolist7: [],
// u-radio-group的v-model绑定的值如果设置为某个radio的name,就会被默认选中
radiovalue7: '',
roomType: 0, //房间类型
isBack:false
}
},
onReady() {
plus.navigator.setFullscreen(false);
plus.navigator.setStatusBarStyle("light");
this.winHeight = uni.$u.sys()['windowHeight']; //获取系统高度
this.barH = uni.$u.sys()['statusBarHeight']; //状态栏高度
// 注意:需要在onReady中 或 onLoad 延时
this.context = uni.createLivePusherContext("livePusher", this);
this.startPreview(); //开启摄像头预览
},
onBackPress(e) {
console.log(e);
if(!this.isBack){
return true;
}
},
onLoad() {
this.radiovalue7 = this.push_commonRoom
//必须要调用这个才能禁止ios的左侧滑动返回
plus.webview.currentWebview().setStyle({
'popGesture': 'none'
});
},
onShow() {
if(!uni.$u.test.isEmpty(this.context)){
this.startPreview(); //开启摄像头预览
setTimeout(()=>{
this.resume()
},1000)
}
this.radiolist7 = [{
id: 0,
name: this.push_commonRoom,
disabled: false
},
{
id: 2,
name: this.push_passwordRoom,
disabled: false
},
{
id: 1,
name: this.push_timeRoom,
disabled: false
},
]
},
methods: {
backPage(){
this.isBack = true
uni.navigateBack()
},
getPx(value) {
let val = parseInt(uni.upx2px(Number(value)))
return val % 2 === 0 ? val : val + 1
},
pusherClick(){
uni.hideKeyboard();
},
popOpen() {
uni.hideKeyboard();
this.show = true;
},
roomTypeChange(e) {
console.log(e);
this.radiolist7.forEach((v, i) => {
console.log(v);
if (e == v.name) {
this.roomType = v.id
console.log(this.roomType);
}
})
this.close1()
},
close1() {
this.show = false
},
statechange(e) {
console.log(e);
},
netstatus(e) {
console.log("netstatus:" + JSON.stringify(e));
},
error(e) {
console.log("error:" + JSON.stringify(e));
},
start: function() {
this.context.start({
success: (a) => {
console.log("livePusher.start:" + JSON.stringify(a));
}
});
},
close() {
this.context.close({
success: (a) => {
console.log("livePusher.close:" + JSON.stringify(a));
}
});
},
snapshot() {
this.context.snapshot({
success: (e) => {
console.log(JSON.stringify(e));
}
});
},
resume() {
this.context.resume({
success: (a) => {
console.log("livePusher.resume:" + JSON.stringify(a));
}
});
},
pause() {
this.context.pause({
success: (a) => {
console.log("livePusher.pause:" + JSON.stringify(a));
}
});
},
stop() {
this.context.stop({
success: (a) => {
console.log(JSON.stringify(a));
}
});
},
switchCamera() {
this.context.switchCamera({
success: (a) => {
console.log("livePusher.switchCamera:" + JSON.stringify(a));
}
});
},
startPreview(){
this.context.startPreview({
success: (a) => {
console.log("livePusher.startPreview:" + JSON.stringify(a));
},
fail: (e) => {
uni.$u.toast('摄像头开启失败,请检查是否基于app摄像头权限')
}
});
},
stopPreview() {
this.context.stopPreview({
success: (a) => {
console.log("livePusher.stopPreview:" + JSON.stringify(a));
}
});
}
},
computed: {
...mapGetters(['theme', 'language', 'conf']),
push_commonRoom() {
return $t('push_commonRoom', this.language);
},
push_passwordRoom() {
return $t('push_passwordRoom', this.language);
},
push_timeRoom() {
return $t('push_timeRoom', this.language);
},
push_roomType() {
return $t('push_roomType', this.language);
},
push_roomPass() {
return $t('push_roomPass', this.language);
},
push_roomMoney() {
return $t('push_roomMoney', this.language);
},
push_reversal() {
return $t('push_reversal', this.language);
},
push_quality() {
return $t('push_quality', this.language);
},
push_beauty() {
return $t('push_beauty', this.language);
},
push_whitening() {
return $t('push_whitening', this.language);
},
push_cover() {
return $t('push_cover', this.language);
}
}
}
</script>
<style>
</style>
</live-pusher>
<view class=""
style="position: fixed;right: 0;width: 750rpx;right: 0;align-items: center;justify-content: center;"
style="'top:'+barH+'px;'">
<view class=""
style="height: 250rpx;width: 720rpx;background-color: rgba(0, 0, 0, .389);border-radius: 50rpx;padding: 25rpx;flex-direction: row;align-items: center;justify-content: center;">
<view class="" style="position: relative;width: 150rpx;height: 150rpx;border-radius: 10rpx;">
<image
style="position: absolute;left: 0;right: 0;bottom: 0;right: 0;width: 150rpx;height: 150rpx;border-radius: 10rpx;"
src="../../static/logo.png" mode=""></image>
<view class=""
style="width: 150rpx;height: 40rpx;background-color: rgba(0, 0, 0, .389);bottom: 0;right: 0;left: 0;position: absolute;justify-content: center;align-items: center;">
<text style="font-size: 13px;color: #fff;text-align: center;">{{push_cover}}</text>
</view>
</view>
<view class="" style="flex: 1;margin-left: 25rpx;width: 515rpx;">
<view class="" style="flex-direction: row;" @click="popOpen">
<text style="color: #fff;font-size: 13px;">{{push_roomType}}:</text>
<text style="color: #9d65e1;font-size: 13px;">{{radiovalue7}}</text>
</view>
<view class="" style="flex-direction: row;align-items: center;margin-top: 20rpx;"
v-if="roomType == 2">
<text style="color: #fff;font-size: 13px;">{{push_roomPass}}:</text>
<view class="u-demo-block__content">
<u-code-input v-model="value3" :space="0" :maxlength="4" :size="25" color="#9d65e1" hairline borderColor="#9d65e1"></u-code-input>
</view>
</view>
<view class="" style="flex-direction: row;align-items: center;margin-top: 20rpx;"
v-if="roomType == 1">
<text style="color: #fff;font-size: 13px;">{{push_roomMoney}}:</text>
<u-number-box color="#fff" iconStyle="color: #fff" min="1" max="100" step="0.01" bgColor="#9d65e1" :buttonSize="25" v-model="value" @change="valChange"></u-number-box>
</view>
</view>
</view>
</view>
<view class="" style="width: 750rpx;position: fixed;flex-direction: row;" :style="'top:'+(barH+getPx(250))+'px;height:'+(winHeight - barH - getPx(250) - 100)+'px;'">
<view class="" style="width: 550rpx;">
</view>
<view class="" style="width: 200rpx;">
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/camera.png" :label="push_reversal" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/clarity.png" :label="push_quality" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/beauty.png" :label="push_beauty" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon name="../../static/push/whitening.png" :label="push_whitening" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
<view class="" style="width: 200rpx;height: 75px;align-items: center;justify-content: center;">
<u-icon @click="backPage" name="close-circle-fill" color="#fff" label="退出直播" labelPos="bottom" labelColor="#fff" size="28"></u-icon>
</view>
</view>
</view>
<view class="" style="width: 750rpx;position: fixed;bottom: 0;height: 100px;align-items: center;justify-content: center;flex-direction: row;">
<view class="" style="width: 500rpx;">
<u-button @click="start" text="开始直播" color="linear-gradient(to right, rgb(66, 83, 216), rgb(213, 51, 186))" shape="circle" iconColor="#fff" icon="camera-fill"></u-button>
</view>
</view>
<u-popup :show="show" @close="close1" bgColor="transparent" round='15'>
<view :style="'height: '+(winHeight/2)+'px;'" :class="['bgPage'+theme]" style="border-radius: 15px;">
<view class="" style="margin-top: 35rpx;align-items: center;justify-content: center;">
<text :style="theme == '_light' ?'color:#000;':'color:#fff;'" style="font-size: 14px;">类型选择</text>
</view>
<view class="" style="margin: 20rpx;">
<view>
<view class="u-page__radio-item">
<u-radio-group @change="roomTypeChange" v-model="radiovalue7" :borderBottom="true"
placement="column" iconPlacement="right">
<u-radio :labelColor="theme == '_light' ? '#000':'#fff'"
customStyle="{marginBottom: '16px'}" v-for="(item, index) in radiolist7"
key="index" :label="item.name" :name="item.name">
</u-radio></u-radio-group>
</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import $t from '@/i18n/index.js';
import {
mapGetters
} from 'vuex';
export default {
data() {
return {
url: "rtmp://192.168.31.96/live/livestream?token=1234566&sign=123", //推流地址
mode: "", //推流视频模式,可取值:SD(标清), HD(高清), FHD(超清)。
aspect: "9:16", //宽高比
muted: false, //是否静音
enableCamera: true, //是否开启摄像头
autofocus: true, //自动聚焦
beauty: 0, //美颜,取值范围 0-9(iOS取值范围为1即0-0.9-1) ,0 表示关闭。
whiteness: 0, //美白,取值范围 0-9(iOS取值范围为1) ,0 表示关闭。同上
orientation: "vertical", //vertical竖屏horizontal横屏
minBitrate: 200, //最小码率
maxBitrate: 1000, //最大码率
audioQuality: "high", //高音质(48KHz)或低音质(16KHz),值为high, low
waitingImage: "../../static/push/leave.png", //进入后台时推流的等待画面
waitingImageHash: "3c846863a47d2656cc5ad7326f6aee03", //等待画面资源的MD5值
zoom: false, //调整焦距
devicePosition: "front", //前置或后置,值为front, back
backgroundMute: false, //进入后台时是否静音
remoteMirror: false, //推流是否镜像
localMirror: "disable", //auto前置摄像头镜像,后置摄像头不镜像,enable前后置摄像头均镜像,disable前后置摄像头均不镜像
audioReverbType: 0, //0关闭1KTV2小房间3大会堂4低沉5洪亮6金属声7磁性
enableMic: false, //开启或关闭麦克风
enableAgc: false, //是否开启音频自动增益
enableAns: false, //是否开启音频噪声抑制
audioVolumeType: "media", //media 媒体音量 voicecall 通话音量
winHeight: 0, //系统高度
context: null, //推流上下文
barH: 0, //状态栏高度
show: false,
//横向两端排列形式数据
radiolist7: [],
// u-radio-group的v-model绑定的值如果设置为某个radio的name,就会被默认选中
radiovalue7: '',
roomType: 0, //房间类型
isBack:false
}
},
onReady() {
plus.navigator.setFullscreen(false);
plus.navigator.setStatusBarStyle("light");
this.winHeight = uni.$u.sys()['windowHeight']; //获取系统高度
this.barH = uni.$u.sys()['statusBarHeight']; //状态栏高度
// 注意:需要在onReady中 或 onLoad 延时
this.context = uni.createLivePusherContext("livePusher", this);
this.startPreview(); //开启摄像头预览
},
onBackPress(e) {
console.log(e);
if(!this.isBack){
return true;
}
},
onLoad() {
this.radiovalue7 = this.push_commonRoom
//必须要调用这个才能禁止ios的左侧滑动返回
plus.webview.currentWebview().setStyle({
'popGesture': 'none'
});
},
onShow() {
if(!uni.$u.test.isEmpty(this.context)){
this.startPreview(); //开启摄像头预览
setTimeout(()=>{
this.resume()
},1000)
}
this.radiolist7 = [{
id: 0,
name: this.push_commonRoom,
disabled: false
},
{
id: 2,
name: this.push_passwordRoom,
disabled: false
},
{
id: 1,
name: this.push_timeRoom,
disabled: false
},
]
},
methods: {
backPage(){
this.isBack = true
uni.navigateBack()
},
getPx(value) {
let val = parseInt(uni.upx2px(Number(value)))
return val % 2 === 0 ? val : val + 1
},
pusherClick(){
uni.hideKeyboard();
},
popOpen() {
uni.hideKeyboard();
this.show = true;
},
roomTypeChange(e) {
console.log(e);
this.radiolist7.forEach((v, i) => {
console.log(v);
if (e == v.name) {
this.roomType = v.id
console.log(this.roomType);
}
})
this.close1()
},
close1() {
this.show = false
},
statechange(e) {
console.log(e);
},
netstatus(e) {
console.log("netstatus:" + JSON.stringify(e));
},
error(e) {
console.log("error:" + JSON.stringify(e));
},
start: function() {
this.context.start({
success: (a) => {
console.log("livePusher.start:" + JSON.stringify(a));
}
});
},
close() {
this.context.close({
success: (a) => {
console.log("livePusher.close:" + JSON.stringify(a));
}
});
},
snapshot() {
this.context.snapshot({
success: (e) => {
console.log(JSON.stringify(e));
}
});
},
resume() {
this.context.resume({
success: (a) => {
console.log("livePusher.resume:" + JSON.stringify(a));
}
});
},
pause() {
this.context.pause({
success: (a) => {
console.log("livePusher.pause:" + JSON.stringify(a));
}
});
},
stop() {
this.context.stop({
success: (a) => {
console.log(JSON.stringify(a));
}
});
},
switchCamera() {
this.context.switchCamera({
success: (a) => {
console.log("livePusher.switchCamera:" + JSON.stringify(a));
}
});
},
startPreview(){
this.context.startPreview({
success: (a) => {
console.log("livePusher.startPreview:" + JSON.stringify(a));
},
fail: (e) => {
uni.$u.toast('摄像头开启失败,请检查是否基于app摄像头权限')
}
});
},
stopPreview() {
this.context.stopPreview({
success: (a) => {
console.log("livePusher.stopPreview:" + JSON.stringify(a));
}
});
}
},
computed: {
...mapGetters(['theme', 'language', 'conf']),
push_commonRoom() {
return $t('push_commonRoom', this.language);
},
push_passwordRoom() {
return $t('push_passwordRoom', this.language);
},
push_timeRoom() {
return $t('push_timeRoom', this.language);
},
push_roomType() {
return $t('push_roomType', this.language);
},
push_roomPass() {
return $t('push_roomPass', this.language);
},
push_roomMoney() {
return $t('push_roomMoney', this.language);
},
push_reversal() {
return $t('push_reversal', this.language);
},
push_quality() {
return $t('push_quality', this.language);
},
push_beauty() {
return $t('push_beauty', this.language);
},
push_whitening() {
return $t('push_whitening', this.language);
},
push_cover() {
return $t('push_cover', this.language);
}
}
}
</script>
<style>
</style>
操作步骤:
开启推流-切换后台-等待三秒-切回应用-onShow开启摄像头预览-开始黑屏或花屏此时有音频输出,在安卓下高度可设置,在ios下高度只有一半
开启推流-切换后台-等待三秒-切回应用-onShow开启摄像头预览-开始黑屏或花屏此时有音频输出,在安卓下高度可设置,在ios下高度只有一半
预期结果:
可正常推流,ios预览高度正常
可正常推流,ios预览高度正常
实际结果:
无法正常推流,ios高度不正常
无法正常推流,ios高度不正常
bug描述:
live-pusher切到后台在切回应用必定黑屏或花屏,推流过程中 切出到后台,等待几秒切回应用onShow调用开启摄像头预览,然后有音频输出 画面黑屏或者花屏,测试过同类推流组件比如阿里推流是正常的。
adcold (作者)
上诉代码就是demo 把i18n去掉就行了
2023-05-31 13:45
DCloud_iOS_XHY
回复 adcold: 需要完整的工程,页面中使用 live-pusher 最基础组件复现问题,不要封装
2023-05-31 18:12