Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: clean up unknowns #478

Open
wants to merge 3 commits into
base: v1-migration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 4 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"swc-loader": "0.1.15",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
"typescript": "5.5.4",
"typescript": "^5.6.3",
"underscore": "^1.13.1",
"vite": "^5.2.10",
"vite-plugin-dts": "~3.8.1",
Expand Down
6 changes: 5 additions & 1 deletion packages/millicast-sdk/src/Director.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,11 @@ const parseIncomingDirectorResponse = (directorResponse: { data: DirectorRespons
if (Director.getLiveDomain()) {
const domainRegex = /\/\/(.*?)\//
const urlsParsed = directorResponse.data.urls.map((url) => {
const matched = domainRegex.exec(url) as RegExpExecArray
const matched = domainRegex.exec(url)
if (!matched) {
logger.warn('Unable to parse incoming director response')
return url
}
return url.replace(matched[1], Director.getLiveDomain())
})
directorResponse.data.urls = urlsParsed
Expand Down
16 changes: 9 additions & 7 deletions packages/millicast-sdk/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,14 @@ const Logger = {
*
* // Output: Diagnostics object with specified configuration
*/
diagnose: (config: DiagnosticsOptions = {
statsCount: 60,
historySize: 1000,
minLogLevel: 'TRACE',
statsFormat: 'JSON',
}): DiagnosticsObject | CMCDDiagnostics => {
diagnose: (
config: DiagnosticsOptions = {
statsCount: 60,
historySize: 1000,
minLogLevel: 'TRACE',
statsFormat: 'JSON',
}
): DiagnosticsObject | CMCDDiagnostics => {
let finalConfig
const defaultConfig = {
statsCount: 60,
Expand All @@ -315,7 +317,7 @@ const Logger = {
}
const { statsCount, historySize, minLogLevel, statsFormat } = finalConfig
const result = Diagnostics.get(statsCount, statsFormat)
const history = Logger.getHistory() as string[]
const history = Logger.getHistory()

if (!Number.isInteger(historySize) || historySize <= 0) {
throw new Error('Invalid Argument Exception : historySize must be a positive integer.')
Expand Down
46 changes: 28 additions & 18 deletions packages/millicast-sdk/src/PeerConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import UserAgent from './utils/UserAgent'
import Logger from './Logger'
import { SdpOptions, MillicastCapability, ICodecs, PeerConnectionConfig } from './types/PeerConnection.types'
import { AudioCodec, VideoCodec } from './types/Codecs.types'
import { isAudioCodec, isVideoCodec } from './utils/Codecs'
import { typedKeys } from './utils/ObjectUtils'

const logger = Logger.get('PeerConnection')

Expand Down Expand Up @@ -39,17 +41,17 @@ const localSDPOptions = {
*/
export default class PeerConnection extends EventEmitter {
public mode: 'Publisher' | 'Viewer' | null
public sessionDescription: RTCSessionDescriptionInit | null
public peer: RTCPeerConnection | null
public peerConnectionStats: PeerConnectionStats | null
public transceiverMap: Map<
RTCRtpTransceiver,
(value: RTCRtpTransceiver | PromiseLike<RTCRtpTransceiver>) => void
>
public sessionDescription?: RTCSessionDescriptionInit

constructor() {
super()
this.mode = null
this.sessionDescription = null
this.peer = null
this.peerConnectionStats = null
this.transceiverMap = new Map()
Expand Down Expand Up @@ -293,7 +295,7 @@ export default class PeerConnection extends EventEmitter {
const browserCapabilities = RTCRtpSender.getCapabilities(kind) as MillicastCapability

if (browserCapabilities) {
const codecs: { [key: string]: ICodecs } = {}
const codecs: { [key in VideoCodec | AudioCodec]?: ICodecs } = {}
let regex = new RegExp(`^video/(${Object.values(VideoCodec).join('|')})x?$`, 'i')

if (kind === 'audio') {
Expand All @@ -305,23 +307,25 @@ export default class PeerConnection extends EventEmitter {
}

for (const codec of browserCapabilities.codecs) {
const matches = codec.mimeType.match(regex)
const matches = codec.mimeType?.match(regex)
if (matches) {
const codecName = matches[1].toLowerCase()
codecs[codecName] = { ...codecs[codecName], mimeType: codec.mimeType }
if (codec.scalabilityModes) {
let modes = codecs[codecName].scalabilityModes || []
modes = [...modes, ...codec.scalabilityModes]
codecs[codecName].scalabilityModes = [...new Set(modes)]
}
if (codec.channels) {
codecs[codecName].channels = codec.channels
if (isVideoCodec(codecName) || isAudioCodec(codecName)) {
codecs[codecName] = { ...codecs[codecName], mimeType: codec.mimeType }
if (codec.scalabilityModes) {
let modes = codecs[codecName].scalabilityModes || []
modes = [...modes, ...codec.scalabilityModes]
codecs[codecName].scalabilityModes = [...new Set(modes)]
}
if (codec.channels) {
codecs[codecName].channels = codec.channels
}
}
}
}

browserCapabilities.codecs = Object.keys(codecs).map((key) => {
return { codec: key, ...codecs[key] } as ICodecs
browserCapabilities.codecs = typedKeys(codecs).map((key) => {
return { codec: key, ...codecs[key] }
})
}

Expand All @@ -332,8 +336,13 @@ export default class PeerConnection extends EventEmitter {
* Get sender tracks
* @returns {Array<MediaStreamTrack>} An array with all tracks in sender peer.
*/
getTracks(): (MediaStreamTrack | null)[] {
return this.peer?.getSenders().map((sender: RTCRtpSender) => sender.track) || []
getTracks(): MediaStreamTrack[] {
return (
this.peer
?.getSenders()
.map((sender: RTCRtpSender) => sender.track)
.filter((track) => track !== null) || []
)
}

/**
Expand Down Expand Up @@ -397,7 +406,7 @@ export default class PeerConnection extends EventEmitter {
const isMediaStreamValid = (mediaStream: MediaStream) =>
mediaStream.getAudioTracks().length <= 1 && mediaStream.getVideoTracks().length <= 1

const getValidMediaStream = (mediaStream?: MediaStream | Array<MediaStreamTrack>) => {
const getValidMediaStream = (mediaStream?: MediaStream | Array<MediaStreamTrack> | null) => {
if (!mediaStream) {
return null
}
Expand Down Expand Up @@ -514,10 +523,11 @@ const addMediaStreamToPeer = (peer: RTCPeerConnection, mediaStream: MediaStream,

if (track.kind === 'video') {
initOptions.direction = !options.disableVideo ? 'sendonly' : 'inactive'
const encodings = []
const encodings: RTCRtpEncodingParameters[] = []

if (options.scalabilityMode && new UserAgent().isChrome()) {
logger.debug(`Video track with scalability mode: ${options.scalabilityMode}.`)
// Typescript dom RTCRtpEncodingParameters is not up to date with scaleabilityMode as as of Typescript 5.6.3
encodings.push({ scalabilityMode: options.scalabilityMode } as RTCRtpEncodingParameters)
} else if (options.scalabilityMode) {
logger.warn('SVC is only supported in Google Chrome')
Expand Down
2 changes: 1 addition & 1 deletion packages/millicast-sdk/src/Publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ export default class Publish extends BaseWebRTC {

const publishPromise = this.signaling.publish(localSdp, this.options as SignalingPublishOptions)
const setLocalDescriptionPromise = webRTCPeerInstance.peer?.setLocalDescription(
webRTCPeerInstance.sessionDescription as RTCSessionDescriptionInit
webRTCPeerInstance.sessionDescription
)
promises = await Promise.all([publishPromise, setLocalDescriptionPromise])
let remoteSdp = promises[0]
Expand Down
6 changes: 3 additions & 3 deletions packages/millicast-sdk/src/types/PeerConnection.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { VideoCodec } from './Codecs.types'
import { AudioCodec, VideoCodec } from './Codecs.types'

export interface PeerConnectionConfig extends RTCConfiguration {
/**
Expand Down Expand Up @@ -32,8 +32,8 @@ export interface SdpOptions {
}

export interface ICodecs {
codec?: VideoCodec
mimeType: string
codec?: VideoCodec | AudioCodec
mimeType?: string
scalabilityModes?: Array<string>
channels?: number
}
Expand Down
8 changes: 4 additions & 4 deletions packages/millicast-sdk/src/types/Publish.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { PublishServerEvent } from './BaseWebRTC.types'
import { VideoCodec } from './Codecs.types'
import { PeerConnectionConfig } from './PeerConnection.types'

export type PublishConnectOptions = {
export interface PublishConnectOptions {
/**
* - Source unique id. Only avialable if stream is multisource.
*/
sourceId: string | null
sourceId?: string | null
/**
* - True to modify SDP for support stereo. Otherwise False.
*/
Expand All @@ -27,7 +27,7 @@ export type PublishConnectOptions = {
* - MediaStream to offer in a stream. This object must have
* 1 audio track and 1 video track, or at least one of them. Alternative you can provide both tracks in an array.
*/
mediaStream: MediaStream | (MediaStreamTrack | null)[] | null
mediaStream: MediaStream | Array<MediaStreamTrack> | null
/**
* - Broadcast bandwidth. 0 for unlimited.
*/
Expand Down Expand Up @@ -76,7 +76,7 @@ export type PublishConnectOptions = {
/**
* - Specify which events will be delivered by the server (any of "active" | "inactive" | "viewercount").*
*/
events?: PublishServerEvent
events?: PublishServerEvent[]
/**
* - When multiple ingest streams are provided by the customer, add the ability to specify a priority between all ingest streams. Decimal integer between the range [-2^31, +2^31 - 1]. For more information, visit [our documentation](https://docs.dolby.io/streaming-apis/docs/backup-publishing).
*/
Expand Down
10 changes: 9 additions & 1 deletion packages/millicast-sdk/src/utils/Codecs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-new-wrappers */
/* eslint-disable camelcase */
import { PictureParameterSet, SequenceParameterSet, VUIParameters } from '../types/Codecs.types'
import { AudioCodec, PictureParameterSet, SequenceParameterSet, VUIParameters } from '../types/Codecs.types'
import BitStreamReader from './BitStreamReader'
import { VideoCodec } from '../types/Codecs.types'
import { SEIUserUnregisteredData } from '../types/View.types'
Expand Down Expand Up @@ -705,3 +705,11 @@ export function addH26xSEI(

encodedFrame.data = encodedFrameWithSEI
}

export function isVideoCodec(value: string): value is VideoCodec {
return Object.values(VideoCodec).includes(value as VideoCodec)
}

export function isAudioCodec(value: string): value is AudioCodec {
return Object.values(AudioCodec).includes(value as AudioCodec)
}
4 changes: 4 additions & 0 deletions packages/millicast-sdk/src/utils/ObjectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ export function swapPropertyValues<T1 extends object, T2 extends object, K exten
console.error(`One or both objects do not have the property "${String(key)}"`)
}
}

export function typedKeys<T extends object>(obj: T): Array<keyof T> {
return Object.keys(obj) as Array<keyof T>
}