UNPKG

livekit-client

Version:

JavaScript/TypeScript client SDK for LiveKit

184 lines (183 loc) 8.11 kB
import type TypedEventEmitter from 'typed-emitter'; import type { VideoCodec } from '../../room/track/options'; import { CryptorCallbacks } from '../events'; import type { KeyProviderOptions } from '../types'; import type { ParticipantKeyHandler } from './ParticipantKeyHandler'; export declare const encryptionEnabledMap: Map<string, boolean>; export interface FrameCryptorConstructor { new (opts?: unknown): BaseFrameCryptor; } export interface TransformerInfo { readable: ReadableStream; writable: WritableStream; transformer: TransformStream; abortController: AbortController; } declare const BaseFrameCryptor_base: new () => TypedEventEmitter<CryptorCallbacks>; export declare class BaseFrameCryptor extends BaseFrameCryptor_base { protected encodeFunction(encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame, controller: TransformStreamDefaultController): Promise<any>; protected decodeFunction(encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame, controller: TransformStreamDefaultController): Promise<any>; } /** * Cryptor is responsible for en-/decrypting media frames. * Each Cryptor instance is responsible for en-/decrypting a single mediaStreamTrack. */ export declare class FrameCryptor extends BaseFrameCryptor { private sendCounts; private participantIdentity; private trackId; private keys; private videoCodec?; private rtpMap; private keyProviderOptions; /** * used for detecting server injected unencrypted frames */ private sifTrailer; private sifGuard; private detectedCodec?; constructor(opts: { keys: ParticipantKeyHandler; participantIdentity: string; keyProviderOptions: KeyProviderOptions; sifTrailer?: Uint8Array; }); private get logContext(); /** * Assign a different participant to the cryptor. * useful for transceiver re-use * @param id * @param keys */ setParticipant(id: string, keys: ParticipantKeyHandler): void; unsetParticipant(): void; isEnabled(): boolean | undefined; getParticipantIdentity(): string | undefined; getTrackId(): string | undefined; /** * Update the video codec used by the mediaStreamTrack * @param codec */ setVideoCodec(codec: VideoCodec): void; /** * rtp payload type map used for figuring out codec of payload type when encoding * @param map */ setRtpMap(map: Map<number, VideoCodec>): void; setupTransform(operation: 'encode' | 'decode', readable: ReadableStream, writable: WritableStream, trackId: string, codec?: VideoCodec): void; setSifTrailer(trailer: Uint8Array): void; /** * Function that will be injected in a stream and will encrypt the given encoded frames. * * @param {RTCEncodedVideoFrame|RTCEncodedAudioFrame} encodedFrame - Encoded video frame. * @param {TransformStreamDefaultController} controller - TransportStreamController. * * The VP8 payload descriptor described in * https://tools.ietf.org/html/rfc7741#section-4.2 * is part of the RTP packet and not part of the frame and is not controllable by us. * This is fine as the SFU keeps having access to it for routing. * * The encrypted frame is formed as follows: * 1) Find unencrypted byte length, depending on the codec, frame type and kind. * 2) Form the GCM IV for the frame as described above. * 3) Encrypt the rest of the frame using AES-GCM. * 4) Allocate space for the encrypted frame. * 5) Copy the unencrypted bytes to the start of the encrypted frame. * 6) Append the ciphertext to the encrypted frame. * 7) Append the IV. * 8) Append a single byte for the key identifier. * 9) Enqueue the encrypted frame for sending. */ protected encodeFunction(encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame, controller: TransformStreamDefaultController): Promise<void>; /** * Function that will be injected in a stream and will decrypt the given encoded frames. * * @param {RTCEncodedVideoFrame|RTCEncodedAudioFrame} encodedFrame - Encoded video frame. * @param {TransformStreamDefaultController} controller - TransportStreamController. */ protected decodeFunction(encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame, controller: TransformStreamDefaultController): Promise<void>; /** * Function that will decrypt the given encoded frame. If the decryption fails, it will * ratchet the key for up to RATCHET_WINDOW_SIZE times. */ private decryptFrame; /** * Construct the IV used for AES-GCM and sent (in plain) with the packet similar to * https://tools.ietf.org/html/rfc7714#section-8.1 * It concatenates * - the 32 bit synchronization source (SSRC) given on the encoded frame, * - the 32 bit rtp timestamp given on the encoded frame, * - a send counter that is specific to the SSRC. Starts at a random number. * The send counter is essentially the pictureId but we currently have to implement this ourselves. * There is no XOR with a salt. Note that this IV leaks the SSRC to the receiver but since this is * randomly generated and SFUs may not rewrite this is considered acceptable. * The SSRC is used to allow demultiplexing multiple streams with the same key, as described in * https://tools.ietf.org/html/rfc3711#section-4.1.1 * The RTP timestamp is 32 bits and advances by the codec clock rate (90khz for video, 48khz for * opus audio) every second. For video it rolls over roughly every 13 hours. * The send counter will advance at the frame rate (30fps for video, 50fps for 20ms opus audio) * every second. It will take a long time to roll over. * * See also https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams */ private makeIV; private getUnencryptedBytes; /** * inspects frame payloadtype if available and maps it to the codec specified in rtpMap */ private getVideoCodec; } /** * Slice the NALUs present in the supplied buffer, assuming it is already byte-aligned * code adapted from https://github.com/medooze/h264-frame-parser/blob/main/lib/NalUnits.ts to return indices only */ export declare function findNALUIndices(stream: Uint8Array): number[]; export declare function parseNALUType(startByte: number): NALUType; export declare enum NALUType { /** Coded slice of a non-IDR picture */ SLICE_NON_IDR = 1, /** Coded slice data partition A */ SLICE_PARTITION_A = 2, /** Coded slice data partition B */ SLICE_PARTITION_B = 3, /** Coded slice data partition C */ SLICE_PARTITION_C = 4, /** Coded slice of an IDR picture */ SLICE_IDR = 5, /** Supplemental enhancement information */ SEI = 6, /** Sequence parameter set */ SPS = 7, /** Picture parameter set */ PPS = 8, /** Access unit delimiter */ AUD = 9, /** End of sequence */ END_SEQ = 10, /** End of stream */ END_STREAM = 11, /** Filler data */ FILLER_DATA = 12, /** Sequence parameter set extension */ SPS_EXT = 13, /** Prefix NAL unit */ PREFIX_NALU = 14, /** Subset sequence parameter set */ SUBSET_SPS = 15, /** Depth parameter set */ DPS = 16, /** Coded slice of an auxiliary coded picture without partitioning */ SLICE_AUX = 19, /** Coded slice extension */ SLICE_EXT = 20, /** Coded slice extension for a depth view component or a 3D-AVC texture view component */ SLICE_LAYER_EXT = 21 } /** * we use a magic frame trailer to detect whether a frame is injected * by the livekit server and thus to be treated as unencrypted * @internal */ export declare function isFrameServerInjected(frameData: ArrayBuffer, trailerBytes: Uint8Array): boolean; export {}; //# sourceMappingURL=FrameCryptor.d.ts.map