Revert "feat(streams): add phase-2 SFU transport handshake and produce/consume APIs"

This reverts commit 498a7f838b7747470b220701505c4bfbd3ea8cff.
This commit is contained in:
2026-02-20 14:00:00 +00:00
parent ef652ea7e5
commit 37d7c27ba0
12 changed files with 65 additions and 1395 deletions

View File

@@ -17,18 +17,7 @@ router.get('/ready', async (_req, res) => {
try {
await db.execute('select 1');
await minioClient.bucketExists(minioBucket);
const sfu = sfuService;
const sfuSessions = sfu ? await sfu.listSessions() : [];
const sfuSessionIds = sfuSessions.map((session) => session.streamSessionId);
const sfuTransports = sfu
? (await Promise.all(sfuSessionIds.map(async (streamSessionId) => await sfu.listTransports(streamSessionId)))).flat()
: [];
const sfuProducers = sfu
? (await Promise.all(sfuSessionIds.map(async (streamSessionId) => await sfu.listProducers(streamSessionId)))).flat()
: [];
const sfuConsumers = sfu
? (await Promise.all(sfuSessionIds.map(async (streamSessionId) => await sfu.listConsumers(streamSessionId)))).flat()
: [];
const sfuSessions = sfuService ? await sfuService.listSessions() : [];
res.json({
status: 'ready',
@@ -39,9 +28,6 @@ router.get('/ready', async (_req, res) => {
mediaProvider: mediaProvider.name,
sfuService: sfuService ? sfuService.mode : 'disabled',
sfuActiveSessions: sfuSessions.filter((session) => session.state !== 'ended').length,
sfuTransports: sfuTransports.length,
sfuProducers: sfuProducers.length,
sfuConsumers: sfuConsumers.length,
},
timestamp: new Date().toISOString(),
});

View File

@@ -40,23 +40,6 @@ const sfuTransportRequestSchema = z.object({
role: z.enum(['camera', 'viewer']).optional(),
});
const sfuTransportConnectSchema = z.object({
transportId: z.string().min(1),
dtlsParameters: z.record(z.string(), z.unknown()).default({}),
});
const sfuProduceSchema = z.object({
transportId: z.string().min(1),
kind: z.enum(['audio', 'video']).default('video'),
rtpParameters: z.record(z.string(), z.unknown()).default({}),
});
const sfuConsumeSchema = z.object({
transportId: z.string().min(1),
producerId: z.string().min(1).optional(),
rtpCapabilities: z.record(z.string(), z.unknown()).optional(),
});
const listSchema = z.object({
status: z.string().optional(),
limit: z.coerce.number().int().min(1).max(100).default(25),
@@ -105,14 +88,6 @@ const getOwnedStreamSession = async (streamSessionId: string, ownerUserId: strin
where: and(eq(streamSessions.id, streamSessionId), eq(streamSessions.ownerUserId, ownerUserId)),
});
const ensureSfuEnabled = (res: Parameters<typeof requireDeviceAuth>[1]) => {
if (!sfuService) {
res.status(409).json({ message: `SFU service disabled (MEDIA_MODE=${mediaMode})` });
return null;
}
return sfuService;
};
router.post('/request', requireDeviceAuth, async (req, res) => {
const parsed = requestStreamSchema.safeParse(req.body ?? {});
@@ -471,8 +446,10 @@ router.get('/:streamSessionId/sfu/session', requireDeviceAuth, async (req, res)
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
if (!sfuService) {
res.status(409).json({ message: `SFU service disabled (MEDIA_MODE=${mediaMode})` });
return;
}
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
@@ -486,58 +463,11 @@ router.get('/:streamSessionId/sfu/session', requireDeviceAuth, async (req, res)
return;
}
const [sfuSession, transports, producers, consumers] = await Promise.all([
sfu.getSession(session.id),
sfu.listTransports(session.id),
sfu.listProducers(session.id),
sfu.listConsumers(session.id),
]);
const sfuSession = await sfuService.getSession(session.id);
res.json({
streamSessionId: session.id,
mediaMode,
sfuSession,
transports,
producers,
consumers,
});
});
router.get('/:streamSessionId/sfu/router-rtp-capabilities', requireDeviceAuth, async (req, res) => {
const parsedParams = streamParamSchema.safeParse(req.params);
if (!parsedParams.success) {
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
return;
}
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
res.status(404).json({ message: 'Stream session not found' });
return;
}
const isParticipant = session.requesterDeviceId === deviceAuth.deviceId || session.cameraDeviceId === deviceAuth.deviceId;
if (!isParticipant) {
res.status(403).json({ message: 'Device cannot access SFU router capabilities for this stream' });
return;
}
const routerRtpCapabilities = await sfu.getRouterRtpCapabilities(session.id);
if (!routerRtpCapabilities) {
res.status(409).json({ message: 'SFU session is not initialized for this stream' });
return;
}
res.json({
streamSessionId: session.id,
mediaMode,
routerRtpCapabilities,
});
});
@@ -557,8 +487,10 @@ router.post('/:streamSessionId/sfu/publish-transport', requireDeviceAuth, async
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
if (!sfuService) {
res.status(409).json({ message: `SFU service disabled (MEDIA_MODE=${mediaMode})` });
return;
}
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
@@ -576,11 +508,11 @@ router.post('/:streamSessionId/sfu/publish-transport', requireDeviceAuth, async
return;
}
const transport = await sfu.createPublishTransport({
const transport = await sfuService.createPublishTransport({
streamSessionId: session.id,
cameraDeviceId: deviceAuth.deviceId,
});
await sfu.setSessionState(session.id, 'live');
await sfuService.setSessionState(session.id, 'live');
res.json({
streamSessionId: session.id,
@@ -605,8 +537,10 @@ router.post('/:streamSessionId/sfu/subscribe-transport', requireDeviceAuth, asyn
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
if (!sfuService) {
res.status(409).json({ message: `SFU service disabled (MEDIA_MODE=${mediaMode})` });
return;
}
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
@@ -625,11 +559,11 @@ router.post('/:streamSessionId/sfu/subscribe-transport', requireDeviceAuth, asyn
return;
}
const transport = await sfu.createSubscribeTransport({
const transport = await sfuService.createSubscribeTransport({
streamSessionId: session.id,
viewerDeviceId: deviceAuth.deviceId,
});
await sfu.setSessionState(session.id, 'live');
await sfuService.setSessionState(session.id, 'live');
res.json({
streamSessionId: session.id,
@@ -638,186 +572,6 @@ router.post('/:streamSessionId/sfu/subscribe-transport', requireDeviceAuth, asyn
});
});
router.post('/:streamSessionId/sfu/publish-transport/connect', requireDeviceAuth, async (req, res) => {
const parsedParams = streamParamSchema.safeParse(req.params);
if (!parsedParams.success) {
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
return;
}
const parsedBody = sfuTransportConnectSchema.safeParse(req.body ?? {});
if (!parsedBody.success) {
res.status(400).json({ message: 'Invalid request body', errors: parsedBody.error.flatten() });
return;
}
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
res.status(404).json({ message: 'Stream session not found' });
return;
}
if (session.cameraDeviceId !== deviceAuth.deviceId) {
res.status(403).json({ message: 'Only camera device can connect publish transport' });
return;
}
try {
const transport = await sfu.connectPublishTransport({
streamSessionId: session.id,
transportId: parsedBody.data.transportId,
deviceId: deviceAuth.deviceId,
dtlsParameters: parsedBody.data.dtlsParameters,
});
await sfu.setSessionState(session.id, 'live');
res.json({ streamSessionId: session.id, mediaMode, transport });
} catch (error) {
res.status(409).json({ message: error instanceof Error ? error.message : 'Unable to connect publish transport' });
}
});
router.post('/:streamSessionId/sfu/subscribe-transport/connect', requireDeviceAuth, async (req, res) => {
const parsedParams = streamParamSchema.safeParse(req.params);
if (!parsedParams.success) {
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
return;
}
const parsedBody = sfuTransportConnectSchema.safeParse(req.body ?? {});
if (!parsedBody.success) {
res.status(400).json({ message: 'Invalid request body', errors: parsedBody.error.flatten() });
return;
}
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
res.status(404).json({ message: 'Stream session not found' });
return;
}
const isParticipant = session.requesterDeviceId === deviceAuth.deviceId || session.cameraDeviceId === deviceAuth.deviceId;
if (!isParticipant) {
res.status(403).json({ message: 'Device cannot connect subscribe transport for this stream' });
return;
}
try {
const transport = await sfu.connectSubscribeTransport({
streamSessionId: session.id,
transportId: parsedBody.data.transportId,
deviceId: deviceAuth.deviceId,
dtlsParameters: parsedBody.data.dtlsParameters,
});
await sfu.setSessionState(session.id, 'live');
res.json({ streamSessionId: session.id, mediaMode, transport });
} catch (error) {
res.status(409).json({ message: error instanceof Error ? error.message : 'Unable to connect subscribe transport' });
}
});
router.post('/:streamSessionId/sfu/produce', requireDeviceAuth, async (req, res) => {
const parsedParams = streamParamSchema.safeParse(req.params);
if (!parsedParams.success) {
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
return;
}
const parsedBody = sfuProduceSchema.safeParse(req.body ?? {});
if (!parsedBody.success) {
res.status(400).json({ message: 'Invalid request body', errors: parsedBody.error.flatten() });
return;
}
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
res.status(404).json({ message: 'Stream session not found' });
return;
}
if (session.cameraDeviceId !== deviceAuth.deviceId) {
res.status(403).json({ message: 'Only camera device can publish media' });
return;
}
try {
const producer = await sfu.produce({
streamSessionId: session.id,
transportId: parsedBody.data.transportId,
cameraDeviceId: deviceAuth.deviceId,
kind: parsedBody.data.kind,
rtpParameters: parsedBody.data.rtpParameters,
});
await sfu.setSessionState(session.id, 'live');
res.json({ streamSessionId: session.id, mediaMode, producer });
} catch (error) {
res.status(409).json({ message: error instanceof Error ? error.message : 'Unable to produce media' });
}
});
router.post('/:streamSessionId/sfu/consume', requireDeviceAuth, async (req, res) => {
const parsedParams = streamParamSchema.safeParse(req.params);
if (!parsedParams.success) {
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
return;
}
const parsedBody = sfuConsumeSchema.safeParse(req.body ?? {});
if (!parsedBody.success) {
res.status(400).json({ message: 'Invalid request body', errors: parsedBody.error.flatten() });
return;
}
const deviceAuth = ensureDeviceAuth(req, res);
if (!deviceAuth) return;
const sfu = ensureSfuEnabled(res);
if (!sfu) return;
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
if (!session) {
res.status(404).json({ message: 'Stream session not found' });
return;
}
const isParticipant = session.requesterDeviceId === deviceAuth.deviceId || session.cameraDeviceId === deviceAuth.deviceId;
if (!isParticipant) {
res.status(403).json({ message: 'Device cannot consume media for this stream' });
return;
}
try {
const consumer = await sfu.consume({
streamSessionId: session.id,
transportId: parsedBody.data.transportId,
viewerDeviceId: deviceAuth.deviceId,
producerId: parsedBody.data.producerId,
rtpCapabilities: parsedBody.data.rtpCapabilities,
});
await sfu.setSessionState(session.id, 'live');
res.json({ streamSessionId: session.id, mediaMode, consumer });
} catch (error) {
res.status(409).json({ message: error instanceof Error ? error.message : 'Unable to consume media' });
}
});
router.post('/:streamSessionId/end', requireDeviceAuth, async (req, res) => {
const parsedParams = streamParamSchema.safeParse(req.params);