Skip to content

Commit 46157b0

Browse files
committed
feat: 视频聊天的连接测试
1 parent 31512e6 commit 46157b0

File tree

6 files changed

+215
-73
lines changed

6 files changed

+215
-73
lines changed

Diff for: client/packages/rtc-web/src/config/constant.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ export const VideoControlMenuAction: MenuActionType[] = [
3434
btn: true,
3535
disabled: false,
3636
},
37-
{
38-
name: 'mirror-image',
39-
tip: '开启镜像',
40-
color: '#707070',
41-
tipDir: 'tooltip-top',
42-
btn: true,
43-
disabled: false,
44-
},
37+
// {
38+
// name: 'mirror-image',
39+
// tip: '开启镜像',
40+
// color: '#707070',
41+
// tipDir: 'tooltip-top',
42+
// btn: true,
43+
// disabled: false,
44+
// },
4545
{
4646
name: 'hang-up',
4747
tip: '结束通话',

Diff for: client/packages/rtc-web/src/hooks/useRoom.ts

+93-19
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ export type OwnerInfo = {
4040
owner: boolean;
4141
};
4242

43+
export type ConnectOption = {
44+
roomJoined?: (...args: any[]) => Promise<void>;
45+
roomCreated?: (data: any) => Promise<void>;
46+
onAddRtcPeer?: (id: string, pc: any) => Promise<void>;
47+
onConnectComplete?: (...args: any[]) => void;
48+
onBeforeCreateOffer?: (...args: any[]) => Promise<void>;
49+
onBeforeCreateAnswer?: (...args: any[]) => Promise<void>;
50+
onTrack?: (...args: any[]) => void;
51+
};
52+
4353
export const useRoom = (value: MaybeRef<string> | CommonFnType) => {
4454
const realValue = resolveRef(value);
4555
const roomIdReg = /^[a-zA-Z0-9]{4,32}$/;
@@ -101,13 +111,15 @@ export const useCreateRoom = (type: 'password' | 'video' = 'password') => {
101111
};
102112
};
103113

104-
export const useRoomConnect = () => {
114+
export const useRoomConnect = (option: ConnectOption = {}) => {
105115
const roomInfo = useGetRoomInfo();
106116

107117
const { members, selfInfo } = roomInfo;
108118
const rtcConnects = new Map<string, RTCPeerConnection>();
119+
const dataChanelMap = new Map<string, RTCDataChannel>();
109120
const initData = inject(InitDataKey)!;
110121
const socketRef = shallowRef();
122+
const completed = ref(false);
111123

112124
watchArray(
113125
() => members.value,
@@ -116,41 +128,90 @@ export const useRoomConnect = () => {
116128

117129
// 处理 exit
118130
if (removed.length) {
119-
removed.forEach((peer) => {
131+
removed.forEach(async (peer) => {
120132
if (peer.id) {
133+
const rtcConnect = await getRtcConnect(peer.id);
134+
rtcConnect.close();
121135
rtcConnects.delete(peer.id);
122136
}
123137
});
124138
}
125139
}
126140
);
127141

128-
const createRtcConnect = (id: string) => {
129-
const pc = new RTCPeerConnection(initData.value.config);
142+
const createRtcConnect = async (id: string) => {
143+
// const pc = new RTCPeerConnection(initData.value.config);
144+
const pc = new RTCPeerConnection();
145+
pc.onicecandidate = (event) => {
146+
if (event.candidate != null) {
147+
const message = {
148+
from: selfInfo.value.socketId,
149+
to: id,
150+
room: selfInfo.value.roomId,
151+
sdpMid: event.candidate.sdpMid,
152+
sdpMLineIndex: event.candidate.sdpMLineIndex,
153+
sdp: event.candidate.candidate,
154+
};
155+
socketRef.value.emit('candidate', message);
156+
}
157+
};
158+
159+
const dataChanel = pc.createDataChannel('datachanel');
160+
dataChanelMap.set(id, dataChanel);
161+
162+
dataChanel.onopen = () => {
163+
// dataChanel.send('aaa');
164+
};
165+
166+
pc.ondatachannel = (e) => {
167+
const chanel = e.channel;
168+
if (chanel.label === 'datachanel') {
169+
chanel.onmessage = (e: any) => {
170+
// console.log('接受', e.data);
171+
};
172+
}
173+
};
174+
175+
pc.onconnectionstatechange = (e) => {
176+
if (pc.connectionState === 'connected') {
177+
// console.log('完成');
178+
completed.value = true;
179+
}
180+
};
130181

131-
pc.onicecandidate = () => {
132-
// console.log('on candidate', e);
182+
pc.ontrack = (e) => {
183+
option?.onTrack?.(e, id);
133184
};
134185

135186
rtcConnects.set(id, pc);
187+
await option.onAddRtcPeer?.(id, pc);
136188

137189
return pc;
138190
};
139191

140-
const getRtcConnect = (id: string) => {
141-
return rtcConnects.get(id) || createRtcConnect(id);
192+
const getRtcConnect = async (id: string) => {
193+
return rtcConnects.get(id) || (await createRtcConnect(id));
194+
};
195+
196+
const roomCreated = async (data: any) => {
197+
await option?.roomCreated?.(data);
142198
};
143199

144200
const roomJoined = async (data: any) => {
145-
createOffer(getRtcConnect(data.id), data);
201+
const peer = await getRtcConnect(data.id);
202+
203+
await option?.roomJoined?.(data.id, peer);
204+
createOffer(peer, data);
146205
};
147206

148207
/**
149208
* @description 这里的 createOffer
150209
*/
151210
const createOffer = async (pc: RTCPeerConnection, peer: any) => {
211+
await option?.onBeforeCreateOffer?.(peer.id, pc);
152212
const offer = await pc.createOffer(initData.value.options);
153213
await pc.setLocalDescription(offer);
214+
console.log('create offer - send');
154215
socketRef.value.emit(SocketEventName.RoomOffer, {
155216
from: selfInfo.value.socketId,
156217
to: peer.id,
@@ -163,13 +224,14 @@ export const useRoomConnect = () => {
163224
* @description offer 监听事件
164225
*/
165226
const roomOffer = async (data: any) => {
166-
const pc = getRtcConnect(data.from);
227+
const pc = await getRtcConnect(data.from);
167228
await pc.setRemoteDescription(
168229
new RTCSessionDescription({ type: 'offer', sdp: data.sdp })
169230
);
231+
await option?.onBeforeCreateAnswer?.(data.from, pc);
170232
const answer = await pc.createAnswer(initData.value.options);
171233
await pc.setLocalDescription(answer);
172-
234+
console.log('receive offer - send answer');
173235
socketRef.value.emit(SocketEventName.RoomAnswer, {
174236
from: selfInfo.value.socketId,
175237
to: data.from,
@@ -182,25 +244,37 @@ export const useRoomConnect = () => {
182244
* @description answer 监听事件
183245
*/
184246
const roomAnswer = async (data: any) => {
185-
const pc = getRtcConnect(data.from);
247+
const pc = await getRtcConnect(data.from);
248+
console.log('receive answer');
186249
await pc.setRemoteDescription(
187250
new RTCSessionDescription({ type: 'answer', sdp: data.sdp })
188251
);
189252
};
190-
const roomCandidate = () => {
191-
//
253+
const roomCandidate = async (data: any) => {
254+
const pc = await getRtcConnect(data.from);
255+
const rtcIceCandidate = new RTCIceCandidate({
256+
candidate: data.sdp,
257+
sdpMid: data.sdpMid,
258+
sdpMLineIndex: data.sdpMLineIndex,
259+
});
260+
await pc.addIceCandidate(rtcIceCandidate);
192261
};
193262

194263
const handleRoomConnect = (socket: any) => {
195264
socketRef.value = socket;
196-
socket.on(SocketEventName.RoomJoin, roomJoined);
197-
socket.on(SocketEventName.RoomOffer, roomOffer);
198-
socket.on(SocketEventName.RoomAnswer, roomAnswer);
199-
socket.on(SocketEventName.RoomCandidate, roomCandidate);
265+
startConnect();
266+
};
267+
268+
const startConnect = () => {
269+
socketRef.value.on(SocketEventName.RoomCreated, roomCreated);
270+
socketRef.value.on(SocketEventName.RoomJoin, roomJoined);
271+
socketRef.value.on(SocketEventName.RoomOffer, roomOffer);
272+
socketRef.value.on(SocketEventName.RoomAnswer, roomAnswer);
273+
socketRef.value.on(SocketEventName.RoomCandidate, roomCandidate);
200274
};
201275
useSocket(handleRoomConnect);
202276

203-
return { ...roomInfo };
277+
return { ...roomInfo, rtcConnects, dataChanelMap, completed, startConnect };
204278
};
205279

206280
// 获取房间的一些信息,例如 peer 等信息

Diff for: client/packages/rtc-web/src/views/video/hooks/useVideoCall.ts

+79-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useRoomConnect } from '@/hooks';
12
import { useUserMedia, useDevicesList } from '@vueuse/core';
23
import {
34
Ref,
@@ -10,11 +11,14 @@ import {
1011
} from 'vue';
1112

1213
export type VideoShareOption = {
14+
immeately?: boolean;
1315
audio?: Ref<MediaDeviceInfo | undefined>;
1416
speaker?: Ref<string>;
1517
};
1618

17-
export const useVideoShare = (option: VideoShareOption = {}) => {
19+
export const useMediaSetting = (
20+
option: VideoShareOption = { immeately: true }
21+
) => {
1822
const currentCamera = ref<string>();
1923
const currentAudioInput = ref<string>();
2024
const currentAudioOutput = ref<string>();
@@ -107,15 +111,15 @@ export const useVideoShare = (option: VideoShareOption = {}) => {
107111
};
108112
});
109113

110-
const { stream, enabled, stop, restart } = useUserMedia({
114+
const { stream, stop, restart, start } = useUserMedia({
111115
constraints,
112116
});
113117

114118
const audioTracks = ref<MediaStreamTrack[]>([]);
115119
const videoTracks = ref<MediaStreamTrack[]>([]);
116120

117-
const audioEnabled = ref(false);
118-
const videoEnabled = ref(false);
121+
const audioEnabled = ref(true);
122+
const videoEnabled = ref(true);
119123

120124
// 切换 video、audio 渲染
121125
const switchTrackEnable = (type: 'video' | 'audio', flag: boolean) => {
@@ -151,33 +155,44 @@ export const useVideoShare = (option: VideoShareOption = {}) => {
151155
videoTracks.value = stream.value.getVideoTracks();
152156
}
153157
if (!videoEnabled.value) {
154-
switchTrackEnable('video', false);
158+
// switchTrackEnable('video', false);
155159
}
156160
if (!audioEnabled.value) {
157-
switchTrackEnable('audio', false);
161+
// switchTrackEnable('audio', false);
158162
}
159163
mediaLoaded.value = true;
160164
}
161165
}
162166
});
163167

164168
// 进入页面先连接
165-
const watchEnableStop = watchEffect(() => {
166-
if (
167-
currentAudioInput.value &&
168-
currentCamera.value &&
169-
currentAudioOutput.value
170-
) {
171-
enabled.value = true;
172-
watchEnableStop();
173-
}
174-
});
169+
const startGetMedia = () => {
170+
return new Promise<MediaStream | undefined>((resolve) => {
171+
const watchEnableStop = watchEffect(async () => {
172+
if (
173+
currentAudioInput.value &&
174+
currentCamera.value &&
175+
currentAudioOutput.value
176+
) {
177+
const stream = await start();
178+
watchEnableStop();
179+
resolve(stream);
180+
}
181+
});
182+
});
183+
};
184+
185+
if (option.immeately) {
186+
startGetMedia();
187+
}
175188

176189
onBeforeUnmount(() => {
177190
stop();
178191
});
179192

180193
return {
194+
startGetMedia,
195+
stream,
181196
video,
182197
setSinkId,
183198
switchTrackEnable,
@@ -190,3 +205,51 @@ export const useVideoShare = (option: VideoShareOption = {}) => {
190205
currentAudioOutput,
191206
};
192207
};
208+
209+
export const useMediaConnect = (
210+
connect: { onTrack?: (track: MediaStreamTrack, id: string) => void } = {},
211+
...args: Parameters<typeof useMediaSetting>
212+
) => {
213+
const { startGetMedia, ...mediaResult } = useMediaSetting(...args);
214+
215+
let stream: MediaStream | undefined = undefined;
216+
useRoomConnect({
217+
async roomCreated() {
218+
console.log('ccccreated');
219+
stream = await startGetMedia();
220+
},
221+
roomJoined: async (_, pc) => {
222+
let innerStream = stream;
223+
stream = undefined;
224+
if (!innerStream) {
225+
innerStream = await startGetMedia();
226+
console.log('jjjjjjoined');
227+
}
228+
if (pc && innerStream) {
229+
innerStream.getTracks().forEach((track) => {
230+
pc.addTrack(track, innerStream);
231+
});
232+
}
233+
},
234+
onBeforeCreateAnswer: async (_, pc) => {
235+
let innerStream = stream;
236+
stream = undefined;
237+
if (!innerStream) {
238+
innerStream = await startGetMedia();
239+
}
240+
if (pc && innerStream) {
241+
innerStream.getTracks().forEach((track) => {
242+
pc.addTrack(track, innerStream);
243+
});
244+
}
245+
},
246+
onTrack(e: any, id: string) {
247+
console.log(e);
248+
if (e.track.kind === 'video') {
249+
connect.onTrack?.(e.streams[0], id);
250+
}
251+
},
252+
});
253+
254+
return { ...mediaResult };
255+
};

0 commit comments

Comments
 (0)