Skip to content

Commit

Permalink
chore: [#1332] Continues on implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 committed Apr 8, 2024
1 parent 0af09bd commit 5f29bdd
Show file tree
Hide file tree
Showing 12 changed files with 550 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ export default class CanvasCaptureMediaStreamTrack extends MediaStreamTrack {
public canvas: HTMLCanvasElement;

/**
* Constructor.
*
* @param canvas
* @param frameRate
* @param options Options.
* @param options.kind 'audio' or 'video'.
* @param options.canvas Canvas.
*/
constructor(canvas: HTMLCanvasElement) {
super();
this.canvas = canvas;
constructor(options: { kind: 'audio' | 'video'; canvas: HTMLCanvasElement }) {
super(options);
this.canvas = options.canvas;
}

/**
Expand All @@ -31,7 +33,7 @@ export default class CanvasCaptureMediaStreamTrack extends MediaStreamTrack {
*
* @returns Clone.
*/
public clone(): MediaStreamTrack {
public clone(): CanvasCaptureMediaStreamTrack {
const clone = <CanvasCaptureMediaStreamTrack>super.clone();
clone.canvas = this.canvas;
return clone;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Blob from '../../file/Blob.js';
import OffscreenCanvas from './OffscreenCanvas.js';
import Event from '../../event/Event.js';

const DEVICE_ID = 'S3F/aBCdEfGHIjKlMnOpQRStUvWxYz1234567890+1AbC2DEf2GHi3jK34le+ab12C3+1aBCdEf==';

/**
* HTMLCanvasElement
*
Expand Down Expand Up @@ -60,15 +62,29 @@ export default class HTMLCanvasElement extends HTMLElement {
/**
* Returns capture stream.
*
* @param [_frameRate] Frame rate.
* @param [frameRate] Frame rate.
* @returns Capture stream.
*/
public captureStream(_frameRate?: number): MediaStream {
public captureStream(frameRate?: number): MediaStream {
const stream = new MediaStream();
stream.addTrack(new CanvasCaptureMediaStreamTrack(this));
stream[PropertySymbol.capabilities].aspectRatio.max = this.width;
stream[PropertySymbol.capabilities].height.max = this.height;
stream[PropertySymbol.capabilities].width.max = this.width;
const track = new CanvasCaptureMediaStreamTrack({
kind: 'video',
canvas: this
});

track[PropertySymbol.capabilities].deviceId = DEVICE_ID;
track[PropertySymbol.capabilities].aspectRatio.max = this.width;
track[PropertySymbol.capabilities].height.max = this.height;
track[PropertySymbol.capabilities].width.max = this.width;
track[PropertySymbol.settings].deviceId = DEVICE_ID;

if (frameRate !== undefined) {
track[PropertySymbol.capabilities].frameRate.max = frameRate;
track[PropertySymbol.settings].frameRate = frameRate;
}

stream.addTrack(track);

return stream;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/**
* Image Bitmap.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap
*/
export default class ImageBitmap {
public height: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import * as PropertySymbol from '../../PropertySymbol.js';
import Crypto from 'crypto';
import IMediaTrackCapabilities from './IMediaTrackCapabilities.js';
import IMediaTrackSettings from './IMediaTrackSettings.js';

const DEVICE_ID = 'S3F/aBCdEfGHIjKlMnOpQRStUvWxYz1234567890+1AbC2DEf2GHi3jK34le+ab12C3+1aBCdEf==';
const CAPABILITIES: IMediaTrackCapabilities = {
aspectRatio: {
max: 300,
min: 0.006666666666666667
},
deviceId: DEVICE_ID,
deviceId: '',
facingMode: [],
frameRate: {
max: 60,
Expand All @@ -28,7 +26,7 @@ const CAPABILITIES: IMediaTrackCapabilities = {
}
};
const SETTINGS: IMediaTrackSettings = {
deviceId: DEVICE_ID,
deviceId: '',
frameRate: 60,
resizeMode: 'none'
};
Expand All @@ -48,11 +46,11 @@ export default class MediaStreamTrack extends EventTarget {
| 'detail'
| 'text' = '';
public enabled = true;
public id: string = Crypto.randomUUID();
public kind: 'audio' | 'video' = 'video';
public label: string = DEVICE_ID;
public readonly id: string = Crypto.randomUUID();
public readonly kind: 'audio' | 'video' = 'video';
public muted = false;
public readyState: 'live' | 'ended' = 'live';
public label: string = '';
public [PropertySymbol.constraints]: object = {};
public [PropertySymbol.capabilities]: IMediaTrackCapabilities = JSON.parse(
JSON.stringify(CAPABILITIES)
Expand All @@ -65,22 +63,24 @@ export default class MediaStreamTrack extends EventTarget {
public onunmute: (event: Event) => void | null = null;

/**
* Applies constraints.
* Constructor.
*
* @param _constraints Constraints.
* @param constraints
* @param options Options.
* @param options.kind 'audio' or 'video'.
*/
public async applyConstraints(constraints: object): Promise<void> {
Object.apply(this[PropertySymbol.constraints], constraints);
constructor(options: { kind: 'audio' | 'video' }) {
super();
this.kind = options.kind;
}

/**
* Returns capabilities.
* Applies constraints.
*
* @returns Capabilities.
* @param _constraints Constraints.
* @param constraints
*/
public getCapabilities(): IMediaTrackCapabilities {
return this[PropertySymbol.capabilities];
public async applyConstraints(constraints: object): Promise<void> {
this.#mergeObjects(this[PropertySymbol.constraints], constraints);
}

/**
Expand All @@ -92,6 +92,15 @@ export default class MediaStreamTrack extends EventTarget {
return this[PropertySymbol.constraints];
}

/**
* Returns capabilities.
*
* @returns Capabilities.
*/
public getCapabilities(): IMediaTrackCapabilities {
return this[PropertySymbol.capabilities];
}

/**
* Returns settings.
*
Expand All @@ -107,11 +116,12 @@ export default class MediaStreamTrack extends EventTarget {
* @returns Clone.
*/
public clone(): MediaStreamTrack {
const clone = new (<typeof MediaStreamTrack>this.constructor)();
const clone = new (<typeof MediaStreamTrack>this.constructor)({ kind: this.kind });
clone[PropertySymbol.constraints] = this[PropertySymbol.constraints];
clone[PropertySymbol.capabilities] = this[PropertySymbol.capabilities];
clone[PropertySymbol.settings] = this[PropertySymbol.settings];
clone.contentHint = this.contentHint;
clone.enabled = this.enabled;
clone.id = this.id;
clone.kind = this.kind;
clone.label = this.label;
clone.muted = this.muted;
clone.readyState = this.readyState;
Expand All @@ -124,4 +134,23 @@ export default class MediaStreamTrack extends EventTarget {
public stop(): void {
this.readyState = 'ended';
}

/**
* Merges two objects.
*
* @param source Target.
* @param target Source.
*/
#mergeObjects(source: object, target: object): void {
for (const key in target) {
if (target[key] !== null && typeof target[key] === 'object' && !Array.isArray(target[key])) {
if (typeof source[key] !== 'object') {
source[key] = {};
}
this.#mergeObjects(source[key], target[key]);
} else {
source[key] = target[key];
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import ImageBitmap from './ImageBitmap.js';
* @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas/OffscreenCanvas
*/
export default class OffscreenCanvas {
public width: number;
public height: number;
public readonly width: number;
public readonly height: number;

/**
* Constructor.
Expand Down Expand Up @@ -43,8 +43,8 @@ export default class OffscreenCanvas {
* @param [_options.quality] Quality.
* @returns Blob.
*/
public convertToBlob(_options?: { type?: string; quality?: any }): Promise<Blob> {
return Promise.resolve(new Blob([]));
public async convertToBlob(_options?: { type?: string; quality?: any }): Promise<Blob> {
return new Blob([]);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import HTMLCanvasElement from '../../../src/nodes/html-canvas-element/HTMLCanvasElement.js';
import Window from '../../../src/window/Window.js';
import Document from '../../../src/nodes/document/Document.js';
import { beforeEach, describe, it, expect } from 'vitest';
import CanvasCaptureMediaStreamTrack from '../../../src/nodes/html-canvas-element/CanvasCaptureMediaStreamTrack.js';

describe('CanvasCaptureMediaStreamTrack', () => {
let window: Window;
let document: Document;
let canvas: HTMLCanvasElement;

beforeEach(() => {
window = new Window();
document = window.document;
canvas = document.createElement('canvas');
});

describe('get canvas()', () => {
it('Returns the canvas.', () => {
const track = new CanvasCaptureMediaStreamTrack({ kind: 'video', canvas });
expect(track.canvas).toBe(canvas);
});
});

describe('requestFrame()', () => {
it('Does nothing.', () => {
const track = new CanvasCaptureMediaStreamTrack({ kind: 'video', canvas });
expect(() => track.requestFrame()).not.toThrow();
});
});

describe('clone()', () => {
it('Clones the track.', () => {
const track = new CanvasCaptureMediaStreamTrack({ kind: 'video', canvas });
const clone = track.clone();

// MediaStreamTrack
expect(clone).not.toBe(track);
expect(clone.id).not.toBe(track.id);
expect(clone.label).toBe(track.label);
expect(clone.kind).toBe(track.kind);
expect(clone.muted).toBe(track.muted);
expect(clone.readyState).toBe(track.readyState);
expect(clone.getCapabilities()).toEqual(track.getCapabilities());
expect(clone.getSettings()).toEqual(track.getSettings());

// CanvasCaptureMediaStreamTrack
expect(clone.canvas).toBe(track.canvas);
});
});
});

0 comments on commit 5f29bdd

Please sign in to comment.