import { NativeModules } from 'react-native'; import { MediaTrackConstraints } from './Constraints'; import MediaStream from './MediaStream'; import MediaStreamError from './MediaStreamError'; import permissions from './Permissions'; import * as RTCUtil from './RTCUtil'; const { WebRTCModule } = NativeModules; export interface Constraints { audio?: boolean | MediaTrackConstraints; video?: boolean | MediaTrackConstraints; } export default function getUserMedia(constraints: Constraints = {}): Promise { // According to // https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-getusermedia, // the constraints argument is a dictionary of type MediaStreamConstraints. if (typeof constraints !== 'object') { return Promise.reject(new TypeError('constraints is not a dictionary')); } if ( (typeof constraints.audio === 'undefined' || !constraints.audio) && (typeof constraints.video === 'undefined' || !constraints.video) ) { return Promise.reject(new TypeError('audio and/or video is required')); } console.log('[RNWebRTC] get_user_media_start', { audio: !!constraints.audio, video: !!constraints.video, }); // Normalize constraints. constraints = RTCUtil.normalizeConstraints(constraints); // Request required permissions const reqPermissions: Promise[] = []; if (constraints.audio) { console.log('[RNWebRTC] requesting_mic_permission'); reqPermissions.push(permissions.request({ name: 'microphone' })); } else { reqPermissions.push(Promise.resolve(false)); } if (constraints.video) { console.log('[RNWebRTC] requesting_camera_permission'); reqPermissions.push(permissions.request({ name: 'camera' })); } else { reqPermissions.push(Promise.resolve(false)); } const _t0 = Date.now(); return new Promise((resolve, reject) => { Promise.all(reqPermissions).then(results => { const [ audioPerm, videoPerm ] = results; console.log('[RNWebRTC] permission_results', { audioPerm, videoPerm }); // Check permission results and remove unneeded permissions. if (!audioPerm && !videoPerm) { // https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-getusermedia // step 4 console.log('[RNWebRTC] permission_denied_both'); const error = { message: 'Permission denied.', name: 'SecurityError' }; reject(new MediaStreamError(error)); return; } audioPerm || delete constraints.audio; videoPerm || delete constraints.video; const success = (id, tracks) => { // Store initial constraints. for (const trackInfo of tracks) { const c = constraints[trackInfo.kind]; if (typeof c === 'object') { trackInfo.constraints = RTCUtil.deepClone(c); } } console.log('[RNWebRTC] get_user_media_success', { durationMs: Date.now() - _t0, streamId: id, trackCount: tracks.length, trackKinds: tracks.map(t => t.kind), }); const info = { streamId: id, streamReactTag: id, tracks }; resolve(new MediaStream(info)); }; const failure = (type, message) => { console.log('[RNWebRTC] get_user_media_error', { durationMs: Date.now() - _t0, type, message, }); let error; switch (type) { case 'TypeError': error = new TypeError(message); break; } if (!error) { error = new MediaStreamError({ message, name: type }); } reject(error); }; WebRTCModule.getUserMedia(constraints, success, failure); }); }); }