@techsee/techsee-media-service 999.7.0-gal.alpha9 → 999.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/lib/LocalStreamManager.d.ts +1 -19
  2. package/lib/LocalStreamManager.d.ts.map +1 -1
  3. package/lib/LocalStreamManager.js +239 -444
  4. package/lib/LocalStreamManager.js.map +1 -1
  5. package/lib/MediaConstants.d.ts +1 -12
  6. package/lib/MediaConstants.d.ts.map +1 -1
  7. package/lib/MediaConstants.js +35 -79
  8. package/lib/MediaConstants.js.map +1 -1
  9. package/lib/MediaContracts.d.ts +14 -19
  10. package/lib/MediaContracts.d.ts.map +1 -1
  11. package/lib/MediaContracts.js +3 -3
  12. package/lib/MediaContracts.js.map +1 -1
  13. package/lib/MediaPublisher.d.ts +3 -3
  14. package/lib/MediaPublisher.d.ts.map +1 -1
  15. package/lib/MediaPublisher.js +35 -46
  16. package/lib/MediaPublisher.js.map +1 -1
  17. package/lib/MediaServiceBase.d.ts +7 -21
  18. package/lib/MediaServiceBase.d.ts.map +1 -1
  19. package/lib/MediaServiceBase.js +577 -924
  20. package/lib/MediaServiceBase.js.map +1 -1
  21. package/lib/MediaSession/MediaSessionBase.d.ts +1 -10
  22. package/lib/MediaSession/MediaSessionBase.d.ts.map +1 -1
  23. package/lib/MediaSession/MediaSessionBase.js +64 -128
  24. package/lib/MediaSession/MediaSessionBase.js.map +1 -1
  25. package/lib/MediaSession/SessionOpentok.d.ts +9 -11
  26. package/lib/MediaSession/SessionOpentok.d.ts.map +1 -1
  27. package/lib/MediaSession/SessionOpentok.js +352 -500
  28. package/lib/MediaSession/SessionOpentok.js.map +1 -1
  29. package/lib/MediaSession/SessionTurn.d.ts +1 -4
  30. package/lib/MediaSession/SessionTurn.d.ts.map +1 -1
  31. package/lib/MediaSession/SessionTurn.js +417 -611
  32. package/lib/MediaSession/SessionTurn.js.map +1 -1
  33. package/lib/MediaSession/TurnConstants.js +30 -31
  34. package/lib/MediaSession/TurnConstants.js.map +1 -1
  35. package/lib/MediaSubscriber.d.ts +11 -11
  36. package/lib/MediaSubscriber.d.ts.map +1 -1
  37. package/lib/MediaSubscriber.js +192 -236
  38. package/lib/MediaSubscriber.js.map +1 -1
  39. package/lib/MediaUtils/Compatibility.d.ts +1 -2
  40. package/lib/MediaUtils/Compatibility.d.ts.map +1 -1
  41. package/lib/MediaUtils/Compatibility.js +85 -130
  42. package/lib/MediaUtils/Compatibility.js.map +1 -1
  43. package/lib/MediaUtils/MediaDomUtils.d.ts +2 -3
  44. package/lib/MediaUtils/MediaDomUtils.d.ts.map +1 -1
  45. package/lib/MediaUtils/MediaDomUtils.js +174 -235
  46. package/lib/MediaUtils/MediaDomUtils.js.map +1 -1
  47. package/lib/MediaUtils/MediaTracer.js +4 -9
  48. package/lib/MediaUtils/MediaTracer.js.map +1 -1
  49. package/lib/TechseeMediaStream.d.ts +6 -6
  50. package/lib/TechseeMediaStream.d.ts.map +1 -1
  51. package/lib/TechseeMediaStream.js +53 -59
  52. package/lib/TechseeMediaStream.js.map +1 -1
  53. package/lib/oldCode/constants.js +15 -20
  54. package/lib/oldCode/constants.js.map +1 -1
  55. package/lib/oldCode/event-emitter.js +22 -45
  56. package/lib/oldCode/event-emitter.js.map +1 -1
  57. package/lib/oldCode/index.js +52 -48
  58. package/lib/oldCode/index.js.map +1 -1
  59. package/lib/oldCode/opentok/session.js +236 -261
  60. package/lib/oldCode/opentok/session.js.map +1 -1
  61. package/lib/oldCode/opentok/stream.js +269 -283
  62. package/lib/oldCode/opentok/stream.js.map +1 -1
  63. package/lib/oldCode/publisher.js +71 -96
  64. package/lib/oldCode/publisher.js.map +1 -1
  65. package/lib/oldCode/service.js +272 -294
  66. package/lib/oldCode/service.js.map +1 -1
  67. package/lib/oldCode/session.js +60 -82
  68. package/lib/oldCode/session.js.map +1 -1
  69. package/lib/oldCode/stream.js +125 -153
  70. package/lib/oldCode/stream.js.map +1 -1
  71. package/lib/oldCode/subscriber.js +35 -60
  72. package/lib/oldCode/subscriber.js.map +1 -1
  73. package/lib/oldCode/tracer.d.ts +2 -3
  74. package/lib/oldCode/tracer.d.ts.map +1 -1
  75. package/lib/oldCode/tracer.js +130 -181
  76. package/lib/oldCode/tracer.js.map +1 -1
  77. package/lib/oldCode/utils/ImageFixer.js +44 -67
  78. package/lib/oldCode/utils/ImageFixer.js.map +1 -1
  79. package/lib/oldCode/webrtc/constants.js +110 -102
  80. package/lib/oldCode/webrtc/constants.js.map +1 -1
  81. package/lib/oldCode/webrtc/helper.js +124 -176
  82. package/lib/oldCode/webrtc/helper.js.map +1 -1
  83. package/lib/oldCode/webrtc/session-kms.js +393 -408
  84. package/lib/oldCode/webrtc/session-kms.js.map +1 -1
  85. package/lib/oldCode/webrtc/session-loopback.js +227 -245
  86. package/lib/oldCode/webrtc/session-loopback.js.map +1 -1
  87. package/lib/oldCode/webrtc/session-turn.js +658 -705
  88. package/lib/oldCode/webrtc/session-turn.js.map +1 -1
  89. package/lib/oldCode/webrtc/session-turn.v2.js +471 -480
  90. package/lib/oldCode/webrtc/session-turn.v2.js.map +1 -1
  91. package/lib/oldCode/webrtc/session.js +6 -12
  92. package/lib/oldCode/webrtc/session.js.map +1 -1
  93. package/lib/oldCode/webrtc/stream.js +504 -526
  94. package/lib/oldCode/webrtc/stream.js.map +1 -1
  95. package/lib/oldCode/webrtc/temasys/adapter-loader.js +6 -5
  96. package/lib/oldCode/webrtc/temasys/adapter-loader.js.map +1 -1
  97. package/lib/oldCode/webrtc/temasys/adapter.js +5199 -5271
  98. package/lib/oldCode/webrtc/temasys/adapter.js.map +1 -1
  99. package/lib/oldCode/webrtc/webrtc-ie-shim.js +2927 -3357
  100. package/lib/oldCode/webrtc/webrtc-ie-shim.js.map +1 -1
  101. package/lib/qos/raw-qos.js +273 -348
  102. package/lib/qos/raw-qos.js.map +1 -1
  103. package/lib/webrtc-ie-shim.js +2985 -3386
  104. package/lib/webrtc-ie-shim.js.map +1 -1
  105. package/package.json +43 -55
  106. package/lib/MediaSession/MediaServer.d.ts +0 -45
  107. package/lib/MediaSession/MediaServer.d.ts.map +0 -1
  108. package/lib/MediaSession/MediaServer.js +0 -538
  109. package/lib/MediaSession/MediaServer.js.map +0 -1
  110. package/lib/MultiParty/Contracts.d.ts +0 -15
  111. package/lib/MultiParty/Contracts.d.ts.map +0 -1
  112. package/lib/MultiParty/Contracts.js +0 -6
  113. package/lib/MultiParty/Contracts.js.map +0 -1
  114. package/lib/MultiParty/DetectWebRtcService.d.ts +0 -16
  115. package/lib/MultiParty/DetectWebRtcService.d.ts.map +0 -1
  116. package/lib/MultiParty/DetectWebRtcService.js +0 -79
  117. package/lib/MultiParty/DetectWebRtcService.js.map +0 -1
  118. package/lib/MultiParty/MediaCapabilitiesHelper.d.ts +0 -23
  119. package/lib/MultiParty/MediaCapabilitiesHelper.d.ts.map +0 -1
  120. package/lib/MultiParty/MediaCapabilitiesHelper.js +0 -408
  121. package/lib/MultiParty/MediaCapabilitiesHelper.js.map +0 -1
  122. package/lib/MultiParty/MultiParty.d.ts +0 -46
  123. package/lib/MultiParty/MultiParty.d.ts.map +0 -1
  124. package/lib/MultiParty/MultiParty.js +0 -253
  125. package/lib/MultiParty/MultiParty.js.map +0 -1
  126. package/lib/MultiParty/MultipartyFactory.d.ts +0 -4
  127. package/lib/MultiParty/MultipartyFactory.d.ts.map +0 -1
  128. package/lib/MultiParty/MultipartyFactory.js +0 -21
  129. package/lib/MultiParty/MultipartyFactory.js.map +0 -1
  130. package/lib/MultiParty/OpentokMultiparty.d.ts +0 -33
  131. package/lib/MultiParty/OpentokMultiparty.d.ts.map +0 -1
  132. package/lib/MultiParty/OpentokMultiparty.js +0 -885
  133. package/lib/MultiParty/OpentokMultiparty.js.map +0 -1
@@ -1,39 +1,21 @@
1
1
  import { Nullable } from '@techsee/techsee-common';
2
- import { IMediaEnvironment, LocalMediaConstraints, LocalVideoStreamConstraints, MediaRequestSuccessResult } from './MediaContracts';
2
+ import { LocalMediaConstraints, LocalVideoStreamConstraints, MediaRequestSuccessResult, IMediaEnvironment } from './MediaContracts';
3
3
  declare global {
4
4
  interface Window {
5
5
  latestUserMediaStream: Nullable<MediaRequestSuccessResult>;
6
6
  latestDesktopMediaStream: Nullable<MediaRequestSuccessResult>;
7
- latestLocalMediaConstraints: Nullable<LocalMediaConstraints>;
8
- mediaStreamAlreadyReplaced: boolean;
9
7
  }
10
8
  }
11
- interface IGroupedDevices {
12
- video: Nullable<{
13
- back?: MediaDeviceInfo;
14
- front?: MediaDeviceInfo;
15
- }>;
16
- audio: Nullable<MediaDeviceInfo>;
17
- camerasCount: number;
18
- }
19
9
  export declare class LocalStreamManager {
20
10
  private environment;
21
- private _groupedDevices;
22
11
  constructor(environment: IMediaEnvironment);
23
- get groupedDevices(): IGroupedDevices;
24
12
  getUserMediaStream(constraints: LocalMediaConstraints): Promise<MediaRequestSuccessResult>;
25
13
  getDesktopMediaStream(constraints: LocalVideoStreamConstraints): Promise<MediaRequestSuccessResult>;
26
14
  destroyUserMediaStream(): Promise<void>;
27
15
  destroyDesktopMediaStream(): Promise<void>;
28
16
  clearAllStreams(): Promise<void>;
29
17
  private getHighestResolutionStream;
30
- private getUserMediaStreamMediaDevice;
31
18
  private getStreamPromiseByParsedConstraints;
32
- setGroupedDevices(groupedDevices: {
33
- video: MediaDeviceInfo[];
34
- audio: MediaDeviceInfo[];
35
- }): void;
36
19
  private getParsedConstraints;
37
20
  private parseMediaErrorThenThrow;
38
21
  }
39
- export {};
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LocalStreamManager.ts"],"names":[],"mappings":"AAOA,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAEjD,OAAO,EACH,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAE3B,yBAAyB,EAE5B,MAAM,kBAAkB,CAAC;AAY1B,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,qBAAqB,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QAC3D,wBAAwB,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QAC9D,2BAA2B,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;QAC7D,0BAA0B,EAAE,OAAO,CAAC;KACvC;CACJ;AAeD,UAAU,eAAe;IACrB,KAAK,EAAE,QAAQ,CAAC;QAAE,IAAI,CAAC,EAAE,eAAe,CAAC;QAAC,KAAK,CAAC,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IACrE,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,eAAe,CAAgE;gBAE3E,WAAW,EAAE,iBAAiB;IAO1C,IAAI,cAAc,oBAEjB;IAED,kBAAkB,CAAC,WAAW,EAAE,qBAAqB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA2C1F,qBAAqB,CAAC,WAAW,EAAE,2BAA2B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA4CnG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBvC,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB1C,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC,OAAO,CAAC,0BAA0B;IAwDlC,OAAO,CAAC,6BAA6B;IAsBrC,OAAO,CAAC,mCAAmC;IAoD3C,iBAAiB,CAAC,cAAc,EAAE;QAAC,KAAK,EAAE,eAAe,EAAE,CAAC;QAAC,KAAK,EAAE,eAAe,EAAE,CAAA;KAAC;IAStF,OAAO,CAAC,oBAAoB;IAuE5B,OAAO,CAAC,wBAAwB;CAwCnC","file":"LocalStreamManager.d.ts","sourcesContent":["import assign from 'lodash/assign';\nimport get from 'lodash/get';\nimport last from 'lodash/last';\nimport first from 'lodash/first';\nimport cloneDeep from 'lodash/cloneDeep';\nimport {Promise} from 'bluebird';\n\nimport {Nullable} from '@techsee/techsee-common';\n\nimport {\n IMediaEnvironment,\n LocalMediaConstraints,\n LocalVideoStreamConstraints,\n MediaRequestFailResult,\n MediaRequestSuccessResult,\n VideoStreamResolution\n} from './MediaContracts';\n\nimport {\n CameraTypes,\n ConstraintType,\n DEFAULT_VIDEO_CONSTRAINT_TYPE,\n DEFAULT_VIDEO_RESOLUTION,\n LocalVideoSourceType,\n MediaRequestErrorCode\n} from './MediaConstants';\nimport {getMediaTracer} from './MediaUtils/MediaTracer';\n\ndeclare global {\n interface Window {\n latestUserMediaStream: Nullable<MediaRequestSuccessResult>;\n latestDesktopMediaStream: Nullable<MediaRequestSuccessResult>;\n latestLocalMediaConstraints: Nullable<LocalMediaConstraints>;\n mediaStreamAlreadyReplaced: boolean;\n }\n}\n\ndeclare const window: Window;\n\nwindow.latestUserMediaStream = null;\nlet userMediaPromise: Nullable<Promise<MediaRequestSuccessResult>> = null;\n\nwindow.latestDesktopMediaStream = null;\nlet desktopMediaPromise: Nullable<Promise<MediaRequestSuccessResult>> = null;\n\nwindow.mediaStreamAlreadyReplaced = false;\nwindow.latestLocalMediaConstraints = null;\n\nconst trace = getMediaTracer('LocalStreamManager');\n\ninterface IGroupedDevices {\n video: Nullable<{ back?: MediaDeviceInfo; front?: MediaDeviceInfo }>;\n audio: Nullable<MediaDeviceInfo>;\n camerasCount: number;\n}\n\nexport class LocalStreamManager {\n private environment: IMediaEnvironment;\n private _groupedDevices: IGroupedDevices = {video: null, audio: null, camerasCount: 0};\n\n constructor(environment: IMediaEnvironment) {\n this.environment = environment;\n\n this.parseMediaErrorThenThrow = this.parseMediaErrorThenThrow.bind(this);\n this.clearAllStreams = this.clearAllStreams.bind(this);\n }\n\n get groupedDevices() {\n return this._groupedDevices;\n }\n\n getUserMediaStream(constraints: LocalMediaConstraints): Promise<MediaRequestSuccessResult> {\n trace.info('getUserMediaStream', constraints);\n if (userMediaPromise) {\n return userMediaPromise;\n }\n\n if (window.latestUserMediaStream) {\n const videoTrack = window.latestUserMediaStream.mediaStream.getVideoTracks();\n\n if (videoTrack.length > 0 && videoTrack[0].readyState === 'live') {\n return Promise.resolve({...window.latestUserMediaStream, isNew: false});\n }\n\n this.destroyUserMediaStream();\n }\n\n userMediaPromise = new Promise((resolve, reject) => {\n const catchHandler = (err: any): void => {\n userMediaPromise = null;\n window.latestUserMediaStream = null;\n trace.error('getUserMedia error', err);\n reject(err);\n };\n\n try {\n this.getHighestResolutionStream(false, constraints)\n .then((streamResult: MediaRequestSuccessResult) => {\n userMediaPromise = null;\n window.latestUserMediaStream = streamResult;\n window.latestLocalMediaConstraints = cloneDeep(constraints);\n window.latestLocalMediaConstraints.audio = (streamResult.constraint && streamResult.constraint.audio) as boolean;\n\n resolve({...window.latestUserMediaStream, isNew: true});\n })\n .catch(catchHandler);\n } catch (err) {\n catchHandler(err);\n }\n });\n\n return userMediaPromise;\n }\n\n getDesktopMediaStream(constraints: LocalVideoStreamConstraints): Promise<MediaRequestSuccessResult> {\n if (desktopMediaPromise) {\n return desktopMediaPromise;\n }\n\n trace.info('getDesktopMediaStream', constraints);\n\n if (window.latestDesktopMediaStream) {\n const track = window.latestDesktopMediaStream.mediaStream.getVideoTracks();\n\n if (track.length > 0 && track[0].readyState === 'live') {\n //return Promise.resolve();\n return Promise.resolve({...window.latestDesktopMediaStream, isNew: false});\n }\n this.destroyDesktopMediaStream().catch((error: any) => {\n trace.error('Error destroying desktop media stream', error);\n });\n\n }\n\n desktopMediaPromise = new Promise((resolve, reject) => {\n const mediaCatchHandler = (err: any): void => {\n desktopMediaPromise = null;\n window.latestDesktopMediaStream = null;\n trace.error('getDisplayMedia error', err);\n reject(err);\n };\n\n try {\n this.getHighestResolutionStream(true, {video: constraints, audio: false})\n .then((streamResult: MediaRequestSuccessResult) => {\n desktopMediaPromise = null;\n window.latestDesktopMediaStream = streamResult;\n\n resolve({...window.latestDesktopMediaStream, isNew: true});\n }).catch(mediaCatchHandler);\n } catch (err) {\n mediaCatchHandler(err);\n }\n });\n\n return desktopMediaPromise;\n }\n\n destroyUserMediaStream(): Promise<void> {\n const streamResult = window.latestUserMediaStream;\n\n userMediaPromise = null;\n window.latestUserMediaStream = null;\n window.latestLocalMediaConstraints = null;\n window.mediaStreamAlreadyReplaced = false;\n\n if (streamResult && streamResult.mediaStream) {\n try {\n streamResult.mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.stop();\n });\n\n trace.info('destroyUserMediaStream - stop all tracks');\n } catch (e) {\n trace.info('destroyUserMediaStream - Failed to stop all tracks', e);\n }\n }\n\n return Promise.resolve();\n }\n\n destroyDesktopMediaStream(): Promise<void> {\n const streamResult = window.latestDesktopMediaStream;\n\n window.latestDesktopMediaStream = null;\n desktopMediaPromise = null;\n\n if (streamResult && streamResult.mediaStream) {\n try {\n streamResult.mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.stop();\n });\n\n trace.info('destroyDesktopMediaStream - stop all tracks');\n } catch (e) {\n trace.info('destroyDesktopMediaStream - Failed to stop all tracks', e);\n }\n }\n\n return Promise.resolve();\n }\n\n clearAllStreams(): Promise<void> {\n trace.info('LocalStreamManager Clearing all streams');\n\n return Promise.all([\n this.destroyDesktopMediaStream(),\n this.destroyUserMediaStream()\n ]).then(() => undefined);\n }\n\n private getHighestResolutionStream(isDesktopMedia: boolean, constraints?: LocalMediaConstraints): Promise<MediaRequestSuccessResult> {\n const constraintsCandidates = this.getParsedConstraints(isDesktopMedia, constraints);\n\n trace.info('getHighestResolutionStream - constraintsCandidates:', constraintsCandidates);\n\n if (constraintsCandidates.length === 0) {\n return Promise.reject(new Error('No constraints to retrieve the stream'));\n }\n\n return new Promise((resolve, reject) => {\n let lastSuccessfulResult: Nullable<MediaRequestSuccessResult> = null;\n let lastFailedResult: Nullable<MediaRequestFailResult> = null;\n let isStreamRequestFulfilled = false;\n\n (Promise as any).reduce(constraintsCandidates, (total: any, candidate: MediaStreamConstraints) => {\n if (isStreamRequestFulfilled) {\n return;\n }\n\n const constraintType = get(constraints, 'video.videoResolution.constraintType') || get(constraints, 'video.videoResolution[0].constraintType');\n\n return this.getStreamPromiseByParsedConstraints(candidate, isDesktopMedia)\n .then((stream: MediaStream) => {\n lastSuccessfulResult = {\n mediaStream: stream,\n constraint: candidate,\n constraintType,\n isNew: true\n };\n trace.info('getHighestResolutionStream Success', lastSuccessfulResult);\n isStreamRequestFulfilled = true;\n resolve(lastSuccessfulResult);\n })\n .catch((failResult: MediaRequestFailResult) => {\n lastFailedResult = failResult;\n\n if (lastFailedResult.errorCode === MediaRequestErrorCode.PermissionDenied) {\n isStreamRequestFulfilled = true;\n reject(lastFailedResult);\n }\n });\n }, 0)\n .then(() => {\n if (!isStreamRequestFulfilled) {\n if (!lastFailedResult) {\n lastFailedResult = {\n errorCode: MediaRequestErrorCode.GeneralError,\n message: 'Suitable stream cannot be created'\n };\n }\n reject(lastFailedResult);\n }\n });\n });\n }\n\n private getUserMediaStreamMediaDevice(constraints: MediaStreamConstraints, isDesktopMedia: boolean) {\n let streamPromise = null;\n\n if (!isDesktopMedia) {\n streamPromise = navigator.mediaDevices.getUserMedia(constraints);\n } else {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n streamPromise = navigator.mediaDevices.getDisplayMedia\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n ? navigator.mediaDevices.getDisplayMedia(constraints)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n : navigator.getDisplayMedia(constraints);\n }\n\n return streamPromise;\n }\n\n // eslint-disable-next-line consistent-return,@typescript-eslint/ban-ts-comment\n // @ts-ignore\n private getStreamPromiseByParsedConstraints(constraints: MediaStreamConstraints, isDesktopMedia: boolean): Promise<MediaStream> {\n trace.info('getStreamPromiseByParsedConstraints', constraints);\n\n try {\n return this.getUserMediaStreamMediaDevice(constraints, isDesktopMedia).catch((err: any) => {\n let streamPromise = null;\n\n trace.info('getStreamPromiseByParsedConstraints - get user stream error', err.name);\n\n // Android (Galaxy esp.) have a bug that when using facingMode it might cause NotReadableError. So\n // we should try again but without facingMode. The exception to the rule is when we don't have specific\n // device to use (like in IOS13 bug, as can be seen in MediaServiceBase.ts), in that case, we might end\n // up using the front camera, which is a privacy concern and the preference is to fallback from video\n if (err && (err.name === 'NotReadableError') && get(constraints, 'video.facingMode') &&\n get(constraints, 'video.deviceId')) {\n\n const newConstraints = constraints;\n\n trace.info(`getStreamPromiseByParsedConstraints - NotReadableError - Failed to get video user media stream with facingMode=${get(constraints, 'video.facingMode')}`, err.name);\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n delete newConstraints.video.facingMode;\n ((newConstraints.video as MediaTrackConstraints).deviceId as ConstrainDOMStringParameters) = {\n exact: (constraints.video as MediaTrackConstraints).deviceId\n } as any as ConstrainDOMStringParameters;\n\n streamPromise = this.getStreamPromiseByParsedConstraints(newConstraints, isDesktopMedia);\n } else if (err && err.name && constraints.audio && !constraints.video) {\n trace.info('getStreamPromiseByParsedConstraints - audioStreamFailed - Failed to get audio user media stream', err.name);\n\n return this.parseMediaErrorThenThrow({name: 'audioStreamFailed'});\n } else if (err && err.name && constraints.audio) {\n const newConstraints = constraints;\n\n trace.info('getStreamPromiseByParsedConstraints - Failed to get video and audio user media stream, try to get video media stream only', err.name);\n\n newConstraints.audio = false;\n streamPromise = this.getStreamPromiseByParsedConstraints(newConstraints, isDesktopMedia);\n } else if (err && !streamPromise) {\n trace.info('getStreamPromiseByParsedConstraints - Failed to get video user media stream', err && err.name);\n\n streamPromise = Promise.reject(err);\n }\n\n return streamPromise && streamPromise.catch(this.parseMediaErrorThenThrow);\n });\n } catch (e) {\n this.parseMediaErrorThenThrow(e);\n }\n }\n\n setGroupedDevices(groupedDevices: {video: MediaDeviceInfo[]; audio: MediaDeviceInfo[]}) {\n trace.info('setGroupedDevices', groupedDevices);\n this._groupedDevices = {video: groupedDevices.video\n ? {[CameraTypes.BACK]: last(groupedDevices.video), [CameraTypes.FRONT]: first(groupedDevices.video)}\n : null,\n audio: last(groupedDevices.audio) || null,\n camerasCount: groupedDevices.video.length};\n }\n\n private getParsedConstraints(isDesktopMedia: boolean, streamConstraints?: LocalMediaConstraints): MediaStreamConstraints[] {\n const constraintCandidates: MediaStreamConstraints[] = [];\n\n //TODO - Alex: need to understand which constraints not compatible with screen share\n if (isDesktopMedia) {\n return [{video: true}];\n }\n\n if (!streamConstraints) {\n return constraintCandidates;\n }\n\n const baseConstraints: MediaStreamConstraints = {};\n\n baseConstraints.audio = typeof streamConstraints.audio === 'boolean' ? streamConstraints.audio : undefined;\n\n if (!streamConstraints.video) {\n return [baseConstraints];\n }\n\n const cameraType = (streamConstraints.video !== 'boolean') &&\n (streamConstraints.video as LocalVideoStreamConstraints).videoSourceType;\n\n baseConstraints.video = {\n facingMode: cameraType && cameraType === LocalVideoSourceType.CAMERA_FRONT\n ? 'user'\n : 'environment',\n frameRate: {ideal: 15, max: 30}\n };\n\n const deviceId = get(this._groupedDevices, `video.${cameraType === LocalVideoSourceType.CAMERA_FRONT\n ? CameraTypes.FRONT\n : CameraTypes.BACK}.deviceId`);\n\n if (deviceId) {\n baseConstraints.video.deviceId = deviceId;\n\n if (this._groupedDevices.camerasCount > 1) {\n baseConstraints.video.facingMode = {exact: baseConstraints.video.facingMode} as any as ConstrainDOMStringParameters;\n }\n }\n\n const assignConstraint = (videoResolution: VideoStreamResolution): void => {\n const [width, height] = videoResolution.resolution.split('x');\n const constraintCandidate = assign({}, baseConstraints);\n\n constraintCandidate.video = assign({}, baseConstraints.video, {\n width: _constraintByType(width, videoResolution.constraintType),\n height: _constraintByType(height, videoResolution.constraintType)\n });\n constraintCandidates.push(constraintCandidate);\n };\n\n if ((baseConstraints.video && typeof streamConstraints.video === 'boolean') ||\n !((streamConstraints.video as LocalVideoStreamConstraints).videoResolution instanceof Array)) {\n\n const defaultResolution: VideoStreamResolution = {\n resolution: DEFAULT_VIDEO_RESOLUTION,\n constraintType: DEFAULT_VIDEO_CONSTRAINT_TYPE\n };\n\n assignConstraint(defaultResolution);\n\n return constraintCandidates;\n }\n\n (streamConstraints.video as any).videoResolution.forEach(assignConstraint);\n\n return constraintCandidates;\n }\n\n private parseMediaErrorThenThrow(error: any): MediaRequestFailResult {\n if (error && error.errorCode) {\n throw error;\n }\n\n trace.error('Get media stream error.', error);\n const errorName = error && error.name ? error.name : '';\n\n const permissionErrorNames = [\n 'NotAllowedError',\n 'PermissionDismissedError',\n 'PermissionDeniedError'\n\n ];\n\n // const generalError = [\n // 'NotFoundError',\n // 'DevicesNotFoundError',\n // 'NotReadableError',\n // 'TrackStartError'\n // ];\n\n const constraintsErrors = [\n 'OverconstrainedError',\n 'ConstraintNotSatisfiedError'\n\n ];\n\n const isErrorOfType = (errorsArr: string[]) => errorsArr.filter((err: string) => err === errorName).length > 0;\n\n if (isErrorOfType(permissionErrorNames)) {\n throw {errorCode: MediaRequestErrorCode.PermissionDenied, message: errorName};\n }\n\n if (isErrorOfType(constraintsErrors)) {\n throw {errorCode: MediaRequestErrorCode.Overconstrained, message: errorName};\n }\n\n throw {errorCode: MediaRequestErrorCode.GeneralError, message: errorName};\n }\n}\n\nfunction _constraintByType(value: any, type: ConstraintType): any {\n switch (type) {\n case ConstraintType.MIN:\n return {min: value};\n default:\n return {ideal: value};\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/LocalStreamManager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAEjD,OAAO,EAEH,qBAAqB,EACrB,2BAA2B,EAE3B,yBAAyB,EACzB,iBAAiB,EACpB,MAAM,kBAAkB,CAAC;AAS1B,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,qBAAqB,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QAC3D,wBAAwB,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;KACjE;CACJ;AAcD,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,WAAW,CAAoB;gBAE3B,WAAW,EAAE,iBAAiB;IAO1C,kBAAkB,CAAC,WAAW,EAAE,qBAAqB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAyC1F,qBAAqB,CAAC,WAAW,EAAE,2BAA2B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA0CnG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAevC,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;IAe1C,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC,OAAO,CAAC,0BAA0B;IAqDlC,OAAO,CAAC,mCAAmC;IAsB3C,OAAO,CAAC,oBAAoB;IAsD5B,OAAO,CAAC,wBAAwB;CAoCnC","file":"LocalStreamManager.d.ts","sourcesContent":["import assign from 'lodash/assign';\nimport get from 'lodash/get';\nimport {Promise} from 'bluebird';\n\nimport {Nullable} from '@techsee/techsee-common';\n\nimport {\n VideoStreamResolution,\n LocalMediaConstraints,\n LocalVideoStreamConstraints,\n MediaRequestFailResult,\n MediaRequestSuccessResult,\n IMediaEnvironment\n} from './MediaContracts';\n\nimport {\n ConstraintType,\n DEFAULT_VIDEO_CONSTRAINT_TYPE,\n DEFAULT_VIDEO_RESOLUTION,\n MediaRequestErrorCode\n} from './MediaConstants';\n\ndeclare global {\n interface Window {\n latestUserMediaStream: Nullable<MediaRequestSuccessResult>;\n latestDesktopMediaStream: Nullable<MediaRequestSuccessResult>;\n }\n}\n\ndeclare const window: Window;\n\nwindow.latestUserMediaStream = null;\nlet userMediaPromise: Nullable<Promise<MediaRequestSuccessResult>> = null;\n\nwindow.latestDesktopMediaStream = null;\nlet desktopMediaPromise: Nullable<Promise<MediaRequestSuccessResult>> = null;\n\nimport {getMediaTracer} from './MediaUtils/MediaTracer';\n\nconst trace = getMediaTracer('LocalStreamManager');\n\nexport class LocalStreamManager {\n private environment: IMediaEnvironment;\n\n constructor(environment: IMediaEnvironment) {\n this.environment = environment;\n\n this.parseMediaErrorThenThrow = this.parseMediaErrorThenThrow.bind(this);\n this.clearAllStreams = this.clearAllStreams.bind(this);\n }\n\n getUserMediaStream(constraints: LocalMediaConstraints): Promise<MediaRequestSuccessResult> {\n trace.info('getUserMediaStream', constraints);\n if (userMediaPromise) {\n return userMediaPromise;\n }\n\n if (window.latestUserMediaStream) {\n const videoTrack = window.latestUserMediaStream.mediaStream.getVideoTracks();\n\n if (videoTrack.length > 0 && videoTrack[0].readyState === 'live') {\n return Promise.resolve({...window.latestUserMediaStream, isNew: false});\n }\n this.destroyUserMediaStream();\n\n }\n\n\n userMediaPromise = new Promise((resolve, reject) => {\n const catchHandler = (err: any): void => {\n userMediaPromise = null;\n window.latestUserMediaStream = null;\n trace.error('getUserMedia error', err);\n reject(err);\n };\n\n try {\n this.getHighestResolutionStream(false, constraints)\n .then((streamResult: MediaRequestSuccessResult) => {\n userMediaPromise = null;\n window.latestUserMediaStream = streamResult;\n resolve({...window.latestUserMediaStream, isNew: true});\n })\n .catch(catchHandler);\n } catch (err) {\n catchHandler(err);\n }\n });\n\n return userMediaPromise;\n }\n\n getDesktopMediaStream(constraints: LocalVideoStreamConstraints): Promise<MediaRequestSuccessResult> {\n if (desktopMediaPromise) {\n return desktopMediaPromise;\n }\n\n if (window.latestDesktopMediaStream) {\n const track = window.latestDesktopMediaStream.mediaStream.getVideoTracks();\n\n if (track.length > 0 && track[0].readyState === 'live') {\n //return Promise.resolve();\n return Promise.resolve({...window.latestDesktopMediaStream, isNew: false});\n }\n this.destroyDesktopMediaStream().catch((error: any) => {\n trace.error('Error destroying desktop media stream', error);\n });\n\n }\n\n desktopMediaPromise = new Promise((resolve, reject) => {\n const mediaCatchHandler = (err: any): void => {\n desktopMediaPromise = null;\n window.latestDesktopMediaStream = null;\n trace.error('getDisplayMedia error', err);\n reject(err);\n };\n\n try {\n this.getHighestResolutionStream(true, {video: constraints, audio: false})\n .then((streamResult: MediaRequestSuccessResult) => {\n desktopMediaPromise = null;\n window.latestDesktopMediaStream = streamResult;\n\n resolve({...window.latestDesktopMediaStream, isNew: true});\n }).catch(mediaCatchHandler);\n } catch (err) {\n mediaCatchHandler(err);\n }\n });\n\n return desktopMediaPromise;\n }\n\n destroyUserMediaStream(): Promise<void> {\n const streamResult = window.latestUserMediaStream;\n\n window.latestUserMediaStream = null;\n userMediaPromise = null;\n\n if (streamResult) {\n streamResult.mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.stop();\n });\n }\n\n return Promise.resolve();\n }\n\n destroyDesktopMediaStream(): Promise<void> {\n const streamResult = window.latestDesktopMediaStream;\n\n window.latestDesktopMediaStream = null;\n desktopMediaPromise = null;\n\n if (streamResult) {\n streamResult.mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.stop();\n });\n }\n\n return Promise.resolve();\n }\n\n clearAllStreams(): Promise<void> {\n trace.info('LocalStreamManager Clearing all streams');\n\n return Promise.all([\n this.destroyDesktopMediaStream(),\n this.destroyUserMediaStream()\n ]).then(() => undefined);\n }\n\n private getHighestResolutionStream(isDesktopMedia: boolean, constraints?: LocalMediaConstraints): Promise<MediaRequestSuccessResult> {\n const constraintsCandidates = this.getParsedConstraints(isDesktopMedia, constraints);\n\n if (constraintsCandidates.length === 0) {\n return Promise.reject(new Error('No constraints to retrieve the stream'));\n }\n\n return new Promise((resolve, reject) => {\n let lastSuccessfulResult: Nullable<MediaRequestSuccessResult> = null;\n let lastFailedResult: Nullable<MediaRequestFailResult> = null;\n let isStreamRequestFulfilled = false;\n\n (Promise as any).reduce(constraintsCandidates, (total: any, candidate: MediaStreamConstraints) => {\n if (isStreamRequestFulfilled) {\n return;\n }\n const constraintType = get(constraints, 'video.videoResolution.constraintType') || get(constraints, 'video.videoResolution[0].constraintType');\n\n return this.getStreamPromiseByParsedConstraints(candidate, isDesktopMedia)\n .then((stream: MediaStream) => {\n lastSuccessfulResult = {\n mediaStream: stream,\n constraint: candidate,\n constraintType,\n isNew: true\n };\n trace.info('getHighestResolutionStream Success', lastSuccessfulResult);\n isStreamRequestFulfilled = true;\n resolve(lastSuccessfulResult);\n })\n .catch((failResult: MediaRequestFailResult) => {\n lastFailedResult = failResult;\n if (lastFailedResult.errorCode === MediaRequestErrorCode.PermissionDenied) {\n isStreamRequestFulfilled = true;\n reject(lastFailedResult);\n }\n });\n }, 0)\n .then(() => {\n if (!isStreamRequestFulfilled) {\n if (!lastFailedResult) {\n lastFailedResult = {\n errorCode: MediaRequestErrorCode.GeneralError,\n message: 'Suitable stream cannot be created'\n };\n }\n reject(lastFailedResult);\n }\n });\n });\n }\n\n //@ts-ignore\n private getStreamPromiseByParsedConstraints(constraints: MediaStreamConstraints, isDesktopMedia: boolean): Promise<MediaStream> {\n let streamPromise = null;\n\n trace.info('getStreamPromiseByParsedConstraints', constraints);\n\n try {\n if (!isDesktopMedia) {\n streamPromise = navigator.mediaDevices.getUserMedia(constraints);\n } else {\n //@ts-ignore\n streamPromise = navigator.mediaDevices.getDisplayMedia\n //@ts-ignore\n ? navigator.mediaDevices.getDisplayMedia(constraints)\n : navigator.getDisplayMedia(constraints);\n }\n\n return streamPromise.catch(this.parseMediaErrorThenThrow);\n } catch (e) {\n this.parseMediaErrorThenThrow(e);\n }\n }\n\n private getParsedConstraints(isDesktopMedia: boolean, streamConstraints?: LocalMediaConstraints): MediaStreamConstraints[] {\n const constraintCandidates: MediaStreamConstraints[] = [];\n\n //TODO - Alex: need to understand which constraints not compatible with screen share\n if (isDesktopMedia) {\n return [{video: true}];\n }\n\n if (!streamConstraints) {\n return constraintCandidates;\n }\n\n const baseConstraints: MediaStreamConstraints = {};\n\n baseConstraints.audio = typeof streamConstraints.audio === 'boolean' ? streamConstraints.audio : undefined;\n\n if (!streamConstraints.video) {\n return [baseConstraints];\n }\n\n baseConstraints.video = {\n facingMode: 'environment',\n frameRate: {ideal: 15, max: 30}\n };\n\n const assignConstraint = (videoResolution: VideoStreamResolution): void => {\n const [width, height] = videoResolution.resolution.split('x');\n const constraintCandidate = assign({}, baseConstraints);\n\n constraintCandidate.video = assign({}, baseConstraints.video, {\n width: _constraintByType(width, videoResolution.constraintType),\n height: _constraintByType(height, videoResolution.constraintType)\n });\n constraintCandidates.push(constraintCandidate);\n };\n\n if ((baseConstraints.video && typeof streamConstraints.video === 'boolean') ||\n !((streamConstraints.video as LocalVideoStreamConstraints).videoResolution instanceof Array)) {\n\n const defaultResolution: VideoStreamResolution = {\n resolution: DEFAULT_VIDEO_RESOLUTION,\n constraintType: DEFAULT_VIDEO_CONSTRAINT_TYPE\n };\n\n assignConstraint(defaultResolution);\n\n return constraintCandidates;\n }\n\n (streamConstraints.video as any).videoResolution.forEach(assignConstraint);\n\n return constraintCandidates;\n }\n\n private parseMediaErrorThenThrow(error: any): MediaRequestFailResult {\n trace.error('Get media stream error.', error);\n const errorName = error && error.name ? error.name : '';\n\n const permissionErrorNames = [\n 'NotAllowedError',\n 'PermissionDismissedError',\n 'PermissionDeniedError'\n\n ];\n\n // const generalError = [\n // 'NotFoundError',\n // 'DevicesNotFoundError',\n // 'NotReadableError',\n // 'TrackStartError'\n // ];\n\n const constraintsErrors = [\n 'OverconstrainedError',\n 'ConstraintNotSatisfiedError'\n\n ];\n\n const isErrorOfType = (errorsArr: string[]) => errorsArr.filter((err: string) => err === errorName).length > 0;\n\n if (isErrorOfType(permissionErrorNames)) {\n throw {errorCode: MediaRequestErrorCode.PermissionDenied, message: errorName};\n }\n\n if (isErrorOfType(constraintsErrors)) {\n throw {errorCode: MediaRequestErrorCode.Overconstrained, message: errorName};\n }\n\n throw {errorCode: MediaRequestErrorCode.GeneralError, message: errorName};\n }\n}\n\nfunction _constraintByType(value: any, type: ConstraintType): any {\n switch (type) {\n case ConstraintType.MIN:\n return {min: value};\n default:\n return {ideal: value};\n }\n}\n"]}