Hbuild中h5直播

总结
  • 延迟比较高大概在5-8秒左右,原因是基于tcp的传输;
  • 目前使用情况来看,效果不是太好,假如上传服务断了,没有明显的回调告知;
// 推流
<template>
    <!-- 推送 -->
    <div class="live_push">
        <x-header :left-options="{backText: '', preventGoBack: true}" @on-click-back="onBack">推流</x-header>
        <div id="pusher" class="pusher_wrap"></div>
        <!-- <div>
            <textarea  v-model="url" placeholder="请输入auth_key" style="width:100%;" rows="5"></textarea>
            <button @click="handleSetUrl">确定</button>
        </div> -->
        <footer class="footer_bar" id="parentWebview">
            <div @click="handleSwitchMuteStatus">
                <svg class="dd_iconfont" aria-hidden="true">
                    <use xlink:href="#iconaudio"></use>
                </svg>
            </div>
            <div @click="handleSwitchCamera">
                <svg class="dd_iconfont" aria-hidden="true">
                    <use xlink:href="#iconjingtouqiehuan"></use>
                </svg>
            </div>
            <div @click="handlePlayStatus">
                <svg class="dd_iconfont" aria-hidden="true">
                    <use :xlink:href="playStatus === 0 ? '#iconkaishi' : playStatus === 1 ? '#iconbofangzanting' :
                        playStatus === 2 ? '#iconkaishi' : '#iconbofangzanting'"></use>
                </svg>
            </div>
            <div @click="onBack">
                <svg class="dd_iconfont" aria-hidden="true">
                    <use xlink:href="#icontuichu"></use>
                </svg>
            </div>
        </footer>
    </div>
</template>

<script>
import { XHeader } from 'vux';
export default {
    components: {
        XHeader
    },
    data() {
        return {
            playStatus: 0, // 0未开始 1 开始 2暂停 3恢复
            muteStatus: true, // true 开启 false关闭
            pusher: null,
            url: 'rtmp://blcs.fnptt.cn/mfs_test/mfs_test_stream?auth_key=1656920156-0-0-6fe9847c28d311a309505f9db6a49e7c'
        };
    },
    mounted() {
        this.init();
    },
    methods: {
        init() {
            if (!window.plus) return;
            // document.addEventListener('plusready', this.plusReady(), false);
            this.plusReady();
        },
        plusReady() {
            // const pusherWidth = document.body.offsetWidth + 'px';
            const pusherHeight = document.body.offsetHeight - 87 + 'px';
            const pusherWidth = '100%';
            // const pusherHeight = '300px';
            // 创建直播推流控件
            const pusher = new window.plus.video.LivePusher('pusher', {
                url: 'rtmp://blcs.fnptt.cn/mfs_test/mfs_test_stream?auth_key=1656920156-0-0-6fe9847c28d311a309505f9db6a49e7c',
                top: '47px',
                width: pusherWidth,
                height: pusherHeight,
                position: 'static',
                mode: 'HD',
                aspect: '9:16',
                zindex: 0
            });
            pusher.setStyles({'zindex': 0});
            window.plus.webview.currentWebview().append(pusher);
            this.pusher = pusher;
            pusher.addEventListener('statechange', (e) => {
                e = JSON.stringify(e);
                const code = e.detail.code || '';
                switch (code) {
                case 1001: // 已经连接推流服务器
                    console.log(e.type, '已经连接推流服务器');
                    break;
                case 1002: // 已经与服务器握手完毕,开始推流
                    console.log(e.type, '已经与服务器握手完毕,开始推流');
                    break;
                case 1003: // 打开摄像头成功
                    console.log(e.type, '打开摄像头成功');
                    break;
                case 1004: // 录屏启动成功
                    console.log(e.type, '录屏启动成功');
                    break;
                case 1005: // 推流动态调整分辨率
                    console.log(e.type, '推流动态调整分辨率');
                    break;
                case 1006: // 推流动态调整码率
                    console.log(e.type, '推流动态调整码率');
                    break;
                case 1007: // 首帧画面采集完成
                    console.log(e.type, '首帧画面采集完成');
                    break;
                case 1008: // 编码器启动
                    console.log(e.type, '编码器启动');
                    break;
                case -1301: // 打开摄像头失败
                    console.log(e.type, '打开摄像头失败');
                    this.nativeUIToast('打开摄像头失败', 'middle');
                    break;
                case -1302: // 打开麦克风失败
                    console.log(e.type, '打开麦克风失败');
                    this.nativeUIToast('打开麦克风失败', 'middle');
                    break;
                case -1303: // 视频编码失败
                    console.log(e.type, '视频编码失败');
                    this.nativeUIToast('视频编码失败', 'middle');
                    break;
                case -1304: // 音频编码失败
                    console.log(e.type, '音频编码失败');
                    this.nativeUIToast('音频编码失败', 'middle');
                    break;
                case -1305: // 不支持的视频分辨率
                    console.log(e.type, '不支持的视频分辨率');
                    this.nativeUIToast('不支持的视频分辨率', 'middle');
                    break;
                case -1306: // 不支持的音频采样率
                    console.log(e.type, '不支持的音频采样率');
                    this.nativeUIToast('不支持的音频采样率', 'middle');
                    break;
                case -1307: // 网络断连,且经多次重连抢救无效,更多重试请自行重启推流
                    console.log(e.type, '网络断连,且经多次重连抢救无效,更多重试请自行重启推流');
                    this.nativeUIToast('网络断连,且经多次重连抢救无效,更多重试请自行重启推流', 'middle');
                    break;
                case -1308: // 开始录屏失败,可能是被用户拒绝
                    console.log(e.type, '开始录屏失败,可能是被用户拒绝');
                    this.nativeUIToast('开始录屏失败,可能是被用户拒绝', 'middle');
                    break;
                case -1309: // 录屏失败,不支持的Android系统版本,需要5.0以上的系统
                    console.log(e.type, '录屏失败,不支持的Android系统版本,需要5.0以上的系统');
                    this.nativeUIToast('录屏失败,不支持的Android系统版本,需要5.0以上的系统', 'middle');
                    break;
                case -1310: // 录屏被其他应用打断了
                    console.log(e.type, '录屏被其他应用打断了');
                    this.nativeUIToast('录屏被其他应用打断了', 'middle');
                    break;
                case -1311: // Android Mic打开成功,但是录不到音频数据
                    console.log(e.type, 'Android Mic打开成功,但是录不到音频数据');
                    this.nativeUIToast('Android Mic打开成功,但是录不到音频数据', 'middle');
                    break;
                case -1312: // 录屏动态切横竖屏失败
                    console.log(e.type, '录屏动态切横竖屏失败');
                    this.nativeUIToast('录屏动态切横竖屏失败', 'middle');
                    break;
                case 1101: // 网络状况不佳:上行带宽太小,上传数据受阻
                    console.log(e.type, '网络状况不佳:上行带宽太小,上传数据受阻');
                    this.nativeUIToast('网络状况不佳', 'middle');
                    break;
                case 1102: // 网络断连, 已启动自动重连
                    console.log(e.type, '网络断连, 已启动自动重连');
                    this.nativeUIToast('网络断连, 已启动自动重连', 'middle');
                    break;
                case 1103: // 硬编码启动失败,采用软编码
                    console.log(e.type, '硬编码启动失败,采用软编码');
                    break;
                case 1104: // 视频编码失败
                    console.log(e.type, '视频编码失败');
                    this.nativeUIToast('视频编码失败', 'middle');
                    break;
                case 1105: // 新美颜软编码启动失败,采用老的软编码
                    console.log(e.type, '新美颜软编码启动失败,采用老的软编码');
                    break;
                case 1106: // 新美颜软编码启动失败,采用老的软编码
                    console.log(e.type, '新美颜软编码启动失败,采用老的软编码');
                    break;
                case 3001: // RTMP -DNS解析失败
                    console.log(e.type, 'RTMP -DNS解析失败');
                    this.nativeUIToast('RTMP -DNS解析失败', 'middle');
                    break;
                case 3002: // RTMP服务器连接失败
                    console.log(e.type, 'RTMP服务器连接失败');
                    this.nativeUIToast('RTMP服务器连接失败', 'middle');
                    break;
                case 3003: // RTMP服务器握手失败
                    console.log(e.type, 'RTMP服务器握手失败');
                    this.nativeUIToast('RTMP服务器握手失败', 'middle');
                    break;
                case 3004: // RTMP服务器主动断开,请检查推流地址的合法性或防盗链有效期
                    console.log(e.type, 'RTMP服务器主动断开,请检查推流地址的合法性或防盗链有效期');
                    this.nativeUIToast('RTMP服务器主动断开', 'middle');
                    break;
                case 3005: // RTMP 读/写失败
                    console.log(e.type, 'RTMP 读/写失败');
                    this.nativeUIToast('RTMP 读/写失败', 'middle');
                    break;
                default:
                    console.log(e.type, '未知错误');
                    this.nativeUIToast('未知错误', 'middle');
                    break;
                };
            }, false);
            // 监听网络状态变化事件
            pusher.addEventListener('netstatus', (e) => {
                e = JSON.stringify(e);
                // {
                //     type:"事件类型,此时为netstatus",
                //     target:"触发此事件的直播推流控件对象",
                //     detail:{
                //         videoBitrate:"视频码率",audioBitrate:"音频码率",
                //         videoFPS:"视频帧率",netSpeed:"推流网速",
                //         videoWidth:"视频宽度",videoHeight:"视频高度"
                //     }
                // }
            }, false);
            // 监听错误事件
            pusher.addEventListener('error', (e) => {
                e = JSON.stringify(e);
                const code = e.detail.code || '';
                switch (code) {
                case 1001: // 用户禁止使用摄像头
                    this.nativeUIToast('用户禁止使用摄像头', 'middle');
                    break;
                case 1002: // 用户禁止使用录音
                    this.nativeUIToast('用户禁止使用录音', 'middle');
                    break;
                default:
                    this.nativeUIToast(e.detail.message || '未知错误', 'middle');
                    break;
                };
            }, false);
        },
        nativeUIToast(message) {
            window.plus.nativeUI.toast(message, {
                type: 'text',
                // align: 'center',
                verticalAlign: 'center'
            });
        },
        preview() { // 预览摄像头采集数据
            this.pusher.preview();
        },
        setOptions(obj) { // 设置
            this.pusher.setOptions({ ...obj });
        },
        startPusher() { // 开始播放
            this.pusher.start(() => {
                this.playStatus = 1;
                console.log('Start pusher success!');
            }, (error) => {
                console.log('Start pusher failed: ' + JSON.stringify(error));
                this.nativeUIToast('Start pusher failed: ' + JSON.stringify(error), 'middle');
            });
        },
        stopPusher() { // 停止
            this.pusher.stop();
        },
        pausePusher() { // 暂停推流
            this.pusher.pause();
        },
        resumePusher() { // 恢复推流
            this.pusher.resume();
        },
        switchCamera() { // 切换前后摄像头
            this.pusher.switchCamera();
        },
        snapshot() { // 快照
            this.pusher.snapshot(() => {
                console.log('Snapshot pusher success!');
            }, (error) => {
                console.log('Snapshot pusher failed: ' + JSON.stringify(error));
                this.nativeUIToast('Snapshot pusher failed: ' + JSON.stringify(error), 'middle');
            });
        },
        close() { // 关闭推流
            if (!this.pusher) return;
            this.pusher.close();
        },
        onBack() {
            if (window.plus) {
                window.plus.nativeUI.confirm('确定的退出当前直播吗?', (e) => {
                    if (e.index === 0) {
                        this.close();
                        this.$router.back();
                    }
                }, {
                    'title': '提示',
                    'buttons': ['确定', '取消'],
                    'verticalAlign': 'center'
                });
            } else {
                this.$router.back();
            };
        },
        /* demo业务逻辑 */
        handlePlayStatus() { // 处理播放状态
            var playStatus = this.playStatus;
            switch (playStatus) {
            case 0:
                this.startPusher();
                this.playStatus = 1;
                break;
            case 1: // 暂停
                this.pausePusher();
                this.playStatus = 2;
                break;
            case 2: // 恢复
                this.resumePusher();
                this.playStatus = 3;
                break;
            case 3: // 暂停
                this.pausePusher();
                this.playStatus = 2;
                break;
            };
        },
        handleSwitchCamera() { // 切换摄像头
            this.switchCamera();
        },
        handleSwitchMuteStatus() { // 切换静音
            if (this.muteStatus) {
                this.setOptions({muted: false});
                this.muteStatus = false;
                this.nativeUIToast('开启静音模式');
            } else {
                this.setOptions({muted: true});
                this.muteStatus = true;
                this.nativeUIToast('开启声音模式');
            }
        },
        handleSetUrl() { // 设置播放url
            this.setOptions({url: this.url});
        }
    }
};
</script>

<style lang="scss" scoped>
.live_push{
    position: relative;
    padding-top: 47px;
    height: 100vh;
    overflow: hidden;
    box-sizing: border-box;
    background: #ddd;
    .pusher_wrap{
        width: 100vw;
        height: calc(100vh - 47px);
        background-color:#3a3a3a;
        position: static;
        z-index: 1;
    }
    .footer_bar{
        position: fixed;
        bottom: 0;
        z-index: 1000;
        width: 100%;
        color: #fff;
        display: flex;
        justify-content: space-evenly;
        padding: 5px;
        z-index: 100px;
        .dd_iconfont{
            font-size: 30px;
        }
    }
}
</style>

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值