Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
balazskreith committed Oct 30, 2024
1 parent a8bc1a3 commit bb8e5c4
Show file tree
Hide file tree
Showing 18 changed files with 422 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
10 changes: 10 additions & 0 deletions media-server/src/client-listeners/CreateProducerRequestListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const logger = createLogger('CreateProducerRequestListener');
export type CreateProducerRequestListenerContext = {
mediasoupService: MediasoupService,
clients: Map<string, ClientContext>,
maxProducerPerClients: number,
}

export function createCreateProducerRequestListener(listenerContext: CreateProducerRequestListenerContext) {
Expand All @@ -27,14 +28,23 @@ export function createCreateProducerRequestListener(listenerContext: CreateProdu
return console.warn(`Invalid message type ${request.type}`);
} else if (!client) {
return console.warn(`Client ${messageContext.clientId} not found`);
} else if (!client.routerId) {
return console.warn(`Client ${messageContext.clientId} routerId not found`);
} else if (client.sndTransport === undefined) {
return console.warn(`Client ${messageContext.clientId} has no sending transport`);
} else if (client.mediaProducers.size >= listenerContext.maxProducerPerClients) {
return messageContext.send(new Response(
request.requestId,
undefined,
`Max producers per client reached`
));
}

let response: CreateProducerResponsePayload | undefined;
let error: string | undefined;
try {


const producer = await client.sndTransport.produce({
kind: request.kind,
rtpParameters: request.rtpParameters,
Expand Down
17 changes: 16 additions & 1 deletion media-server/src/client-listeners/JoinCallRequestListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const logger = createLogger('JoinCallRequestListener');
export type JoinCallRequestListenerContext = {
mediasoupService: MediasoupService;
clients: Map<string, ClientContext>;
maxTransportsPerRouter: number;
}

type TurnServerConfig = {
Expand Down Expand Up @@ -37,12 +38,22 @@ export function createJoinCallRequestListener(listenerContext: JoinCallRequestLi

logger.debug(`Client ${client.clientId} joining call ${request.callId}. request: %o`, request);

let closeClient = false;
let response: JoinCallResponsePayload | undefined;
let error: string | undefined;

try {
if (request.callId && mediasoupService.routers.has(request.callId) === false) {
throw new Error(`Call with id ${request.callId} does not exist`);
}

const router = await mediasoupService.getOrCreateRouter(request.callId);


if (listenerContext.maxTransportsPerRouter <= router.appData.transports.size) {
closeClient = true;
throw new Error(`Max transports per router reached`);
}

client.routerId = router.id;

const turnResponse = await (await fetch(`http://stunner-auth.stunner-system:8088?service=turn`)).json();
Expand Down Expand Up @@ -75,6 +86,10 @@ export function createJoinCallRequestListener(listenerContext: JoinCallRequestLi
response,
error
));

if (closeClient) {
client.webSocket.close();
}
};
return result;
}
4 changes: 4 additions & 0 deletions media-server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export type Config = {
configPath?: string;
server: ServerConfig,
mediasoup: MediasoupServiceConfig;
maxTransportsPerRouter: number;
maxProducerPerClients: number;
};

const getDefaultConfig: () => Config = () => {
Expand All @@ -16,6 +18,8 @@ const getDefaultConfig: () => Config = () => {
serverIp: '127.0.0.1',
// announcedIp: '127.0.0.1',
},
maxTransportsPerRouter: 6,
maxProducerPerClients: 1,
mediasoup: {
numberOfWorkers: 1,
workerSettings: {
Expand Down
2 changes: 2 additions & 0 deletions media-server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const listeners = new Map<ClientMessage['type'], ClientMessageListener>()
.set('join-call-request', createJoinCallRequestListener({
mediasoupService,
clients,
maxTransportsPerRouter: config.maxTransportsPerRouter,
}))
.set('connect-transport-request', createConnectTransportRequestListener({
mediasoupService,
Expand Down Expand Up @@ -66,6 +67,7 @@ const listeners = new Map<ClientMessage['type'], ClientMessageListener>()
createCreateProducerRequestListener({
clients,
mediasoupService,
maxProducerPerClients: config.maxProducerPerClients,
})
)
.set(
Expand Down
55 changes: 38 additions & 17 deletions media-server/src/services/MediasoupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ type WorkerAppData = {
webRtcServer?: mediasoup.types.WebRtcServer<{ port: number }>;
}

type RouterAppData = {
export type RouterAppData = {
workerPid: number;
mediaProducers: Map<string, mediasoup.types.Producer<ProducerAppData>>;
mediaConsumers: Map<string, mediasoup.types.Consumer<ConsumerAppData>>;
dataProducers: Map<string, mediasoup.types.DataProducer>;
dataConsumers: Map<string, mediasoup.types.DataConsumer>;
transports: Map<string, mediasoup.types.Transport>;
}

type ProducerAppData = {
Expand Down Expand Up @@ -116,34 +121,39 @@ export class MediasoupService {
}
}

public async getOrCreateRouter(routerId?: string): Promise<mediasoup.types.Router> {
public async getOrCreateRouter(routerId?: string): Promise<mediasoup.types.Router<RouterAppData>> {
if (!this.workers) throw new Error('Worker is not started');

let router = this.routers.get(routerId || '');

if (router) return router;

const worker = [...this.workers.values()][Math.floor(Math.random() * this.workers.size)];
router = await worker.createRouter<RouterAppData>({
const newrouter = await worker.createRouter<RouterAppData>({
mediaCodecs: this.config.mediaCodecs,
appData: {
workerPid: worker.pid,
dataConsumers: new Map(),
dataProducers: new Map(),
mediaConsumers: new Map(),
mediaProducers: new Map(),
transports: new Map(),
}
});

const addTransport = (transport: mediasoup.types.Transport) => this._addTransport(router!, transport);
const addTransport = (transport: mediasoup.types.Transport) => this._addTransport(newrouter, transport);

router.observer.once('close', () => {
router.observer.off('newtransport', addTransport);
this.routers.delete(router!.id);
newrouter.observer.once('close', () => {
newrouter.observer.off('newtransport', addTransport);
this.routers.delete(newrouter.id);

logger.info(`Router ${router!.id} closed`);
logger.info(`Router ${newrouter.id} closed`);
})
router.observer.on('newtransport', addTransport);
this.routers.set(router.id, router);
newrouter.observer.on('newtransport', addTransport);
this.routers.set(newrouter.id, newrouter);

logger.info(`Router ${router.id} created`);
return router;
logger.info(`Router ${newrouter.id} created`);
return newrouter;
}

public async consumeMediaProducer(producerId: string, consumingClient: ClientContext): Promise<mediasoup.types.Consumer> {
Expand Down Expand Up @@ -198,7 +208,7 @@ export class MediasoupService {
return consumer;
};

private _addTransport = (router: mediasoup.types.Router, transport: mediasoup.types.Transport) => {
private _addTransport = (router: mediasoup.types.Router<RouterAppData>, transport: mediasoup.types.Transport) => {

const addProducer = (producer: mediasoup.types.Producer) => this._addProducer(router, transport, producer);
const addConsumer = (consumer: mediasoup.types.Consumer) => this._addConsumer(router, transport, consumer);
Expand All @@ -211,6 +221,7 @@ export class MediasoupService {
transport.observer.off('newdataproducer', addDataProducer);
transport.observer.off('newdataconsumer', addDataConsumer);

router.appData.transports.delete(transport.id);
this.transports.delete(transport.id);

logger.info(`Transport ${transport.id} closed on router ${router.id}. the number of transports is ${this.transports.size}`);
Expand All @@ -225,14 +236,16 @@ export class MediasoupService {
transport.observer.on('newdataproducer', addDataProducer);
transport.observer.on('newdataconsumer', addDataConsumer);

router.appData.transports.set(transport.id, transport);
this.transports.set(transport.id, transport);

logger.info(`Transport ${transport.id} created on router ${router.id}`);

}

private _addProducer = (router: mediasoup.types.Router, transport: mediasoup.types.Transport, producer: mediasoup.types.Producer) => {
private _addProducer = (router: mediasoup.types.Router<RouterAppData>, transport: mediasoup.types.Transport, producer: mediasoup.types.Producer) => {
producer.observer.once('close', () => {
router.appData.mediaProducers.delete(producer.id);
this.mediaProducers.delete(producer.id);

logger.info(`Producer ${producer.id} closed on transport ${transport.id} on router ${router.id}`);
Expand All @@ -241,39 +254,47 @@ export class MediasoupService {
producer.appData.routerId = router.id;
producer.appData.transportId = transport.id;
producer.appData.remoteClosed = false;

router.appData.mediaProducers.set(producer.id, producer as mediasoup.types.Producer<ProducerAppData>);
this.mediaProducers.set(producer.id, producer as mediasoup.types.Producer<ProducerAppData>);

logger.info(`Producer ${producer.id} created on transport ${transport.id} on router ${router.id}`);
}

private _addConsumer = (router: mediasoup.types.Router, transport: mediasoup.types.Transport, consumer: mediasoup.types.Consumer) => {
private _addConsumer = (router: mediasoup.types.Router<RouterAppData>, transport: mediasoup.types.Transport, consumer: mediasoup.types.Consumer) => {
consumer.observer.once('close', () => {
router.appData.mediaConsumers.delete(consumer.id);
this.mediaConsumers.delete(consumer.id);

logger.info(`Consumer ${consumer.id} closed on transport ${transport.id} on router ${router.id}`);
});
router.appData.mediaConsumers.set(consumer.id, consumer);
this.mediaConsumers.set(consumer.id, consumer);

logger.info(`Consumer ${consumer.id} created on transport ${transport.id} on router ${router.id}`);
}

private _addDataProducer = (router: mediasoup.types.Router, transport: mediasoup.types.Transport, dataProducer: mediasoup.types.DataProducer) => {
private _addDataProducer = (router: mediasoup.types.Router<RouterAppData>, transport: mediasoup.types.Transport, dataProducer: mediasoup.types.DataProducer) => {
dataProducer.observer.once('close', () => {
router.appData.dataProducers.delete(dataProducer.id);
this.dataProducers.delete(dataProducer.id);

logger.info(`Data producer ${dataProducer.id} closed on transport ${transport.id} on router ${router.id}`);
});
router.appData.dataProducers.set(dataProducer.id, dataProducer);
this.dataProducers.set(dataProducer.id, dataProducer);

logger.info(`Data producer ${dataProducer.id} created on transport ${transport.id} on router ${router.id}`);
}

private _addDataConsumer = (router: mediasoup.types.Router, transport: mediasoup.types.Transport, dataConsumer: mediasoup.types.DataConsumer) => {
private _addDataConsumer = (router: mediasoup.types.Router<RouterAppData>, transport: mediasoup.types.Transport, dataConsumer: mediasoup.types.DataConsumer) => {
dataConsumer.observer.once('close', () => {
router.appData.dataConsumers.delete(dataConsumer.id);
this.dataConsumers.delete(dataConsumer.id);

logger.info(`Data consumer ${dataConsumer.id} closed on transport ${transport.id} on router ${router.id}`);
});
router.appData.dataConsumers.set(dataConsumer.id, dataConsumer);
this.dataConsumers.set(dataConsumer.id, dataConsumer);

logger.info(`Data consumer ${dataConsumer.id} created on transport ${transport.id} on router ${router.id}`);
Expand Down
3 changes: 2 additions & 1 deletion webapp/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
dist
yarn-error.log
build
build
.vscode
22 changes: 12 additions & 10 deletions webapp/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
import { Switch, type Component, Match } from 'solid-js';
import { Switch, type Component, Match, Show } from 'solid-js';
import { page } from './signals/signals';
import Join from './views/Join';
import { Transition } from 'solid-transition-group';
import ObserverView from './views/OngoingCalls';
import { Grid } from '@suid/material';
import Menu from './views/Menu';
import ClientMonitor from './components/ClientMonitor/ClientMonitor';
import PoweredByCmp from './components/PoweredBy/PoweredByCmp';
import VideoCall from './views/VideoCall';
import Main from './views/Main';
import { clientStore } from './stores/LocalClientStore';


const App: Component = () => {
return (
<Grid container spacing={2}>
<Grid item xs={2}>
<Menu />
</Grid>
<Grid item xs={10}>
<Grid item xs={9}>
<Transition name='fade' mode='outin'>
<Switch>
<Match when={page() === 'main'}><Main/></Match>
<Match when={page() === 'lobby'}><Join/></Match>
<Match when={page() === 'clientMonitor'}><ClientMonitor /></Match>
<Match when={page() === 'videoCall'}><VideoCall /></Match>
<Match when={page() === 'exit'}><Results /></Match>
<Match when={page() === 'observer'}><ObserverView /></Match>
</Switch>
</Transition>
</Grid>
<Grid item xs={12}>
<PoweredByCmp />
<Grid item xs={3}>
<Show when={clientStore.call} fallback={<Join />}>
<VideoCall />
</Show>
</Grid>
{/* <Grid item xs={12}>
<PoweredByCmp />
</Grid> */}
</Grid>


Expand Down
Loading

0 comments on commit bb8e5c4

Please sign in to comment.