-
Notifications
You must be signed in to change notification settings - Fork 18
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
feat: add generics to device management #61
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,12 @@ import { VideoContentHint } from '../media/local-video-stream'; | |
|
||
export enum ErrorTypes { | ||
DEVICE_PERMISSION_DENIED = 'DEVICE_PERMISSION_DENIED', | ||
CREATE_CAMERA_STREAM_FAILED = 'CREATE_CAMERA_STREAM_FAILED', | ||
CREATE_MICROPHONE_STREAM_FAILED = 'CREATE_MICROPHONE_STREAM_FAILED', | ||
CREATE_STREAM_FAILED = 'CREATE_CAMERA_STREAM', | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type Constructor<T> = new (...args: any[]) => T; | ||
|
||
/** | ||
* Represents a WCME error, which contains error type and error message. | ||
*/ | ||
|
@@ -54,56 +56,109 @@ export type VideoDeviceConstraints = Pick< | |
* 1. Previous captured video stream from the same device is not stopped. | ||
* 2. Previous createCameraStream() call for the same device is in progress. | ||
* | ||
* @param constructor - Constructor for the local camera stream. | ||
* @param constraints - Video device constraints. | ||
* @returns A LocalCameraStream object or an error. | ||
*/ | ||
export async function createCameraStream( | ||
export async function createCameraStream<T extends LocalCameraStream>( | ||
constructor: Constructor<T>, | ||
constraints?: VideoDeviceConstraints | ||
): Promise<LocalCameraStream> { | ||
): Promise<T> { | ||
let stream: MediaStream; | ||
try { | ||
stream = await media.getUserMedia({ video: { ...constraints } }); | ||
} catch (error) { | ||
throw new WcmeError( | ||
ErrorTypes.CREATE_CAMERA_STREAM_FAILED, | ||
`Failed to create camera stream ${error}` | ||
ErrorTypes.CREATE_STREAM_FAILED, | ||
`Failed to create camera stream: ${error}` | ||
); | ||
} | ||
return new LocalCameraStream(stream); | ||
return new constructor(stream); | ||
} | ||
|
||
/** | ||
* Creates a LocalMicrophoneStream with the given constraints. | ||
* | ||
* @param constructor - Constructor for the local microphone stream. | ||
* @param constraints - Audio device constraints. | ||
* @returns A LocalMicrophoneStream object or an error. | ||
*/ | ||
export async function createMicrophoneStream( | ||
export async function createMicrophoneStream<T extends LocalMicrophoneStream>( | ||
constructor: Constructor<T>, | ||
constraints?: AudioDeviceConstraints | ||
): Promise<LocalMicrophoneStream> { | ||
): Promise<T> { | ||
let stream: MediaStream; | ||
try { | ||
stream = await media.getUserMedia({ audio: { ...constraints } }); | ||
} catch (error) { | ||
throw new WcmeError( | ||
ErrorTypes.CREATE_MICROPHONE_STREAM_FAILED, | ||
`Failed to create microphone stream ${error}` | ||
ErrorTypes.CREATE_STREAM_FAILED, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not now but would be nicer to have error codes associated later , so that we know what the cause of failure else anyone using this lib need to figureout what does all getuser media error corresponds to |
||
`Failed to create microphone stream: ${error}` | ||
); | ||
} | ||
return new constructor(stream); | ||
} | ||
|
||
/** | ||
* Creates a LocalCameraStream and a LocalMicrophoneStream with the given constraints. | ||
* | ||
* @param cameraStreamConstructor - Constructor for the local camera stream. | ||
* @param microphoneStreamConstructor - Constructor for the local microphone stream. | ||
* @param constraints - Object containing video and audio device constraints. | ||
* @param constraints.video - Video device constraints. | ||
* @param constraints.audio - Audio device constraints. | ||
* @returns A Promise that resolves to a LocalCameraStream and a LocalMicrophoneStream or an error. | ||
*/ | ||
export async function createCameraAndMicrophoneStreams< | ||
T extends LocalCameraStream, | ||
U extends LocalMicrophoneStream | ||
>( | ||
cameraStreamConstructor: Constructor<T>, | ||
microphoneStreamConstructor: Constructor<U>, | ||
constraints?: { video?: VideoDeviceConstraints; audio?: AudioDeviceConstraints } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice |
||
): Promise<[T, U]> { | ||
let stream; | ||
try { | ||
stream = await media.getUserMedia({ | ||
video: { ...constraints?.video }, | ||
audio: { ...constraints?.audio }, | ||
}); | ||
} catch (error) { | ||
throw new WcmeError( | ||
ErrorTypes.CREATE_STREAM_FAILED, | ||
`Failed to create camera and microphone streams: ${error}` | ||
); | ||
} | ||
return new LocalMicrophoneStream(stream); | ||
// eslint-disable-next-line new-cap | ||
const localCameraStream = new cameraStreamConstructor(new MediaStream(stream.getVideoTracks())); | ||
// eslint-disable-next-line new-cap | ||
const localMicrophoneStream = new microphoneStreamConstructor( | ||
new MediaStream(stream.getAudioTracks()) | ||
); | ||
return [localCameraStream, localMicrophoneStream]; | ||
} | ||
|
||
/** | ||
* Creates a LocalDisplayStream with the given parameters. | ||
* | ||
* @param constructor - Constructor for the local display stream. | ||
* @param videoContentHint - An optional parameter to give a hint for the content of the stream. | ||
* @returns A Promise that resolves to a LocalDisplayStream. | ||
* @returns A Promise that resolves to a LocalDisplayStream or an error. | ||
*/ | ||
export async function createDisplayStream( | ||
export async function createDisplayStream<T extends LocalDisplayStream>( | ||
constructor: Constructor<T>, | ||
videoContentHint?: VideoContentHint | ||
): Promise<LocalDisplayStream> { | ||
const stream = await media.getDisplayMedia({ video: true }); | ||
const localDisplayStream = new LocalDisplayStream(stream); | ||
): Promise<T> { | ||
let stream; | ||
try { | ||
stream = await media.getDisplayMedia({ video: true }); | ||
} catch (error) { | ||
throw new WcmeError( | ||
ErrorTypes.CREATE_STREAM_FAILED, | ||
`Failed to create display stream: ${error}` | ||
); | ||
} | ||
const localDisplayStream = new constructor(stream); | ||
if (videoContentHint) { | ||
localDisplayStream.contentHint = videoContentHint; | ||
} | ||
|
@@ -113,21 +168,41 @@ export async function createDisplayStream( | |
/** | ||
* Creates a LocalDisplayStream and a LocalSystemAudioStream with the given parameters. | ||
* | ||
* @param displayStreamConstructor - Constructor for the local display stream. | ||
* @param systemAudioStreamConstructor - Constructor for the local system audio stream. | ||
* @param videoContentHint - An optional parameter to give a hint for the content of the stream. | ||
* @returns A Promise that resolves to a LocalDisplayStream and a LocalSystemAudioStream. If no system | ||
* audio is available, the LocalSystemAudioStream will be resolved as null instead. | ||
* @returns A Promise that resolves to a LocalDisplayStream and a LocalSystemAudioStream or an | ||
* error. If no system audio is available, the LocalSystemAudioStream will be resolved as null | ||
* instead. | ||
*/ | ||
export async function createDisplayStreamWithAudio( | ||
export async function createDisplayStreamWithAudio< | ||
T extends LocalDisplayStream, | ||
U extends LocalSystemAudioStream | ||
>( | ||
displayStreamConstructor: Constructor<T>, | ||
systemAudioStreamConstructor: Constructor<U>, | ||
videoContentHint?: VideoContentHint | ||
): Promise<[LocalDisplayStream, LocalSystemAudioStream | null]> { | ||
const stream = await media.getDisplayMedia({ video: true, audio: true }); | ||
const localDisplayStream = new LocalDisplayStream(new MediaStream(stream.getVideoTracks())); | ||
): Promise<[T, U | null]> { | ||
let stream; | ||
try { | ||
stream = await media.getDisplayMedia({ video: true, audio: true }); | ||
} catch (error) { | ||
throw new WcmeError( | ||
ErrorTypes.CREATE_STREAM_FAILED, | ||
`Failed to create display and system audio streams: ${error}` | ||
); | ||
} | ||
// eslint-disable-next-line new-cap | ||
const localDisplayStream = new displayStreamConstructor(new MediaStream(stream.getVideoTracks())); | ||
if (videoContentHint) { | ||
localDisplayStream.contentHint = videoContentHint; | ||
} | ||
let localSystemAudioStream = null; | ||
if (stream.getAudioTracks().length > 0) { | ||
localSystemAudioStream = new LocalSystemAudioStream(new MediaStream(stream.getAudioTracks())); | ||
// eslint-disable-next-line new-cap | ||
localSystemAudioStream = new systemAudioStreamConstructor( | ||
new MediaStream(stream.getAudioTracks()) | ||
); | ||
} | ||
return [localDisplayStream, localSystemAudioStream]; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do this in a later PR, but I think it's kind of weird that we're referencing WCME here, and naming the error class
WcmeError
, especially since WCME doesn't actually call any of the device management APIs.