Commit 61292688 authored by liujiaxin's avatar liujiaxin

添加iframe和白板切换按钮

parent 3a2d2dba
......@@ -66,7 +66,7 @@
display: flex;
flex-wrap: wrap;
overflow: hidden;
margin-top: 20px;
//margin-top: 20px;
.member{
flex: 33% 0;
height: 40px;
......
......@@ -106,8 +106,8 @@ export const RootProvider: React.FC<any> = ({children}) => {
});
rtmClient.on("AttributesUpdated", (attributes: object) => {
const channelAttrs = resolveChannelAttrs(attributes);
console.log('[rtm-client] updated resolved attrs', channelAttrs);
console.log('[rtm-client] updated origin attributes', attributes);
// console.log('[rtm-client] updated resolved attrs', channelAttrs);
// console.log('[rtm-client] updated origin attributes', attributes);
roomStore.updateRoomAttrs(channelAttrs)
});
rtmClient.on("MemberJoined", (memberId: string) => {
......@@ -166,4 +166,4 @@ export const RootProvider: React.FC<any> = ({children}) => {
{children}
</RootContext.Provider>
)
}
\ No newline at end of file
}
......@@ -131,8 +131,11 @@ export default function useStream () {
const teacherUid = course.teacherId;
const peerUsers = roomState.rtc.users;
// exclude teacher and me
let studentIds = peerUsers.filter((it: number) => it !== +teacherUid && it !== +me.uid && it !== SHARE_ID);
studentIds = studentIds.add(+me.uid);
let studentIds = peerUsers.filter((it: number) => `${it}` !== `${teacherUid}` && `${it}` !== `${me.uid}` && `${it}` !== `${SHARE_ID}`);
if (me.role != 'teacher') {
studentIds = studentIds.add(+me.uid);
}
const studentStreams: any[] = [];
const myAttr = userAttrs.get(me.uid);
......@@ -140,17 +143,19 @@ export default function useStream () {
console.log(100000, studentsOrder);
console.log(11111111, studentIds.toArray());
studentIds = studentIds.sort(function(a, b){
if (studentsOrder.indexOf(+a) < 0) {return 0}
if (studentsOrder.indexOf(+b) < 0) {return 0}
return studentsOrder.indexOf(+a) - studentsOrder.indexOf(+b);
});
console.log(222222, studentIds.toArray());
// when i m student
// capture all remote streams
for (let studentId of studentIds) {
if (me.role === 'student' && +me.uid == studentId) {
if (myAttr && roomState.rtc.localStream) {
console.log('use local stream')
const _tmpStream = {
...roomState.rtc.localStream,
account: myAttr.account,
......@@ -188,6 +193,7 @@ export default function useStream () {
}, [
course,
me.uid,
roomStore.state.studentsOrder,
roomState.rtc.users,
roomState.rtc.remoteStreams,
roomState.rtc.localStream
......
......@@ -158,6 +158,7 @@ export function RoomPage({ children }: any) {
}, [me.role, location.pathname, course.linkId]);
useEffect(() => {
console.log(4, 'rtc publish stream');
if (!rtcJoined || rtc.current) return;
if (platform === 'web') {
......@@ -209,6 +210,7 @@ export function RoomPage({ children }: any) {
useEffect(() => {
if (!roomState.me.uid || !roomState.course.rid) return;
if (classroom) {
debugger
if (platform === 'web') {
const webClient = roomStore.rtcClient as AgoraWebClient;
if (webClient.joined) {
......@@ -292,7 +294,9 @@ export function RoomPage({ children }: any) {
console.info(`[agora-web] stream: ${uid} fallback: ${msg}`);
})
rtc.current = true;
debugger
// WARN: IF YOU ENABLED APP CERTIFICATE, PLEASE SIGN YOUR TOKEN IN YOUR SERVER SIDE AND OBTAIN IT FROM YOUR OWN TRUSTED SERVER API
console.info(1, 'rtc join')
webClient
.joinChannel({
uid: +roomState.me.uid,
......@@ -300,11 +304,21 @@ export function RoomPage({ children }: any) {
token: '',
dual: isSmallClass
}).then(() => {
console.info(2, 'rtc join ok')
// 如果当前用户是教师,直接发布,
if(roomStore.state.me.role == 'teacher') {
roomStore.publishMeStream();
} else {
// 看台上几个人里包含自己
if (roomStore.state.studentsOrder.includes(+me.uid)) {
roomStore.publishMeStream();
}
}
}).catch(console.warn).finally(() => {
rtc.current = false;
});
return () => {
console.log('exit')
const events = [
'onTokenPrivilegeWillExpire',
'onTokenPrivilegeDidExpire',
......
......@@ -6,6 +6,7 @@ import './small-class.scss';
import CourseWareFrame from "../../components/courseware-frame";
import VideoShowList from "../../components/video-stage-list";
import {ToolsSwitcherController} from "../../components/tools-switcher-controller";
import {roomStore} from "../../stores/room";
export default function SmallClass() {
const [tool, setTool] = useState(true);
......@@ -18,8 +19,11 @@ export default function SmallClass() {
<ToolsSwitcherController onClick={() => {
setTool(!tool);
}}/>
{tool ? <MediaBoard /> : <CourseWareFrame></CourseWareFrame>}
<Roomboard currentActive={'media'} />
{tool
? <div>MediaBoard</div> /*<MediaBoard />*/
: <CourseWareFrame></CourseWareFrame>}
{ roomStore.state.me.role == 'teacher' ? <Roomboard currentActive={'media'} /> : null}
</div>
</div>
)
......
......@@ -131,8 +131,8 @@ function HomePage() {
<div className="web-menu">
<div className="web-menu-container">
<div className="short-title">
<span className="title">Agora Education</span>
<span className="subtitle">Powered by agora.io</span>
<span className="title">iTeachABC 直播教室</span>
<span className="subtitle">Powered by iplayabc.com</span>
</div>
<Icon className="icon-setting" onClick={handleSetting}/>
</div>
......
......@@ -208,7 +208,7 @@ export class RoomStore {
// @ts-ignore
window['roomStore'] = this;
}
/*
async stageUpRtc(uid: string) {
let store = this._state.rtc.users;
let itemsList = store.toList();
......@@ -313,7 +313,7 @@ export class RoomStore {
// this.commit(this.state);
}
async stageDown(uid: string) {
async stageDown2(uid: string) {
const tmp: [string, AgoraUser][] =[];
this._state.users.forEach((v, k)=>{
tmp.push([k, v])
......@@ -335,20 +335,22 @@ export class RoomStore {
}
this.commit(this.state);
}
async stageUp(uid: string) {
debugger
async stageUp2(uid: string) {
const attrs = await this.rtmClient.getChannelAttrs();
let studentsOrder: any[] = [];
// if ((attrs as any).studentsOrder && (attrs as any).studentsOrder.value) {
// studentsOrder = JSON.parse((attrs as any).studentsOrder.value) || [];
// }
const data: any = {};
const onlineStatus = JSON.parse(attrs)
const target = jsonParse(get(onlineStatus[uid], 'value'));
const onlineStatus = jsonParse(attrs)
let target = jsonParse(get(onlineStatus[uid], 'value'));
if (typeof(target) == 'string') {
target = jsonParse(target)
}
// 上台需要开启视频
// if (!+target.video) {
target.video = 1;
data[uid] = JSON.stringify(target)
data[uid] = target
// }
const tmp: [string, AgoraUser][] =[];
......@@ -369,13 +371,13 @@ export class RoomStore {
// 下台关闭音视频
// stageEndObj[1].audio = 0;
// stageEndObj[1].video = 0;
data[stageEndObj[1].uid] = JSON.stringify(stageEndObj[1])
data[stageEndObj[1].uid] = stageEndObj[1]
tmp.forEach(o => {
studentsOrder.push(+o[0]);
});
// const queue = {'studentsOrder': JSON.stringify(studentsOrder)};
data['studentsOrder'] = JSON.stringify(studentsOrder)
data['studentsOrder'] = studentsOrder
const aa = await this.rtmClient.addOrUpdateChannelAttributes(data);
console.log(aa)
const users = OrderedMap(tmp);
......@@ -389,8 +391,46 @@ export class RoomStore {
// this.commit(this.state);
}
*/
async stageDown(uid: string) {}
async stageUp(uid: string) {
debugger
let studentsOrder: any[] = [...this.state.studentsOrder];
studentsOrder.unshift(+uid);
const lastUid = studentsOrder[studentsOrder.length - 1];
const lastUser: AgoraUser | undefined = this.state.users.get(`${lastUid}`);
const upUser: AgoraUser | undefined = this.state.users.get(`${uid}`);
if (!lastUser || !upUser) {
return
}
lastUser.video = 0;
lastUser.audio = 0;
upUser.video = 1;
upUser.audio = 1;
studentsOrder.length = STAGE_NUM;
const data: any = {};
data[upUser.uid] = upUser;
data[lastUser.uid] = lastUser;
data['studentsOrder'] = studentsOrder;
await this.rtmClient.addOrUpdateChannelAttributes(data);
// this.state = {
// ...this.state,
// users
// }
// this.commit(this.state);
}
initialize() {
this.subject = new Subject<RoomState>();
......@@ -511,6 +551,7 @@ export class RoomStore {
}
addRemoteStream(stream: AgoraStream) {
console.log('remoteStreams added',5 , stream.streamID)
this.state = {
...this.state,
rtc: {
......@@ -761,13 +802,16 @@ export class RoomStore {
}
async loginAndJoin(payload: any, pass: boolean = false) {
payload.rid = `channel_${payload.rid}`
console.log('channel:', payload.rid);
const {roomType, role, uid, rid, token} = payload;
await this.rtmClient.logout();
await this.rtmClient.login(uid, token);
const channelMemberCount = await this.rtmClient.getChannelMemberCount([rid]);
const channelCount = channelMemberCount[rid];
let accounts = await this.rtmClient.getChannelAttributeBy(rid);
const channelMeta = await this.rtmClient.getChannelAttributeBy(rid);
let accounts = channelMeta.accounts;
const onlineStatus = await this.rtmClient.queryOnlineStatusBy(accounts);
/*
const me = accounts.find((o)=>{return `${payload.uid}` === `${o.uid}`});
if (onlineStatus[payload.uid]) {
......@@ -785,14 +829,14 @@ export class RoomStore {
payload.video = 1;
}
}*/
// for default
payload.audio = 0;
payload.video = 0;
if (role === 'teacher') {
payload.audio = 1;
payload.video = 1;
}
// for test
payload.audio = 0;
payload.video = 0;
const argsJoin = {
uid,
channelCount,
......@@ -802,12 +846,11 @@ export class RoomStore {
roomType
};
let result = pass === false ? canJoin(argsJoin) : {permitted: true, reason: ''};
// if (uid == this._state.course.teacherId) {
// result = {permitted: false, reason: 'same with teacher id'}
// }
let studentsOrder: number[] = [];
if (result.permitted) {
studentsOrder = this.state.studentsOrder;
// studentsOrder = this.state.studentsOrder;
/*
if (!studentsOrder.length) {
accounts.forEach(a => {
if (!studentsOrder.includes(+a.uid)) {
......@@ -815,8 +858,8 @@ export class RoomStore {
}
})
} else {
debugger
const accIds = accounts.map(a=> +a.uid);
const accs = accounts.filter(a=> a.role != 'teacher');
const accIds = accs.map(a=> +a.uid);
// if (accIds.length >= studentsOrder.length) {
let a = new Set(accIds);
......@@ -827,7 +870,6 @@ export class RoomStore {
studentsOrder.push(+d);
}
})
debugger
// }
}
......@@ -840,22 +882,43 @@ export class RoomStore {
studentsOrder.push(+uid)
}
}
*/
let onlineMe = accounts.find((it: any) => `${it.uid}` == `${payload.uid}`);
if (onlineMe) {
payload.video = onlineMe.video;
payload.audio = onlineMe.audio;
} else {
if (channelMeta.studentsOrder && channelMeta.studentsOrder.includes(+payload.uid)) {
payload.video = 1;
payload.audio = 1;
}
}
let res = await this.rtmClient.join(rid);
this.state = {
...this.state,
rtm: {
...this.state.rtm,
joined: true
let res = await this.rtmClient.join(rid).then(async r => {
this.state = {
...this.state,
rtm: {
...this.state.rtm,
joined: true
}
}
}
const grantBoard = role === 'teacher' ? 1 : 0;
console.log(">>>>>>>>>>#room: ", grantBoard);
await this.updateMe({...payload, grantBoard}, studentsOrder);
this.commit(this.state);
const grantBoard = role === 'teacher' ? 1 : 0;
console.log(">>>>>>>>>>#room: ", grantBoard);
await this.updateMe({...payload, grantBoard});
this.commit(this.state);
});
// this.state = {
// ...this.state,
// rtm: {
// ...this.state.rtm,
// joined: true
// }
// }
// const grantBoard = role === 'teacher' ? 1 : 0;
// console.log(">>>>>>>>>>#room: ", grantBoard);
// await this.updateMe({...payload, grantBoard});
// this.commit(this.state);
return;
}
await this.rtmClient.logout();
......@@ -864,7 +927,12 @@ export class RoomStore {
reason: result.reason
}
}
publishMeStream() {
console.log(3, 'set rtc join flag, should auto publish')
// return await (this.rtcClient as AgoraWebClient).publishStream()
// 通过index.tsx里的监听来触发发布
this.setRTCJoined(true);
}
setRTCJoined(joined: boolean) {
this.state = {
...this.state,
......@@ -938,12 +1006,12 @@ export class RoomStore {
}
const data: any = {};
data[key] = attrs;
await this.rtmClient.updateChannelAttrsByKey(data);
// let res = await this.rtmClient.updateChannelAttrsByKey(key, attrs);
// await this.rtmClient.addOrUpdateChannelAttributes(data);
let res = await this.rtmClient.updateChannelAttrsByKey(key, attrs);
// return res;
}
async updateMe(user: any, studentsOrder: number[] = []) {
async updateMe(user: any) {
const {role, uid, account, rid, video, audio, chat, boardId, linkId, sharedId, muteChat, grantBoard} = user;
const key = role === 'teacher' ? 'teacher' : uid;
const me = this.state.me;
......@@ -991,17 +1059,101 @@ export class RoomStore {
}
const data: any = {};
data[key] = attrs;
if (studentsOrder && studentsOrder.length) {
data['studentsOrder'] = studentsOrder;
}
await this.rtmClient.updateChannelAttrsByKey(data);
// if (studentsOrder && studentsOrder.length) {
// data['studentsOrder'] = studentsOrder;
// }
console.log('update me', data);
await this.rtmClient.addOrUpdateChannelAttributes(data);
// let res = await this.rtmClient.updateChannelAttrsByKey(key, attrs);
// return res;
}
meUp() {
console.log('meUp!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
}
meDown() {
console.log('meDown!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
}
async syncStageStudent(accounts: any[], studentsOrder: number[]) {
debugger
let needUpdate =false;
const data: any = {};
const accData: any = {};
accounts.forEach(acc => {
if (acc.role == 'student') {
accData[acc.uid] = acc
}
})
// 学生在台上并且退出了
const accIds: any[] = Object.keys(accData).map(uid => +uid);
if (!accIds.length) {
return
}
const exitUserIds = studentsOrder.filter( uid => {
return !accIds.includes(uid);
});
if (exitUserIds.length) {
exitUserIds.forEach( uid => {
if (studentsOrder.includes(uid)) {
studentsOrder.splice(studentsOrder.indexOf(uid), 1)
needUpdate = true
}
})
}
if (studentsOrder.length != STAGE_NUM) {
if (studentsOrder.length > STAGE_NUM) {
//台上队列尾部挤下去的人音视频关闭
const lostIdx: number[] = [];
[...Array(studentsOrder.length - STAGE_NUM)].forEach( (_, i) => {
console.log(i)
const idx = studentsOrder.length - 1 - i
lostIdx.push(idx)
})
lostIdx.forEach( uid => {
if (studentsOrder.includes(uid)) {
if ( accData[uid]) {
const u = accData[uid];
// if (u.video != 0 || u.audio != 0) {
u.video = 0;
u.audio = 0;
data[uid] = u;
// }
}
studentsOrder.splice(studentsOrder.indexOf(uid), 1)
needUpdate = true
}
})
studentsOrder.length = STAGE_NUM;
}
if (studentsOrder.length < STAGE_NUM) {
const newUid = accIds.find( uid => {
return !studentsOrder.includes(+uid);
});
const newStudents = accData[newUid];
if (newStudents) {
const uid = newStudents.uid;
// if (newStudents.video != 1 || newStudents.audio != 1) {
//上台的打开音视频
newStudents.video = 1;
newStudents.audio = 1;
data[uid] = newStudents;
studentsOrder.push(+uid)
needUpdate = true;
// }
}
}
}
if (needUpdate) {
data['studentsOrder'] = studentsOrder;
// await this.rtmClient.addOrUpdateChannelAttributes(data);
return data;
}
}
updateRoomAttrs ({teacher, accounts, room, studentsOrder}: any) {
console.log("[agora-board], room: ", room, " teacher: ", teacher, "accounts ", accounts);
async updateRoomAttrs ({teacher, accounts, room, studentsOrder}: {teacher: any, accounts: any, room: any, studentsOrder: number[]}) {
console.log("[agora-board], room: ",teacher, accounts, room, studentsOrder);
const users = accounts.reduce((acc: OrderedMap<string, AgoraUser>, it: any) => {
return acc.set(it.uid, {
......@@ -1043,15 +1195,30 @@ export class RoomStore {
if (users.get(me.uid)) {
Object.assign(me, users.get(me.uid));
}
// 每个学生都要维护一下状态,因为可能涉及到自己的上下台
// if (newInfo && newInfo['studentsOrder'] && me.role == 'student') {
// if (newInfo['studentsOrder'].includes(+this.state.me.uid)) {
// this.meUp();
// } else {
// this.meDown()
// }
// }
let newStudentsOrder = studentsOrder;
if (me.role === 'teacher') {
Object.assign(me, {
linkId: room.link_uid,
boardId: room.whiteboard_uid,
lockBoard: room.lock_board,
})
//教师维护学生顺序,并更新到频道属性
//教师维护学生顺序,仅保留STAGE_NUM个,并更新到频道属性
const newInfo: any = await this.syncStageStudent(JSON.parse(JSON.stringify(accounts)), [...studentsOrder]);
console.log('newInfo', newInfo)
debugger
if (newInfo) {
newStudentsOrder = newInfo['studentsOrder'];
await this.rtmClient.addOrUpdateChannelAttributes(newInfo);
}
}
const newClassState: ClassState = {} as ClassState;
......@@ -1078,7 +1245,7 @@ export class RoomStore {
...this.state.course,
...newClassState
},
studentsOrder
studentsOrder: newStudentsOrder
}
this.commit(this.state);
}
......@@ -1109,6 +1276,10 @@ export class RoomStore {
}
async exitAll() {
console.log('exitAll')
if (this.state.me.role == 'teacher') {
await this.rtmClient.clearChannelAttributes()
}
try {
await this.rtmClient.exit();
await this.rtcClient.exit();
......
......@@ -286,6 +286,7 @@ export class AgoraElectronClient {
}
exit () {
console.log('exit')
this.leave();
this.destroyClient();
}
......@@ -303,4 +304,4 @@ export class AgoraElectronClient {
}
}
export const nativeRTCClient = new AgoraElectronClient();
\ No newline at end of file
export const nativeRTCClient = new AgoraElectronClient();
......@@ -337,9 +337,16 @@ export default class AgoraWebClient {
await this.rtc.createClient(APP_ID, true);
await this.rtc.join(this.localUid, channel, token);
dual && await this.rtc.enableDualStream();
// 改成手动发布
// roomStore.setRTCJoined(true);
this.joined = true;
roomStore.setRTCJoined(true);
}
// async publishStream() {
// if (this.joined) {
// return roomStore.setRTCJoined(true);
// }
// }
async leaveChannel() { console.log('unpublish leaveChannel' , 3);
this.localUid = 0;
......
......@@ -55,7 +55,11 @@ export default class AgoraRTMClient {
this._client = AgoraRTM.createInstance(APP_ID, { enableLogUpload: false, logFilter });
}
async addOrUpdateChannelAttributes(data: any, enableNotificationToChannelMembers = true): Promise<string> {
return await this._client.addOrUpdateChannelAttributes(this._currentChannelName, data, {enableNotificationToChannelMembers});
const channelAttributes: {[key: string]: string} = {};
for (const k of Object.keys(data)) {
channelAttributes[k] = typeof(data[k]) != 'string' ? JSON.stringify(data[k]) : data[k];
}
return await this._client.addOrUpdateChannelAttributes(this._currentChannelName, channelAttributes, {enableNotificationToChannelMembers});
}
public removeAllListeners(): any {
......@@ -95,6 +99,10 @@ export default class AgoraRTMClient {
return
}
async clearChannelAttributes() {
await this._client.clearChannelAttributes(this._currentChannelName);
}
async logout () {
if (!this._logged) return;
await this.leave(this._currentChannelName);
......@@ -160,7 +168,7 @@ export default class AgoraRTMClient {
async setChannelAttrsKey(key: any) {
this._channelAttrsKey = `${key}`;
}
async updateChannelAttrsByKey (data: {[key: string]: string}/*key: string, attrs: any*/) {
async updateChannelAttrsByKey____ (data: {[key: string]: string}/*key: string, attrs: any*/) {
// this._channelAttrsKey = key;
const channelAttributes: {[key: string]: string} = {};
for (const k of Object.keys(data)) {
......@@ -169,7 +177,7 @@ export default class AgoraRTMClient {
// if (key) {
// channelAttributes[key] = JSON.stringify(attrs);
// }
console.log("[rtm-client] updateChannelAttrsByKey ", data);
console.log("[rtm-client] addOrUpdateChannelAttributes ", channelAttributes);
// console.log("[rtm-client] updateChannelAttrsByKey ", attrs, " key ", key, channelAttributes);
await this._client.addOrUpdateChannelAttributes(
this._currentChannelName,
......@@ -177,7 +185,7 @@ export default class AgoraRTMClient {
{enableNotificationToChannelMembers: true});
}
async ___updateChannelAttrsByKey (key: string, attrs: any) {
async updateChannelAttrsByKey (key: string, attrs: any) {
this._channelAttrsKey = key;
const channelAttributes: {[key: string]: string} = {}
if (key) {
......@@ -236,16 +244,17 @@ export default class AgoraRTMClient {
async getChannelAttributeBy(channelName: string) {
let json = await this._client.getChannelAttributes(channelName);
const accounts = [];
const data:any = {};
for (let key of Object.keys(json)) {
if (key === 'teacher') {
const teacherObj = jsonParse(_.get(json, `${key}.value`));
console.log("teacherObj ", teacherObj);
// when teacher is not empty object
if(teacherObj && Object.keys(teacherObj).length) {
accounts.push({role: 'teacher', ...teacherObj});
}
continue;
}
// if (key === 'teacher') {
// const teacherObj = jsonParse(_.get(json, `${key}.value`));
// console.log("teacherObj ", teacherObj);
// // when teacher is not empty object
// if(teacherObj && Object.keys(teacherObj).length) {
// accounts.push({role: 'teacher', ...teacherObj});
// }
// continue;
// }
// if (key === 'studentsOrder') {
// continue
// }
......@@ -256,9 +265,12 @@ export default class AgoraRTMClient {
student.uid = key;
accounts.push(student);
}
} else {
data[key] = jsonParse(_.get(json, `${key}.value`))
}
}
return accounts;
data.accounts = accounts;
return data;
}
async sendPeerMessage(peerId: string, body: MessageBody) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment