diff --git a/.env.dev b/.env.dev index aa983e2..610f977 100644 --- a/.env.dev +++ b/.env.dev @@ -67,6 +67,6 @@ MEDIASOUP_WEBRTC_TRANSPORT_INITIAL_AVAILABLE_OUTGOING_BITRATE = 1000000 MEDIASOUP_WEBRTC_TRANSPORT_LISTEN_IPS = '[ { "ip": "192.168.6.143", - "announcedIp": null, + "announcedIp": null } ]' diff --git a/src/apis/master/room.ts b/src/apis/master/room.ts index 2dc0e5c..f5ca6da 100644 --- a/src/apis/master/room.ts +++ b/src/apis/master/room.ts @@ -1,4 +1,4 @@ -import { RoomService } from '../../services/index.js'; +import { PeerService, RoomService } from '../../services/index.js'; import { RouteConfig, getDataSource } from '../../utils/index.js'; export const room: Array = [ @@ -9,4 +9,11 @@ export const room: Array = [ return new RoomService(getDataSource()).create({}); }, }, + { + method: 'POST', + url: '/rooms/:roomId/producer_peers', + handler: (data) => { + return new PeerService(getDataSource()).createProducer(data); + }, + }, ]; diff --git a/src/apis/slave/router.ts b/src/apis/slave/router.ts index 9301f7b..cec7f9a 100644 --- a/src/apis/slave/router.ts +++ b/src/apis/slave/router.ts @@ -14,9 +14,9 @@ export const router: Array = [ }, { method: 'POST', - url: '/routers/:routerId/transports', + url: '/routers/:routerId/producer_transports', handler: (data) => { - return mediasoupWebRTCTransportManager.create(data.routerId); + return mediasoupWebRTCTransportManager.createProducer(data.routerId); }, }, ]; diff --git a/src/entities/media.peer.ts b/src/entities/media.peer.ts index a611258..1380b50 100644 --- a/src/entities/media.peer.ts +++ b/src/entities/media.peer.ts @@ -31,6 +31,9 @@ export class MediaPeer extends BaseEntity { @Column('text') routerId!: string; + @Column('text') + type!: string; // consumer | producer + @Column({ type: 'jsonb', nullable: true }) metadata?: any; diff --git a/src/services/index.ts b/src/services/index.ts index c0272eb..2315599 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,3 +1,4 @@ export * from './slave.js'; export * from './room.js'; +export * from './peer.js'; export * from './mediasoup/index.js'; diff --git a/src/services/mediasoup/webrtc.transport.ts b/src/services/mediasoup/webrtc.transport.ts index 50632df..4238179 100644 --- a/src/services/mediasoup/webrtc.transport.ts +++ b/src/services/mediasoup/webrtc.transport.ts @@ -5,7 +5,7 @@ import { mediasoupRouterManager } from './router.js'; class MediasoupWebRTCTransportManager { static transports: Array = []; - async create(routerId: string) { + async createProducer(routerId: string) { const router = mediasoupRouterManager.get(routerId); if (router) { const maxIncomingBitrate = Number( diff --git a/src/services/peer.ts b/src/services/peer.ts new file mode 100644 index 0000000..391ad24 --- /dev/null +++ b/src/services/peer.ts @@ -0,0 +1,30 @@ +import { constants } from '../constants.js'; +import { MediaPeer } from '../entities/index.js'; +import { fetchApi } from '../utils/api.js'; +import { BaseService, ServiceError } from './base.js'; +import { RoomService } from './room.js'; + +export class PeerService extends BaseService { + async createProducer(data: { roomId: string; metadata?: any }) { + const room = await this.createService(RoomService).get({ id: data.roomId }); + if (room) { + const result = await fetchApi({ + host: room.slave.externalHost, + port: room.slave.apiPort, + path: '/routers/:routerId/producer_transports', + method: 'POST', + data: { routerId: room.routerId }, + }); + const mediaPeer = new MediaPeer(); + mediaPeer.id = result.id; + mediaPeer.routerId = room.routerId; + mediaPeer.slaveId = room.slave.id; + mediaPeer.type = constants.PRODUCER; + mediaPeer.roomId = room.id; + + await this.dataSource.getRepository(MediaPeer).save(mediaPeer); + return result; + } + throw new ServiceError(404, 'Room not found'); + } +} diff --git a/src/services/room.ts b/src/services/room.ts index e446efa..22ad84f 100644 --- a/src/services/room.ts +++ b/src/services/room.ts @@ -14,19 +14,20 @@ export class RoomService extends BaseService { path: '/routers', method: 'POST', }); - const mediasoupRoom = new MediaRoom(); - mediasoupRoom.routerId = result.id; - mediasoupRoom.slaveId = slave.id; - Object.assign(mediasoupRoom, data); - await this.dataSource.getRepository(MediaRoom).save(mediasoupRoom); - return mediasoupRoom.id; + const mediaRoom = new MediaRoom(); + mediaRoom.routerId = result.id; + mediaRoom.slaveId = slave.id; + Object.assign(mediaRoom, data); + await this.dataSource.getRepository(MediaRoom).save(mediaRoom); + return { id: mediaRoom.id }; } throw new ServiceError(404, 'Slave not found'); } async get(data: { id: string }) { - return this.dataSource - .getRepository(MediaRoom) - .findOne({ where: { id: data.id } }); + return this.dataSource.getRepository(MediaRoom).findOne({ + relations: { slave: true }, + where: { id: data.id }, + }); } } diff --git a/src/utils/api.ts b/src/utils/api.ts index 3e5a8b2..11ddc5d 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -1,16 +1,46 @@ +function generatePath(urlPattern: string, params: Record) { + const retParams = { ...params }; + const parts = urlPattern.split('/'); + const result = [] as string[]; + for (let i = 0; i < parts.length; i += 1) { + if (parts[i].startsWith(':')) { + const key = parts[i].slice(1); + result.push(encodeURIComponent(params[key])); + delete retParams[key]; + } else { + result.push(parts[i]); + } + } + return { + path: result.join('/'), + params: retParams, + }; +} + export function fetchApi({ host, port, path, method, + data, }: { host: string; port?: string | number; path: string; method: 'POST' | 'GET' | 'PUT' | 'DELETE'; + data?: Record; }) { - return fetch('http://' + host + (port ? ':' + port : '') + path, { + const parsed = generatePath(path, data || {}); + let body; + if (method === 'GET') { + parsed.path += '?' + new URLSearchParams(parsed.params); + } else { + body = JSON.stringify(parsed.params); + } + return fetch('http://' + host + (port ? ':' + port : '') + parsed.path, { + headers: { 'Content-Type': 'application/json' }, method, + body, }).then(async (resp) => { if (resp.status > 400) { const message = await resp.text();