review
This commit is contained in:
@@ -37,7 +37,7 @@ import {
|
|||||||
import { type Logger } from "matrix-js-sdk/lib/logger";
|
import { type Logger } from "matrix-js-sdk/lib/logger";
|
||||||
import { deepCompare } from "matrix-js-sdk/lib/utils";
|
import { deepCompare } from "matrix-js-sdk/lib/utils";
|
||||||
|
|
||||||
import { constant, type Behavior } from "../../Behavior.ts";
|
import { type Behavior } from "../../Behavior.ts";
|
||||||
import { type IConnectionManager } from "../remoteMembers/ConnectionManager.ts";
|
import { type IConnectionManager } from "../remoteMembers/ConnectionManager.ts";
|
||||||
import { type ObservableScope } from "../../ObservableScope.ts";
|
import { type ObservableScope } from "../../ObservableScope.ts";
|
||||||
import { type Publisher } from "./Publisher.ts";
|
import { type Publisher } from "./Publisher.ts";
|
||||||
@@ -68,6 +68,8 @@ export enum TransportState {
|
|||||||
|
|
||||||
export enum PublishState {
|
export enum PublishState {
|
||||||
WaitingForUser = "publish_waiting_for_user",
|
WaitingForUser = "publish_waiting_for_user",
|
||||||
|
// XXX: This state is removed for now since we do not have full control over
|
||||||
|
// track publication anymore with the publisher abstraction, might come back in the future?
|
||||||
// /** Implies lk connection is connected */
|
// /** Implies lk connection is connected */
|
||||||
// Starting = "publish_start_publishing",
|
// Starting = "publish_start_publishing",
|
||||||
/** Implies lk connection is connected */
|
/** Implies lk connection is connected */
|
||||||
@@ -79,6 +81,8 @@ export enum PublishState {
|
|||||||
export enum TrackState {
|
export enum TrackState {
|
||||||
/** The track is waiting for user input to create tracks (waiting to call `startTracks()`) */
|
/** The track is waiting for user input to create tracks (waiting to call `startTracks()`) */
|
||||||
WaitingForUser = "tracks_waiting_for_user",
|
WaitingForUser = "tracks_waiting_for_user",
|
||||||
|
// XXX: This state is removed for now since we do not have full control over
|
||||||
|
// track creation anymore with the publisher abstraction, might come back in the future?
|
||||||
// /** Implies lk connection is connected */
|
// /** Implies lk connection is connected */
|
||||||
// Creating = "tracks_creating",
|
// Creating = "tracks_creating",
|
||||||
/** Implies lk connection is connected */
|
/** Implies lk connection is connected */
|
||||||
@@ -154,9 +158,10 @@ export const createLocalMembership$ = ({
|
|||||||
matrixRTCSession,
|
matrixRTCSession,
|
||||||
}: Props): {
|
}: Props): {
|
||||||
/**
|
/**
|
||||||
* This starts audio and video tracks. They will be reused when calling `requestPublish`.
|
* This request to start audio and video tracks.
|
||||||
|
* Can be called early to pre-emptively get media permissions and start devices.
|
||||||
*/
|
*/
|
||||||
startTracks: () => Behavior<void>;
|
startTracks: () => void;
|
||||||
/**
|
/**
|
||||||
* This sets a inner state (shouldPublish) to true and instructs the js-sdk and livekit to keep the user
|
* This sets a inner state (shouldPublish) to true and instructs the js-sdk and livekit to keep the user
|
||||||
* connected to matrix and livekit.
|
* connected to matrix and livekit.
|
||||||
@@ -265,19 +270,10 @@ export const createLocalMembership$ = ({
|
|||||||
* The publisher is stored in here an abstracts creating and publishing tracks.
|
* The publisher is stored in here an abstracts creating and publishing tracks.
|
||||||
*/
|
*/
|
||||||
const publisher$ = new BehaviorSubject<Publisher | null>(null);
|
const publisher$ = new BehaviorSubject<Publisher | null>(null);
|
||||||
/**
|
|
||||||
* Extract the tracks from the published. Also reacts to changing publishers.
|
|
||||||
*/
|
|
||||||
// const tracks$ = scope.behavior(
|
|
||||||
// publisher$.pipe(switchMap((p) => (p?.tracks$ ? p.tracks$ : constant([])))),
|
|
||||||
// );
|
|
||||||
// const publishing$ = scope.behavior(
|
|
||||||
// publisher$.pipe(switchMap((p) => p?.publishing$ ?? constant(false))),
|
|
||||||
// );
|
|
||||||
|
|
||||||
const startTracks = (): Behavior<void> => {
|
const startTracks = (): void => {
|
||||||
trackStartRequested.resolve();
|
trackStartRequested.resolve();
|
||||||
return constant(undefined);
|
// This used to return the tracks, but now they are only accessible via the publisher.
|
||||||
};
|
};
|
||||||
|
|
||||||
const requestJoinAndPublish = (): void => {
|
const requestJoinAndPublish = (): void => {
|
||||||
@@ -348,14 +344,6 @@ export const createLocalMembership$ = ({
|
|||||||
setPublishError(new UnknownCallError(error as Error));
|
setPublishError(new UnknownCallError(error as Error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// XXX Why is that?
|
|
||||||
// else {
|
|
||||||
// try {
|
|
||||||
// await publisher?.stopPublishing();
|
|
||||||
// } catch (error) {
|
|
||||||
// setLivekitError(new UnknownCallError(error as Error));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -401,16 +389,10 @@ export const createLocalMembership$ = ({
|
|||||||
([
|
([
|
||||||
localConnectionState,
|
localConnectionState,
|
||||||
localTransport,
|
localTransport,
|
||||||
// tracks,
|
|
||||||
// publishing,
|
|
||||||
shouldPublish,
|
shouldPublish,
|
||||||
shouldStartTracks,
|
shouldStartTracks,
|
||||||
]) => {
|
]) => {
|
||||||
if (!localTransport) return null;
|
if (!localTransport) return null;
|
||||||
// const hasTracks = tracks.length > 0;
|
|
||||||
// let trackState: TrackState = TrackState.WaitingForUser;
|
|
||||||
// if (hasTracks && shouldStartTracks) trackState = TrackState.Ready;
|
|
||||||
// if (!hasTracks && shouldStartTracks) trackState = TrackState.Creating;
|
|
||||||
const trackState: TrackState = shouldStartTracks
|
const trackState: TrackState = shouldStartTracks
|
||||||
? TrackState.Ready
|
? TrackState.Ready
|
||||||
: TrackState.WaitingForUser;
|
: TrackState.WaitingForUser;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ beforeEach(() => {
|
|||||||
scope = new ObservableScope();
|
scope = new ObservableScope();
|
||||||
});
|
});
|
||||||
|
|
||||||
// afterEach(() => scope.end());
|
afterEach(() => scope.end());
|
||||||
|
|
||||||
function createMockLocalTrack(source: Track.Source): LocalTrack {
|
function createMockLocalTrack(source: Track.Source): LocalTrack {
|
||||||
const track = {
|
const track = {
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export class Publisher {
|
|||||||
// it would also prevent the user from seeing their own video/audio preview.
|
// it would also prevent the user from seeing their own video/audio preview.
|
||||||
// So for that we use pauseUpStream(): Stops sending media to the server by replacing
|
// So for that we use pauseUpStream(): Stops sending media to the server by replacing
|
||||||
// the sender track with null, but keeps the local MediaStreamTrack active.
|
// the sender track with null, but keeps the local MediaStreamTrack active.
|
||||||
// The user can still see/hear themselves locally, but remote participants see nothing
|
// The user can still see/hear themselves locally, but remote participants see nothing.
|
||||||
private onLocalTrackPublished(
|
private onLocalTrackPublished(
|
||||||
localTrackPublication: LocalTrackPublication,
|
localTrackPublication: LocalTrackPublication,
|
||||||
): void {
|
): void {
|
||||||
@@ -128,6 +128,15 @@ export class Publisher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
* Create and setup local audio and video tracks based on the current mute states.
|
||||||
|
* It creates the tracks only if audio and/or video is enabled, to avoid unnecessary
|
||||||
|
* permission prompts.
|
||||||
|
*
|
||||||
|
* It also observes mute state changes to update LiveKit microphone/camera states accordingly.
|
||||||
|
* If a track is not created initially because disabled, it will be created when unmuting.
|
||||||
|
*
|
||||||
|
* This call is not blocking anymore, instead callers can listen to the
|
||||||
|
* `RoomEvent.MediaDevicesError` event in the LiveKit room to be notified of any errors.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public async createAndSetupTracks(): Promise<void> {
|
public async createAndSetupTracks(): Promise<void> {
|
||||||
@@ -141,25 +150,21 @@ export class Publisher {
|
|||||||
const audio = this.muteStates.audio.enabled$.value;
|
const audio = this.muteStates.audio.enabled$.value;
|
||||||
const video = this.muteStates.video.enabled$.value;
|
const video = this.muteStates.video.enabled$.value;
|
||||||
|
|
||||||
const enableTracks = async (): Promise<void> => {
|
// We don't await the creation, because livekit could block until the tracks
|
||||||
if (audio && video) {
|
|
||||||
// Enable both at once in order to have a single permission prompt!
|
|
||||||
await lkRoom.localParticipant.enableCameraAndMicrophone();
|
|
||||||
} else if (audio) {
|
|
||||||
await lkRoom.localParticipant.setMicrophoneEnabled(true);
|
|
||||||
} else if (video) {
|
|
||||||
await lkRoom.localParticipant.setCameraEnabled(true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// We don't await enableTracks, because livekit could block until the tracks
|
|
||||||
// are fully published, and not only that they are created.
|
// are fully published, and not only that they are created.
|
||||||
// We don't have control on that, localParticipant creates and publishes the tracks
|
// We don't have control on that, localParticipant creates and publishes the tracks
|
||||||
// asap.
|
// asap.
|
||||||
// We are using the `ParticipantEvent.LocalTrackPublished` to be notified
|
// We are using the `ParticipantEvent.LocalTrackPublished` to be notified
|
||||||
// when tracks are actually published, and at that point
|
// when tracks are actually published, and at that point
|
||||||
// we can pause upstream if needed (depending on if startPublishing has been called).
|
// we can pause upstream if needed (depending on if startPublishing has been called).
|
||||||
void enableTracks();
|
if (audio && video) {
|
||||||
|
// Enable both at once in order to have a single permission prompt!
|
||||||
|
void lkRoom.localParticipant.enableCameraAndMicrophone();
|
||||||
|
} else if (audio) {
|
||||||
|
void lkRoom.localParticipant.setMicrophoneEnabled(true);
|
||||||
|
} else if (video) {
|
||||||
|
void lkRoom.localParticipant.setCameraEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -233,6 +238,8 @@ export class Publisher {
|
|||||||
public async stopPublishing(): Promise<void> {
|
public async stopPublishing(): Promise<void> {
|
||||||
this.logger.debug("stopPublishing called");
|
this.logger.debug("stopPublishing called");
|
||||||
this.shouldPublish = false;
|
this.shouldPublish = false;
|
||||||
|
// Pause upstream will stop sending media to the server, while keeping
|
||||||
|
// the local MediaStreamTrack active, so the user can still see themselves.
|
||||||
await this.pauseUpstreams(this.connection.livekitRoom, [
|
await this.pauseUpstreams(this.connection.livekitRoom, [
|
||||||
Track.Source.Microphone,
|
Track.Source.Microphone,
|
||||||
Track.Source.Camera,
|
Track.Source.Camera,
|
||||||
|
|||||||
Reference in New Issue
Block a user