feat(streams): add phase-1 single-server SFU session and transport APIs
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
import { mediaConfig } from '../config';
|
||||
import { SfuSessionRegistry } from './registry';
|
||||
import type {
|
||||
SfuPublishTransportRequest,
|
||||
SfuPublishTransportResult,
|
||||
@@ -25,11 +26,11 @@ const toIceServers = (): Array<{ urls: string; username?: string; credential?: s
|
||||
|
||||
export class NoopSfuService implements SfuService {
|
||||
mode: 'single_server_sfu' = 'single_server_sfu';
|
||||
private readonly sessions = new Map<string, SfuSessionDescriptor>();
|
||||
private readonly registry = new SfuSessionRegistry();
|
||||
|
||||
async startSession(input: SfuSessionStartInput): Promise<SfuSessionDescriptor> {
|
||||
const now = new Date().toISOString();
|
||||
const existing = this.sessions.get(input.streamSessionId);
|
||||
const existing = this.registry.get(input.streamSessionId);
|
||||
if (existing) return existing;
|
||||
|
||||
const descriptor: SfuSessionDescriptor = {
|
||||
@@ -40,18 +41,24 @@ export class NoopSfuService implements SfuService {
|
||||
state: 'starting',
|
||||
createdAt: now,
|
||||
};
|
||||
this.sessions.set(input.streamSessionId, descriptor);
|
||||
return descriptor;
|
||||
return this.registry.set(descriptor);
|
||||
}
|
||||
|
||||
async setSessionState(streamSessionId: string, state: SfuSessionDescriptor['state']): Promise<void> {
|
||||
this.registry.updateState(streamSessionId, state);
|
||||
}
|
||||
|
||||
async endSession(streamSessionId: string): Promise<void> {
|
||||
const existing = this.sessions.get(streamSessionId);
|
||||
if (!existing) return;
|
||||
this.sessions.set(streamSessionId, { ...existing, state: 'ended' });
|
||||
this.registry.updateState(streamSessionId, 'ending');
|
||||
this.registry.updateState(streamSessionId, 'ended');
|
||||
}
|
||||
|
||||
async getSession(streamSessionId: string): Promise<SfuSessionDescriptor | null> {
|
||||
return this.sessions.get(streamSessionId) ?? null;
|
||||
return this.registry.get(streamSessionId);
|
||||
}
|
||||
|
||||
async listSessions(): Promise<SfuSessionDescriptor[]> {
|
||||
return this.registry.list();
|
||||
}
|
||||
|
||||
async createPublishTransport(_input: SfuPublishTransportRequest): Promise<SfuPublishTransportResult> {
|
||||
@@ -68,4 +75,3 @@ export class NoopSfuService implements SfuService {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
41
Backend/media/sfu/registry.ts
Normal file
41
Backend/media/sfu/registry.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { SfuSessionDescriptor, SfuSessionState } from './types';
|
||||
|
||||
type StoredSfuSession = SfuSessionDescriptor & {
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export class SfuSessionRegistry {
|
||||
private readonly sessions = new Map<string, StoredSfuSession>();
|
||||
|
||||
get(streamSessionId: string): SfuSessionDescriptor | null {
|
||||
const found = this.sessions.get(streamSessionId);
|
||||
if (!found) return null;
|
||||
const { updatedAt: _updatedAt, ...descriptor } = found;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
set(session: SfuSessionDescriptor): SfuSessionDescriptor {
|
||||
const now = new Date().toISOString();
|
||||
this.sessions.set(session.streamSessionId, { ...session, updatedAt: now });
|
||||
return session;
|
||||
}
|
||||
|
||||
updateState(streamSessionId: string, state: SfuSessionState): SfuSessionDescriptor | null {
|
||||
const existing = this.sessions.get(streamSessionId);
|
||||
if (!existing) return null;
|
||||
|
||||
const next: StoredSfuSession = {
|
||||
...existing,
|
||||
state,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
this.sessions.set(streamSessionId, next);
|
||||
const { updatedAt: _updatedAt, ...descriptor } = next;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
list(): SfuSessionDescriptor[] {
|
||||
return Array.from(this.sessions.values()).map(({ updatedAt: _updatedAt, ...descriptor }) => descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,10 @@ export type SfuSubscribeTransportResult = {
|
||||
export interface SfuService {
|
||||
mode: 'single_server_sfu';
|
||||
startSession(input: SfuSessionStartInput): Promise<SfuSessionDescriptor>;
|
||||
setSessionState(streamSessionId: string, state: SfuSessionState): Promise<void>;
|
||||
endSession(streamSessionId: string): Promise<void>;
|
||||
getSession(streamSessionId: string): Promise<SfuSessionDescriptor | null>;
|
||||
listSessions(): Promise<SfuSessionDescriptor[]>;
|
||||
createPublishTransport(input: SfuPublishTransportRequest): Promise<SfuPublishTransportResult>;
|
||||
createSubscribeTransport(input: SfuSubscribeTransportRequest): Promise<SfuSubscribeTransportResult>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user