Files
2025-06-11 10:21:51 +08:00

551 lines
15 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<block v-if="is_replay">
<view class="video-detail">
<video id="myVideo" :src="replay_url" :autoplay="true" :loop="true" :controls="false" :show-fullscreen-btn="false"
:show-play-btn="false" :show-center-play-btn="false" object-fit="cover" :style="{height: winHeight, width: winWidth}"
@error="videoErrorCallback"></video>
</view>
</block>
<!-- #ifdef APP-PLUS -->
<block v-if="role == 'audience' && player_url != ''">
<video
id="myVideo"
:src="player_url"
:autoplay="true"
:loop="true"
:controls="false"
:show-fullscreen-btn="false"
:show-play-btn="false"
:show-center-play-btn="false"
:auto-pause-if-navigate="false"
:auto-pause-if-open-native="false"
object-fit="cover"
:style="{height: winHeight, width: winWidth}"
></video>
</block>
<!-- #endif -->
<!-- #ifndef APP-PLUS -->
<block v-if="role == 'audience' && player_url != ''">
<live-player id="livePlayer" :picture-in-picture-mode="picture_mode" :src="player_url" autoplay="true" mode="RTC" object-fit="fillCrop" :style="{height: winHeight, width: winWidth}"
></live-player>
</block>
<!-- #endif -->
<block v-if="role == 'broadcaster'">
<live-pusher id="livePusher1" ref="livePusher1" class="livePusher" :url="mainPusherInfo_url" mode="RTC"
enable-camera="true" enable-mic="true" auto-focus="true" aspect="9:16" objectFit="fill"
max-bitrate="500" min-bitrate="200" waiting-image="../../../static/temporarily.jpg" :beauty="beauty" :whiteness="whiteness"
:style="{height: winHeight, width: winWidth}" @statechange="recorderStateChange" @netstatus="recorderNetChange"></live-pusher>
</block>
</view>
</template>
<script>
const AgoraMiniappSDK = require("../../lib/mini-app-sdk-production.js");
const RTMClient = require('../../lib/agora-rtm.js');
export default {
data() {
return {
RTMClient: null,
/*加载中*/
loading_login: false,
/*推流对象*/
pusherContext: null,
/*拉流对象*/
playerContext: null,
player_url: '',
mainPusherInfo_url: '',
room_id: '',
/*发送消息*/
TextMsg: '',
/*是否打开礼物*/
open_gift: false,
/*评论*/
commentsList: [],
/*礼物*/
giftList: [],
/*是否打开商品列表*/
open_products: false,
/*当前讲解商品ID*/
explain_product_id: '',
/*当前讲解商品*/
explain_product: null,
/*是否显示更多功能*/
open_more: false,
/*是否美颜*/
beauty: 5,
/*美白*/
whiteness: 5,
/*前置后置*/
device_position: 'front',
/*打开分享*/
open_share: false,
/*分享参数*/
param_share: {},
/*分享图片*/
qrcode: null,
/*获取观看人数*/
showNumTimer: null,
/*是否点赞*/
is_click_digg: false,
// 房间详情
roomDetail: {},
// 用户信息
userInfo: {},
// RTC房间频道
channel: '',
// 应用appid
appId: '',
// rtm客户端
rtm_client: null,
reconnectTimer: null,
// 0 - loading, 1 - ok, 2 - error
push_status: 'loading',
picture_mode: ["push", "pop"],
isCaster: false
};
},
props: ['winHeight', 'winWidth', 'role', 'is_replay', 'replay_url'],
methods: {
show(){
if(this.playerContext!=null){
this.playerContext.play();
}
if(this.pusherContext){
this.reconnect();
}
},
/*请求对象*/
getRequest(){
let self = this;
// #ifdef APP-PLUS
return getApp().globalData.vueObj;
// #endif
// #ifndef APP-PLUS
return self;
// #endif
},
start(roomDetail, userInfo) {
let self = this;
self.roomDetail = roomDetail;
self.userInfo = userInfo;
self.channel = 'channel_' + roomDetail.shop_supplier_id;
self.isCaster = self.role == 'broadcaster';
if (self.isCaster) {
let whiteness = uni.getStorageSync('whiteness');
if (whiteness) {
self.whiteness = whiteness;
}
let beauty = uni.getStorageSync('beauty');
if (beauty) {
self.beauty = beauty;
}
} else {
//观众
console.log('观众进入');
}
self.loginRoom();
},
/*直播间登录*/
loginRoom() {
let self = this;
uni.showLoading({
title: '正在进入'
});
self.getRequest()._get('plus.live.agora.api/login', {
room_id: self.roomDetail.room_id,
channel: self.channel,
isCaster: self.isCaster
}, function(res) {
self.appId = res.data.appId;
self.initAgoraChannel(res.data.userSign).then(url => {
console.log(`pushing ${url}`);
let ts = new Date().getTime();
self.mainPusherInfo_url = url;
if (self.isCaster) {
self.pusherContext = uni.createLivePusherContext('livePusher1', self);
setTimeout(function() {
console.log('创建 pusherContext app', self.pusherContext);
self.pusherContext.start();
self.loginIM();
}, 500);
// 同步数据
self.showNumTimer = setInterval(() => {
self.synRoomInfo();
}, 15000)
}
}).catch(e => {
console.log(`init agora client failed: ${e}`);
console.log(JSON.stringify(e));
uni.showToast({
title: `客户端初始化失败`,
icon: 'none',
duration: 5000
});
});
});
},
/**
* 初始化sdk推流
*/
initAgoraChannel: function(token) {
let self = this;
return new Promise((resolve, reject) => {
let client = new AgoraMiniappSDK.Client();
//subscribe stream events
self.subscribeEvents(client);
AgoraMiniappSDK.LOG.onLog = (text) => {
// callback to expose sdk logs
console.log(text);
};
// info:1 WARNING:2 ERROR:3 DEBUG:0
AgoraMiniappSDK.LOG.setLogLevel(1);
self.client = client;
client.setRole(self.role);
client.init(self.appId, () => {
console.log(`client init success`);
// pass key instead of undefined if certificate is enabled
client.join(token, self.channel, self.getRequest().getUserId(), () => {
console.log(`client join channel success`);
//and get my stream publish url
if (self.isCaster) {
client.publish(url => {
console.log(`client publish success`);
console.log('url=' + url);
resolve(url);
}, e => {
console.log(`client publish failed: ${e.code} ${e.reason}`);
reject(e)
});
} else {
resolve();
}
}, e => {
console.log(`: ${e.code} ${e.reason}`);
reject(e)
})
}, e => {
console.log(`client init failed: ${e} ${e.code} ${e.reason}`);
reject(e);
});
});
},
loginIM() {
let self = this;
self.getRequest()._get('plus.live.agora.api/rtmToken', {
channel: self.channel
}, function(res) {
self.rtm_client = new RTMClient(self.appId);
self.onChannelEvent();
// sdk连接状态
self.rtm_client.on('ConnectionStateChanged', (newState, reason) => {
console.log('The connection status', newState)
console.log('The reason for the state change', reason)
});
// 登录 RTM 系统
self.rtm_client.login(res.data.userSign, '' + self.getRequest().getUserId()).then(() => {
console.log('AgoraRTM client login success');
self.rtm_client.joinChannel(self.channel).then(() => {
console.log('join channel success');
// 发送通知
let msg = {
type: 'enter',
nickName: self.userInfo.nickName
};
self.sendMsg(JSON.stringify(msg));
if(self.isCaster){
// 直播开始
self.getRequest()._post(
'plus.live.room/set_status', {
room_id: self.roomDetail.room_id,
status: 101
},
function(res) {
// 开始录制
self.startRecord();
}
);
}
}).catch((err) => {
console.log('join channel failed', err)
});
}).catch(err => {
console.log('AgoraRTM client login failure', err);
});
});
},
/*获取直播间信息*/
synRoomInfo(e){
let self = this;
self.getRequest()._post(
'plus.live.room/syn_room',
{
room_id: self.roomDetail.room_id,
},
function(res) {
// 发送通知
let msg = {
type: 'views',
views: res.data.model.views,
digg_num: res.data.model.digg_num,
};
self.sendMsg(JSON.stringify(msg));
}
);
},
/**
* 注册stream事件
*/
subscribeEvents: function(client) {
let self = this;
/**
* sometimes the video could be rotated
* this event will be fired with ratotion
* angle so that we can rotate the video
* NOTE video only supportes vertical or horizontal
* in case of 270 degrees, the video could be
* up side down
*/
client.on("video-rotation", (e) => {
console.log(`video rotated: ${e.rotation} ${e.uid}`);
});
/**
* fired when new stream join the channel
*/
client.on("stream-added", e => {
let uid = e.uid;
console.log(`stream ${uid} added`);
/**
* subscribe to get corresponding url
*/
client.subscribe(uid, (url, rotation) => {
console.log(`stream ${uid} subscribed successful`);
console.log(url);
self.player_url = url;
self.loginIM();
}, e => {
console.log(`stream subscribed failed ${e} ${e.code} ${e.reason}`);
});
});
/**
* remove stream when it leaves the channel
*/
client.on("stream-removed", e => {
let uid = e.uid;
console.log(`stream ${uid} removed`);
});
/**
* when bad thing happens - we recommend you to do a
* full reconnect when meeting such error
* it's also recommended to wait for few seconds before
* reconnect attempt
*/
client.on("error", err => {
let errObj = err || {};
let code = errObj.code || 0;
let reason = errObj.reason || "";
console.log(`error: ${code}, reason: ${reason}`);
if (code === 501 || code === 904) {
self.reconnect();
}
});
/**
* there are cases when server require you to update
* player url, when receiving such event, update url into
* corresponding live-player, REMEMBER to update key property
* so that live-player is properly refreshed
* NOTE you can ignore such event if it's for pusher or happens before
* stream-added
*/
client.on('update-url', e => {
console.log(`update-url: ${JSON.stringify(e)}`);
});
},
onChannelEvent: function() {
let self = this;
// 频道消息
self.rtm_client.on('ChannelMessage', (message, memberId) => {
let object = {
uid: memberId,
message: message.text
}
console.log('message -----');
console.log(message);
if (memberId != self.getRequest().getUserId()) {
self.$emit('showMsg', message.text);
}
})
//频道成员进出通知
self.rtm_client.on('MemberJoined', (memberId) => {
console.log('memberId: ', memberId);
})
self.rtm_client.on('MemberLeft', (memberId) => {
console.log('memberId: ', memberId);
})
},
/** type消息类型 文本text,礼物gift,进入房间enter 观看人数views 点赞: digg
结束over 讲解: explain
*/
sendMsg(msg) {
let self = this;
self.rtm_client.sendChannel(msg).then(() => {
self.$emit('showMsg', msg);
}).catch(error => {
// 频道消息发送失败的处理逻辑
console.log('频道消息发送失败的处理逻辑');
console.log(error);
});
},
/*直播设置*/
liveSet(e) {
switch (e.type) {
case 'beauty':
this.beauty = e.value;
break;
case 'whiteness':
this.whiteness = e.value;
break;
case 'device_position':
this.device_position = e.value;
if (this.pusherContext != null) {
this.pusherContext.switchCamera({
type: e.value,
success: function(res) {
console.log('切换成功');
},
fail: function(err) {
console.log(err);
}
});
}
break;
}
},
/**
* reconnect when bad things happens...
*/
reconnect: function() {
let self = this;
uni.showToast({
title: '尝试恢复链接...',
icon: 'none',
duration: 5000
});
// always destroy client first
// *important* miniapp supports 2 websockets maximum at same time
// do remember to destroy old client first before creating new ones
self.client && self.client.destroy();
self.reconnectTimer = setTimeout(() => {
self.loginRoom();
}, 1 * 1000);
},
/**
* 推流状态更新回调
*/
recorderStateChange: function (e) {
console.log('live-pusher code: ' , e)
if (e.detail.code === -1307) {
//re-push
console.log('live-pusher stopped ---- error');
this.push_status = 'error';
}
if (e.detail.code === 1008) {
//started
console.log('live-pusher started');
if(this.push_status === "loading") {
this.push_status = 'ok';
}
}
},
recorderNetChange: function(e) {
//console.log('netstatus:' + JSON.stringify(e));
},
onMainError: function(e) {
var self = this;
console.log('onMainError called: ', e);
},
/*退出 type: auto:主动 over结束*/
exit: function(type) {
let self = this;
let url = '/pagesLive/live/index';
if (self.role == 'broadcaster') {
type = 'over';
// 通知其他人
let msg = {
type: 'over'
};
self.sendMsg(JSON.stringify(msg));
}
if(type == 'over'){
//直播结束页
url = '/pagesLive/live/live-over?room_id=' + self.roomDetail.room_id;
}
self.clear();
uni.redirectTo({
url: url
});
},
startRecord:function(){
let self = this;
// 请求开始录制
if(self.isCaster){
self.getRequest()._post('plus.live.agora.api/record_acquire', {
room_id: self.roomDetail.room_id
}, function(res) {
self.getRequest()._post('plus.live.agora.api/record_start', {
room_id: self.roomDetail.room_id
}, function(res) {
self.getRequest()._post('plus.live.agora.api/record_query', {
room_id: self.roomDetail.room_id
}, function(res) {
});
});
});
}
},
/*销毁*/
clear: function() {
let self = this;
try {
if (self.showNumTimer) {
clearInterval(self.showNumTimer);
self.showNumTimer = null;
}
if (self.playerContext) {
self.playerContext.stop();
self.playerContext = null;
}
if (self.pusherContext) {
self.pusherContext.stop();
self.pusherContext = null;
}
clearTimeout(this.reconnectTimer);
self.reconnectTimer = null;
if (self.isCaster) {
try {
self.client && self.client.unpublish();
} catch (e) {
console.log(`unpublish failed`);
console.log(e);
}
}
// rtm退出
self.client && self.client.leave();
// rtm退出
self.rtm_client && self.rtm_client.logout();
} catch (e) {
console.log(e);
}
}
}
}
</script>
<style scoped>
</style>