fix(webcam): add suport for multiple tabs
This commit is contained in:
parent
429c9ba63e
commit
41d70b352a
@ -667,7 +667,7 @@ LEFT JOIN "user_voice" user_talking ON (
|
||||
|
||||
|
||||
CREATE TABLE "user_camera" (
|
||||
"streamId" varchar(100) PRIMARY KEY,
|
||||
"streamId" varchar(150) PRIMARY KEY,
|
||||
"meetingId" varchar(100),
|
||||
"userId" varchar(50),
|
||||
FOREIGN KEY ("meetingId", "userId") REFERENCES "user"("meetingId","userId") ON DELETE CASCADE
|
||||
|
@ -29,7 +29,7 @@ const VideoStreamAdapter: React.FC<AdapterProps> = ({
|
||||
|
||||
const streams = data.user_camera.map(({ streamId, user, voice }) => ({
|
||||
stream: streamId,
|
||||
deviceId: streamId.split('_')[2],
|
||||
deviceId: streamId.split('_')[3],
|
||||
userId: user.userId,
|
||||
name: user.name,
|
||||
nameSortable: user.nameSortable,
|
||||
|
@ -66,7 +66,7 @@ const FILTER_VIDEO_STATS = [
|
||||
];
|
||||
|
||||
export const useStatus = () => {
|
||||
const videoState = useVideoState()[0];
|
||||
const [videoState] = useVideoState();
|
||||
if (videoState.isConnecting) return 'videoConnecting';
|
||||
if (videoState.isConnected) return 'connected';
|
||||
return 'disconnected';
|
||||
@ -105,7 +105,7 @@ export const useVideoStreamsCount = () => {
|
||||
|
||||
export const useLocalVideoStreamsCount = () => {
|
||||
const { streams } = useStreams();
|
||||
const localStreams = streams.filter((vs) => vs.userId === Auth.userID);
|
||||
const localStreams = streams.filter((vs) => videoService.isLocalStream(vs.stream));
|
||||
|
||||
return localStreams.length;
|
||||
};
|
||||
@ -308,7 +308,7 @@ export const useStreamUsers = (isGridEnabled: boolean) => {
|
||||
export const useSharedDevices = () => {
|
||||
const { streams } = useStreams();
|
||||
const devices = streams
|
||||
.filter((s) => s.userId === Auth.userID)
|
||||
.filter((s) => videoService.isLocalStream(s.stream))
|
||||
.map((vs) => vs.deviceId);
|
||||
|
||||
return devices;
|
||||
@ -359,13 +359,13 @@ export const useVideoStreams = (
|
||||
if (connectingStream) streams.push(connectingStream);
|
||||
|
||||
if (!viewParticipantsWebcams) {
|
||||
streams = streams.filter((stream) => stream.userId === Auth.userID);
|
||||
streams = streams.filter((vs) => videoService.isLocalStream(vs.stream));
|
||||
}
|
||||
|
||||
if (isPaginationEnabled) {
|
||||
const [filtered, others] = partition(
|
||||
streams,
|
||||
(vs: StreamItem) => Auth.userID === vs.userId || (vs.type === 'stream' && vs.pinned),
|
||||
(vs: StreamItem) => videoService.isLocalStream(vs.stream) || (vs.type === 'stream' && vs.pinned),
|
||||
);
|
||||
const [pin, mine] = partition(
|
||||
filtered,
|
||||
@ -418,12 +418,17 @@ export const useVideoStreams = (
|
||||
|
||||
export const useHasVideoStream = () => {
|
||||
const { streams } = useStreams();
|
||||
return streams.some((s) => s.userId === Auth.userID);
|
||||
return streams.some((s) => videoService.isLocalStream(s.stream));
|
||||
};
|
||||
|
||||
const useOwnVideoStreamsQuery = () => useLazyQuery<OwnVideoStreamsResponse>(
|
||||
OWN_VIDEO_STREAMS_QUERY,
|
||||
{ variables: { userId: Auth.userID } },
|
||||
{
|
||||
variables: {
|
||||
userId: Auth.userID,
|
||||
streamIdPrefix: `${videoService.getPrefix()}%`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const useExitVideo = (forceExit = false) => {
|
||||
|
@ -65,10 +65,11 @@ export const VIDEO_STREAMS_SUBSCRIPTION = gql`
|
||||
`;
|
||||
|
||||
export const OWN_VIDEO_STREAMS_QUERY = gql`
|
||||
query OwnVideoStreams($userId: String!) {
|
||||
query OwnVideoStreams($userId: String!, $streamIdPrefix: String!) {
|
||||
user_camera(
|
||||
where: {
|
||||
userId: { _eq: $userId }
|
||||
userId: { _eq: $userId },
|
||||
streamId: { _like: $streamIdPrefix }
|
||||
},
|
||||
) {
|
||||
streamId
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Session } from 'meteor/session';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import Settings from '/imports/ui/services/settings';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
@ -60,6 +61,8 @@ class VideoService {
|
||||
|
||||
private deviceId: string | null = null;
|
||||
|
||||
private readonly tabId: string;
|
||||
|
||||
constructor() {
|
||||
this.userParameterProfile = null;
|
||||
this.isMobile = deviceInfo.isMobile;
|
||||
@ -67,6 +70,7 @@ class VideoService {
|
||||
this.numberOfDevices = 0;
|
||||
this.record = null;
|
||||
this.hackRecordViewer = null;
|
||||
this.tabId = uuid();
|
||||
|
||||
if (navigator.mediaDevices) {
|
||||
this.updateNumberOfDevices = this.updateNumberOfDevices.bind(this);
|
||||
@ -119,7 +123,7 @@ class VideoService {
|
||||
this.deviceId = deviceId;
|
||||
Storage.setItem('isFirstJoin', false);
|
||||
if (!VideoService.isUserLocked()) {
|
||||
const streamName = VideoService.buildStreamName(Auth.userID ?? '', deviceId);
|
||||
const streamName = this.buildStreamName(deviceId);
|
||||
const stream = {
|
||||
stream: streamName,
|
||||
userId: Auth.userID ?? '',
|
||||
@ -142,11 +146,13 @@ class VideoService {
|
||||
}));
|
||||
}
|
||||
|
||||
static storeDeviceIds(streams: Stream[]) {
|
||||
storeDeviceIds(streams: Stream[]) {
|
||||
const deviceIds: string[] = [];
|
||||
streams.filter((s) => s.userId === Auth.userID).forEach((s) => {
|
||||
deviceIds.push(s.deviceId);
|
||||
});
|
||||
streams
|
||||
.filter((s) => this.isLocalStream(s.stream))
|
||||
.forEach((s) => {
|
||||
deviceIds.push(s.deviceId);
|
||||
});
|
||||
Session.set('deviceIds', deviceIds.join());
|
||||
}
|
||||
|
||||
@ -220,8 +226,8 @@ class VideoService {
|
||||
setConnectingStream(null);
|
||||
}
|
||||
|
||||
static buildStreamName(userId: string, deviceId: string) {
|
||||
return `${userId}${TOKEN}${deviceId}`;
|
||||
buildStreamName(deviceId: string) {
|
||||
return `${this.getPrefix()}${TOKEN}${deviceId}`;
|
||||
}
|
||||
|
||||
static getMediaServerAdapter() {
|
||||
@ -280,13 +286,16 @@ class VideoService {
|
||||
&& !isBreakout);
|
||||
}
|
||||
|
||||
static getMyStreamId(deviceId: string, streams: Stream[]) {
|
||||
const videoStream = streams.find((vs) => vs.userId === Auth.userID && vs.deviceId === deviceId);
|
||||
getMyStreamId(deviceId: string, streams: Stream[]) {
|
||||
const videoStream = streams.find(
|
||||
(vs) => this.isLocalStream(vs.stream)
|
||||
&& vs.deviceId === deviceId,
|
||||
);
|
||||
return videoStream ? videoStream.stream : null;
|
||||
}
|
||||
|
||||
static isLocalStream(cameraId: string) {
|
||||
return !!Auth.userID && cameraId?.startsWith(Auth.userID);
|
||||
isLocalStream(cameraId = '') {
|
||||
return cameraId.startsWith(this.getPrefix());
|
||||
}
|
||||
|
||||
static getCameraProfile() {
|
||||
@ -492,6 +501,14 @@ class VideoService {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getTabId() {
|
||||
return this.tabId;
|
||||
}
|
||||
|
||||
getPrefix() {
|
||||
return `${Auth.userID}${TOKEN}${this.tabId}`;
|
||||
}
|
||||
}
|
||||
|
||||
const videoService = new VideoService();
|
||||
@ -499,7 +516,7 @@ const videoService = new VideoService();
|
||||
export default {
|
||||
addCandidateToPeer: VideoService.addCandidateToPeer,
|
||||
getInfo: VideoService.getInfo,
|
||||
getMyStreamId: VideoService.getMyStreamId,
|
||||
getMyStreamId: videoService.getMyStreamId.bind(videoService),
|
||||
getAuthenticatedURL: VideoService.getAuthenticatedURL,
|
||||
getRole: VideoService.getRole,
|
||||
getMediaServerAdapter: VideoService.getMediaServerAdapter,
|
||||
@ -509,11 +526,11 @@ export default {
|
||||
getNextVideoPage: VideoService.getNextVideoPage,
|
||||
getCurrentVideoPageIndex: VideoService.getCurrentVideoPageIndex,
|
||||
isVideoPinEnabledForCurrentUser: VideoService.isVideoPinEnabledForCurrentUser,
|
||||
isLocalStream: VideoService.isLocalStream,
|
||||
isLocalStream: videoService.isLocalStream.bind(videoService),
|
||||
isPaginationEnabled: VideoService.isPaginationEnabled,
|
||||
mirrorOwnWebcam: VideoService.mirrorOwnWebcam,
|
||||
processInboundIceQueue: VideoService.processInboundIceQueue,
|
||||
storeDeviceIds: VideoService.storeDeviceIds,
|
||||
storeDeviceIds: videoService.storeDeviceIds.bind(videoService),
|
||||
joinedVideo: () => VideoService.joinedVideo(),
|
||||
exitedVideo: () => videoService.exitedVideo(),
|
||||
getPreloadedStream: () => videoService.getPreloadedStream(),
|
||||
@ -536,4 +553,6 @@ export default {
|
||||
{ leading: false, trailing: true },
|
||||
),
|
||||
setTrackEnabled: (value: boolean) => videoService.setTrackEnabled(value),
|
||||
getTabId: videoService.getTabId.bind(videoService),
|
||||
getPrefix: videoService.getPrefix.bind(videoService),
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { StreamItem } from './types';
|
||||
import UserListService from '/imports/ui/components/user-list/service';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import VideoService from './service';
|
||||
|
||||
const DEFAULT_SORTING_MODE = 'LOCAL_ALPHABETICAL';
|
||||
|
||||
@ -52,15 +53,25 @@ export const sortVoiceActivityLocal = (s1: StreamItem, s2: StreamItem) => {
|
||||
|| UserListService.sortUsersByName(s1, s2);
|
||||
};
|
||||
|
||||
export const sortByLocal = (s1: StreamItem, s2: StreamItem) => {
|
||||
if (VideoService.isLocalStream(s1.stream)) {
|
||||
return -1;
|
||||
} if (VideoService.isLocalStream(s2.stream)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// pin -> local -> lastFloorTime (descending) -> alphabetical
|
||||
export const sortLocalVoiceActivity = (s1: StreamItem, s2: StreamItem) => mandatorySorting(s1, s2)
|
||||
|| UserListService.sortUsersByCurrent(s1, s2)
|
||||
|| sortByLocal(s1, s2)
|
||||
|| sortVoiceActivity(s1, s2)
|
||||
|| UserListService.sortUsersByName(s1, s2);
|
||||
|
||||
// pin -> local -> alphabetic
|
||||
export const sortLocalAlphabetical = (s1: StreamItem, s2: StreamItem) => mandatorySorting(s1, s2)
|
||||
|| UserListService.sortUsersByCurrent(s1, s2)
|
||||
|| sortByLocal(s1, s2)
|
||||
|| UserListService.sortUsersByName(s1, s2);
|
||||
|
||||
export const sortPresenter = (s1: StreamItem, s2: StreamItem) => {
|
||||
@ -75,7 +86,7 @@ export const sortPresenter = (s1: StreamItem, s2: StreamItem) => {
|
||||
|
||||
// pin -> local -> presenter -> alphabetical
|
||||
export const sortLocalPresenterAlphabetical = (s1: StreamItem, s2: StreamItem) => mandatorySorting(s1, s2)
|
||||
|| UserListService.sortUsersByCurrent(s1, s2)
|
||||
|| sortByLocal(s1, s2)
|
||||
|| sortPresenter(s1, s2)
|
||||
|| UserListService.sortUsersByName(s1, s2);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user