@techsee/techsee-media-service 999.13.8-sap → 999.14.0-alpha

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.
@@ -1,3 +1,4 @@
1
+ import { VideoStreamResolution } from './MediaContracts';
1
2
  export declare enum LocalVideoSourceType {
2
3
  CAMERA = "CAMERA",
3
4
  CAMERA_FRONT = "CAMERA_FRONT",
@@ -36,6 +37,7 @@ export declare enum KnownMediaStreamKind {
36
37
  }
37
38
  export declare enum KnownMediaStream {
38
39
  AGENT_AUDIO_STREAM = "DASHBOARD_AUDIO_STREAM",
40
+ OBSERVER_AUDIO_STREAM = "OBSERVER_AUDIO_STREAM",
39
41
  USER_AUDIO_STREAM = "MOBILE_CLIENT_AUDIO_STREAM",
40
42
  USER_VIDEO_STREAM = "MOBILE_CLIENT_VIDEO_STREAM",
41
43
  USER_SCREEN_SHARE_STREAM = "USER_SCREEN_SHARE_STREAM"
@@ -59,3 +61,5 @@ export declare const DEFAULT_VIDEO_RESOLUTION = "640x480";
59
61
  export declare const DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;
60
62
  export declare const DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;
61
63
  export declare const DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;
64
+ export declare const DEFAULT_VIDEO_CONSTRAINTS: VideoStreamResolution;
65
+ export declare const POSSIBLE_LOOPBACK_RESOLUTIONS: VideoStreamResolution[];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/MediaConstants.ts"],"names":[],"mappings":"AAAA,oBAAY,oBAAoB;IAC5B,MAAM,WAAW;IACjB,YAAY,iBAAiB;IAC7B,aAAa,kBAAkB;CAClC;AAED,oBAAY,cAAc;IACtB,GAAG,QAAQ;IACX,KAAK,UAAU;CAClB;AAED,oBAAY,WAAW;IACnB,KAAK,UAAU;IACf,IAAI,SAAS;CAChB;AAED,oBAAY,gBAAgB;IACxB,OAAO,YAAY;IACnB,UAAU,gBAAgB;IAC1B,WAAW,iBAAiB;CAC/B;AAED,oBAAY,iBAAiB;IACzB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,IAAI,SAAS;CAChB;AAED,oBAAY,iBAAiB;IACzB,SAAS,cAAc;IACvB,KAAK,eAAe;CACvB;AAED,oBAAY,qBAAqB;IAC7B,eAAe,oBAAoB;IACnC,gBAAgB,qBAAqB;IACrC,YAAY,iBAAiB;CAChC;AAED,oBAAY,oBAAoB;IAC5B,KAAK,UAAU;IACf,KAAK,UAAU;CAClB;AAED,oBAAY,gBAAgB;IACxB,kBAAkB,2BAA2B;IAC7C,iBAAiB,+BAA+B;IAChD,iBAAiB,+BAA+B;IAChD,wBAAwB,6BAA6B;CACxD;AAED,oBAAY,4BAA4B;IAEpC,gBAAgB,qBAAqB;IACrC,yBAAyB,8BAA8B;IACvD,gCAAgC,qCAAqC;IACrE,wBAAwB,6BAA6B;IACrD,wBAAwB,6BAA6B;IACrD,gBAAgB,qBAAqB;IACrC,0BAA0B,+BAA+B;CAC5D;AAED,oBAAY,2BAA2B;IACnC,WAAW,gBAAgB;IAC3B,eAAe,oBAAoB;IACnC,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;CACpC;AAED,eAAO,MAAM,wBAAwB,YAAY,CAAC;AAClD,eAAO,MAAM,6BAA6B,uBAAuB,CAAC;AAClE,eAAO,MAAM,yCAAyC,KAAK,CAAC;AAC5D,eAAO,MAAM,kCAAkC,KAAK,CAAC","file":"MediaConstants.d.ts","sourcesContent":["export enum LocalVideoSourceType {\n CAMERA = 'CAMERA',\n CAMERA_FRONT = 'CAMERA_FRONT',\n DESKTOP_SHARE = 'DESKTOP_SHARE'\n}\n\nexport enum ConstraintType {\n MIN = 'min',\n IDEAL = 'ideal'\n}\n\nexport enum CameraTypes {\n FRONT = 'front',\n BACK = 'back'\n}\n\nexport enum MediaServiceType {\n OPENTOK = 'OPENTOK',\n TURNSERVER = 'TURN_SERVER',\n MEDIASERVER = 'MEDIA_SERVER'\n}\n\nexport enum SessionClientRole {\n AGENT = 'AGENT',\n OBSERVER = 'OBSERVER',\n USER = 'USER'\n}\n\nexport enum SessionClientType {\n INITIATOR = 'publisher',\n GUEST = 'subscriber'\n}\n\nexport enum MediaRequestErrorCode {\n Overconstrained = 'Overconstrained',\n PermissionDenied = 'PermissionDenied',\n GeneralError = 'GeneralError'\n}\n\nexport enum KnownMediaStreamKind {\n Audio = 'audio',\n Video = 'video'\n}\n\nexport enum KnownMediaStream {\n AGENT_AUDIO_STREAM = 'DASHBOARD_AUDIO_STREAM',\n USER_AUDIO_STREAM = 'MOBILE_CLIENT_AUDIO_STREAM',\n USER_VIDEO_STREAM = 'MOBILE_CLIENT_VIDEO_STREAM',\n USER_SCREEN_SHARE_STREAM = 'USER_SCREEN_SHARE_STREAM'\n}\n\nexport enum MediaSessionDisconnectReason {\n //Raised on initiator peer when guest peer was disconnected from signaling\n PeerDisconnected = 'PeerDisconnected',\n PeerConnectionInterrupted = 'PeerConnectionInterrupted',\n PeerConnectionStateChangeTimeout = 'PeerConnectionStateChangeTimeout',\n InitiatorPeerReconnected = 'InitiatorPeerReconnected',\n PublishedStreamDestroyed = 'PublishedStreamDestroyed',\n ForcedByConsumer = 'ForcedByConsumer',\n SignalingChannelDisconnect = 'SignalingChannelDisconnect'\n}\n\nexport enum MediaStreamUnregisterReason {\n NativeEvent = 'NativeEvent',\n ReplacingStream = 'ReplacingStream',\n ClosedRemotely = 'ClosedRemotely',\n ServiceCleanUp = 'ServiceCleanUp'\n}\n\nexport const DEFAULT_VIDEO_RESOLUTION = '640x480';\nexport const DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;\nexport const DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;\nexport const DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;\n"]}
1
+ {"version":3,"sources":["../src/MediaConstants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,oBAAY,oBAAoB;IAC5B,MAAM,WAAW;IACjB,YAAY,iBAAiB;IAC7B,aAAa,kBAAkB;CAClC;AAED,oBAAY,cAAc;IACtB,GAAG,QAAQ;IACX,KAAK,UAAU;CAClB;AAED,oBAAY,WAAW;IACnB,KAAK,UAAU;IACf,IAAI,SAAS;CAChB;AAED,oBAAY,gBAAgB;IACxB,OAAO,YAAY;IACnB,UAAU,gBAAgB;IAC1B,WAAW,iBAAiB;CAC/B;AAED,oBAAY,iBAAiB;IACzB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,IAAI,SAAS;CAChB;AAED,oBAAY,iBAAiB;IACzB,SAAS,cAAc;IACvB,KAAK,eAAe;CACvB;AAED,oBAAY,qBAAqB;IAC7B,eAAe,oBAAoB;IACnC,gBAAgB,qBAAqB;IACrC,YAAY,iBAAiB;CAChC;AAED,oBAAY,oBAAoB;IAC5B,KAAK,UAAU;IACf,KAAK,UAAU;CAClB;AAED,oBAAY,gBAAgB;IACxB,kBAAkB,2BAA2B;IAC7C,qBAAqB,0BAA0B;IAC/C,iBAAiB,+BAA+B;IAChD,iBAAiB,+BAA+B;IAChD,wBAAwB,6BAA6B;CACxD;AAED,oBAAY,4BAA4B;IAEpC,gBAAgB,qBAAqB;IACrC,yBAAyB,8BAA8B;IACvD,gCAAgC,qCAAqC;IACrE,wBAAwB,6BAA6B;IACrD,wBAAwB,6BAA6B;IACrD,gBAAgB,qBAAqB;IACrC,0BAA0B,+BAA+B;CAC5D;AAED,oBAAY,2BAA2B;IACnC,WAAW,gBAAgB;IAC3B,eAAe,oBAAoB;IACnC,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;CACpC;AAED,eAAO,MAAM,wBAAwB,YAAY,CAAC;AAClD,eAAO,MAAM,6BAA6B,uBAAuB,CAAC;AAClE,eAAO,MAAM,yCAAyC,KAAK,CAAC;AAC5D,eAAO,MAAM,kCAAkC,KAAK,CAAC;AAErD,eAAO,MAAM,yBAAyB,EAAE,qBAGvC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,qBAAqB,EAIhE,CAAC","file":"MediaConstants.d.ts","sourcesContent":["import {VideoStreamResolution} from './MediaContracts';\n\nexport enum LocalVideoSourceType {\n CAMERA = 'CAMERA',\n CAMERA_FRONT = 'CAMERA_FRONT',\n DESKTOP_SHARE = 'DESKTOP_SHARE'\n}\n\nexport enum ConstraintType {\n MIN = 'min',\n IDEAL = 'ideal'\n}\n\nexport enum CameraTypes {\n FRONT = 'front',\n BACK = 'back'\n}\n\nexport enum MediaServiceType {\n OPENTOK = 'OPENTOK',\n TURNSERVER = 'TURN_SERVER',\n MEDIASERVER = 'MEDIA_SERVER'\n}\n\nexport enum SessionClientRole {\n AGENT = 'AGENT',\n OBSERVER = 'OBSERVER',\n USER = 'USER'\n}\n\nexport enum SessionClientType {\n INITIATOR = 'publisher',\n GUEST = 'subscriber'\n}\n\nexport enum MediaRequestErrorCode {\n Overconstrained = 'Overconstrained',\n PermissionDenied = 'PermissionDenied',\n GeneralError = 'GeneralError'\n}\n\nexport enum KnownMediaStreamKind {\n Audio = 'audio',\n Video = 'video'\n}\n\nexport enum KnownMediaStream {\n AGENT_AUDIO_STREAM = 'DASHBOARD_AUDIO_STREAM',\n OBSERVER_AUDIO_STREAM = 'OBSERVER_AUDIO_STREAM',\n USER_AUDIO_STREAM = 'MOBILE_CLIENT_AUDIO_STREAM',\n USER_VIDEO_STREAM = 'MOBILE_CLIENT_VIDEO_STREAM',\n USER_SCREEN_SHARE_STREAM = 'USER_SCREEN_SHARE_STREAM'\n}\n\nexport enum MediaSessionDisconnectReason {\n //Raised on initiator peer when guest peer was disconnected from signaling\n PeerDisconnected = 'PeerDisconnected',\n PeerConnectionInterrupted = 'PeerConnectionInterrupted',\n PeerConnectionStateChangeTimeout = 'PeerConnectionStateChangeTimeout',\n InitiatorPeerReconnected = 'InitiatorPeerReconnected',\n PublishedStreamDestroyed = 'PublishedStreamDestroyed',\n ForcedByConsumer = 'ForcedByConsumer',\n SignalingChannelDisconnect = 'SignalingChannelDisconnect'\n}\n\nexport enum MediaStreamUnregisterReason {\n NativeEvent = 'NativeEvent',\n ReplacingStream = 'ReplacingStream',\n ClosedRemotely = 'ClosedRemotely',\n ServiceCleanUp = 'ServiceCleanUp'\n}\n\nexport const DEFAULT_VIDEO_RESOLUTION = '640x480';\nexport const DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;\nexport const DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;\nexport const DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;\n\nexport const DEFAULT_VIDEO_CONSTRAINTS: VideoStreamResolution = {\n resolution: DEFAULT_VIDEO_RESOLUTION,\n constraintType: DEFAULT_VIDEO_CONSTRAINT_TYPE\n};\n\nexport const POSSIBLE_LOOPBACK_RESOLUTIONS: VideoStreamResolution[] = [\n {resolution: '1920x1080', constraintType: ConstraintType.MIN}, // FHD\n {resolution: '1280x720', constraintType: ConstraintType.MIN}, // HD\n DEFAULT_VIDEO_CONSTRAINTS // fallback\n];\n"]}
@@ -48,6 +48,7 @@ var KnownMediaStreamKind;
48
48
  var KnownMediaStream;
49
49
  (function (KnownMediaStream) {
50
50
  KnownMediaStream["AGENT_AUDIO_STREAM"] = "DASHBOARD_AUDIO_STREAM";
51
+ KnownMediaStream["OBSERVER_AUDIO_STREAM"] = "OBSERVER_AUDIO_STREAM";
51
52
  KnownMediaStream["USER_AUDIO_STREAM"] = "MOBILE_CLIENT_AUDIO_STREAM";
52
53
  KnownMediaStream["USER_VIDEO_STREAM"] = "MOBILE_CLIENT_VIDEO_STREAM";
53
54
  KnownMediaStream["USER_SCREEN_SHARE_STREAM"] = "USER_SCREEN_SHARE_STREAM";
@@ -74,6 +75,12 @@ exports.DEFAULT_VIDEO_RESOLUTION = '640x480';
74
75
  exports.DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;
75
76
  exports.DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;
76
77
  exports.DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;
78
+ exports.DEFAULT_VIDEO_CONSTRAINTS = {
79
+ resolution: exports.DEFAULT_VIDEO_RESOLUTION,
80
+ constraintType: exports.DEFAULT_VIDEO_CONSTRAINT_TYPE
81
+ };
82
+ exports.POSSIBLE_LOOPBACK_RESOLUTIONS = [{ resolution: '1920x1080', constraintType: ConstraintType.MIN }, { resolution: '1280x720', constraintType: ConstraintType.MIN }, exports.DEFAULT_VIDEO_CONSTRAINTS // fallback
83
+ ];
77
84
 
78
85
  //# sourceMappingURL=MediaConstants.js.map
79
86
  //# sourceMappingURL=MediaConstants.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["MediaConstants.js","../src/MediaConstants.ts"],"names":["Object","defineProperty","exports","value","LocalVideoSourceType","ConstraintType","CameraTypes","MediaServiceType","SessionClientRole","SessionClientType","MediaRequestErrorCode","KnownMediaStreamKind","KnownMediaStream","MediaSessionDisconnectReason","MediaStreamUnregisterReason","DEFAULT_VIDEO_RESOLUTION","DEFAULT_VIDEO_CONSTRAINT_TYPE","IDEAL","DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS","DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS"],"mappings":"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","file":"MediaConstants.js","sourcesContent":["\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar LocalVideoSourceType;\n(function (LocalVideoSourceType) {\n LocalVideoSourceType[\"CAMERA\"] = \"CAMERA\";\n LocalVideoSourceType[\"CAMERA_FRONT\"] = \"CAMERA_FRONT\";\n LocalVideoSourceType[\"DESKTOP_SHARE\"] = \"DESKTOP_SHARE\";\n})(LocalVideoSourceType = exports.LocalVideoSourceType || (exports.LocalVideoSourceType = {}));\nvar ConstraintType;\n(function (ConstraintType) {\n ConstraintType[\"MIN\"] = \"min\";\n ConstraintType[\"IDEAL\"] = \"ideal\";\n})(ConstraintType = exports.ConstraintType || (exports.ConstraintType = {}));\nvar CameraTypes;\n(function (CameraTypes) {\n CameraTypes[\"FRONT\"] = \"front\";\n CameraTypes[\"BACK\"] = \"back\";\n})(CameraTypes = exports.CameraTypes || (exports.CameraTypes = {}));\nvar MediaServiceType;\n(function (MediaServiceType) {\n MediaServiceType[\"OPENTOK\"] = \"OPENTOK\";\n MediaServiceType[\"TURNSERVER\"] = \"TURN_SERVER\";\n MediaServiceType[\"MEDIASERVER\"] = \"MEDIA_SERVER\";\n})(MediaServiceType = exports.MediaServiceType || (exports.MediaServiceType = {}));\nvar SessionClientRole;\n(function (SessionClientRole) {\n SessionClientRole[\"AGENT\"] = \"AGENT\";\n SessionClientRole[\"OBSERVER\"] = \"OBSERVER\";\n SessionClientRole[\"USER\"] = \"USER\";\n})(SessionClientRole = exports.SessionClientRole || (exports.SessionClientRole = {}));\nvar SessionClientType;\n(function (SessionClientType) {\n SessionClientType[\"INITIATOR\"] = \"publisher\";\n SessionClientType[\"GUEST\"] = \"subscriber\";\n})(SessionClientType = exports.SessionClientType || (exports.SessionClientType = {}));\nvar MediaRequestErrorCode;\n(function (MediaRequestErrorCode) {\n MediaRequestErrorCode[\"Overconstrained\"] = \"Overconstrained\";\n MediaRequestErrorCode[\"PermissionDenied\"] = \"PermissionDenied\";\n MediaRequestErrorCode[\"GeneralError\"] = \"GeneralError\";\n})(MediaRequestErrorCode = exports.MediaRequestErrorCode || (exports.MediaRequestErrorCode = {}));\nvar KnownMediaStreamKind;\n(function (KnownMediaStreamKind) {\n KnownMediaStreamKind[\"Audio\"] = \"audio\";\n KnownMediaStreamKind[\"Video\"] = \"video\";\n})(KnownMediaStreamKind = exports.KnownMediaStreamKind || (exports.KnownMediaStreamKind = {}));\nvar KnownMediaStream;\n(function (KnownMediaStream) {\n KnownMediaStream[\"AGENT_AUDIO_STREAM\"] = \"DASHBOARD_AUDIO_STREAM\";\n KnownMediaStream[\"USER_AUDIO_STREAM\"] = \"MOBILE_CLIENT_AUDIO_STREAM\";\n KnownMediaStream[\"USER_VIDEO_STREAM\"] = \"MOBILE_CLIENT_VIDEO_STREAM\";\n KnownMediaStream[\"USER_SCREEN_SHARE_STREAM\"] = \"USER_SCREEN_SHARE_STREAM\";\n})(KnownMediaStream = exports.KnownMediaStream || (exports.KnownMediaStream = {}));\nvar MediaSessionDisconnectReason;\n(function (MediaSessionDisconnectReason) {\n //Raised on initiator peer when guest peer was disconnected from signaling\n MediaSessionDisconnectReason[\"PeerDisconnected\"] = \"PeerDisconnected\";\n MediaSessionDisconnectReason[\"PeerConnectionInterrupted\"] = \"PeerConnectionInterrupted\";\n MediaSessionDisconnectReason[\"PeerConnectionStateChangeTimeout\"] = \"PeerConnectionStateChangeTimeout\";\n MediaSessionDisconnectReason[\"InitiatorPeerReconnected\"] = \"InitiatorPeerReconnected\";\n MediaSessionDisconnectReason[\"PublishedStreamDestroyed\"] = \"PublishedStreamDestroyed\";\n MediaSessionDisconnectReason[\"ForcedByConsumer\"] = \"ForcedByConsumer\";\n MediaSessionDisconnectReason[\"SignalingChannelDisconnect\"] = \"SignalingChannelDisconnect\";\n})(MediaSessionDisconnectReason = exports.MediaSessionDisconnectReason || (exports.MediaSessionDisconnectReason = {}));\nvar MediaStreamUnregisterReason;\n(function (MediaStreamUnregisterReason) {\n MediaStreamUnregisterReason[\"NativeEvent\"] = \"NativeEvent\";\n MediaStreamUnregisterReason[\"ReplacingStream\"] = \"ReplacingStream\";\n MediaStreamUnregisterReason[\"ClosedRemotely\"] = \"ClosedRemotely\";\n MediaStreamUnregisterReason[\"ServiceCleanUp\"] = \"ServiceCleanUp\";\n})(MediaStreamUnregisterReason = exports.MediaStreamUnregisterReason || (exports.MediaStreamUnregisterReason = {}));\nexports.DEFAULT_VIDEO_RESOLUTION = '640x480';\nexports.DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;\nexports.DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;\nexports.DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;\n\n//# sourceMappingURL=MediaConstants.js.map\n","export enum LocalVideoSourceType {\n CAMERA = 'CAMERA',\n CAMERA_FRONT = 'CAMERA_FRONT',\n DESKTOP_SHARE = 'DESKTOP_SHARE'\n}\n\nexport enum ConstraintType {\n MIN = 'min',\n IDEAL = 'ideal'\n}\n\nexport enum CameraTypes {\n FRONT = 'front',\n BACK = 'back'\n}\n\nexport enum MediaServiceType {\n OPENTOK = 'OPENTOK',\n TURNSERVER = 'TURN_SERVER',\n MEDIASERVER = 'MEDIA_SERVER'\n}\n\nexport enum SessionClientRole {\n AGENT = 'AGENT',\n OBSERVER = 'OBSERVER',\n USER = 'USER'\n}\n\nexport enum SessionClientType {\n INITIATOR = 'publisher',\n GUEST = 'subscriber'\n}\n\nexport enum MediaRequestErrorCode {\n Overconstrained = 'Overconstrained',\n PermissionDenied = 'PermissionDenied',\n GeneralError = 'GeneralError'\n}\n\nexport enum KnownMediaStreamKind {\n Audio = 'audio',\n Video = 'video'\n}\n\nexport enum KnownMediaStream {\n AGENT_AUDIO_STREAM = 'DASHBOARD_AUDIO_STREAM',\n USER_AUDIO_STREAM = 'MOBILE_CLIENT_AUDIO_STREAM',\n USER_VIDEO_STREAM = 'MOBILE_CLIENT_VIDEO_STREAM',\n USER_SCREEN_SHARE_STREAM = 'USER_SCREEN_SHARE_STREAM'\n}\n\nexport enum MediaSessionDisconnectReason {\n //Raised on initiator peer when guest peer was disconnected from signaling\n PeerDisconnected = 'PeerDisconnected',\n PeerConnectionInterrupted = 'PeerConnectionInterrupted',\n PeerConnectionStateChangeTimeout = 'PeerConnectionStateChangeTimeout',\n InitiatorPeerReconnected = 'InitiatorPeerReconnected',\n PublishedStreamDestroyed = 'PublishedStreamDestroyed',\n ForcedByConsumer = 'ForcedByConsumer',\n SignalingChannelDisconnect = 'SignalingChannelDisconnect'\n}\n\nexport enum MediaStreamUnregisterReason {\n NativeEvent = 'NativeEvent',\n ReplacingStream = 'ReplacingStream',\n ClosedRemotely = 'ClosedRemotely',\n ServiceCleanUp = 'ServiceCleanUp'\n}\n\nexport const DEFAULT_VIDEO_RESOLUTION = '640x480';\nexport const DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;\nexport const DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;\nexport const DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;\n"]}
1
+ {"version":3,"sources":["MediaConstants.js","../src/MediaConstants.ts"],"names":["Object","defineProperty","exports","value","LocalVideoSourceType","ConstraintType","CameraTypes","MediaServiceType","SessionClientRole","SessionClientType","MediaRequestErrorCode","KnownMediaStreamKind","KnownMediaStream","MediaSessionDisconnectReason","MediaStreamUnregisterReason","DEFAULT_VIDEO_RESOLUTION","DEFAULT_VIDEO_CONSTRAINT_TYPE","IDEAL","DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS","DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS","DEFAULT_VIDEO_CONSTRAINTS","resolution","constraintType","POSSIBLE_LOOPBACK_RESOLUTIONS","MIN"],"mappings":"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","file":"MediaConstants.js","sourcesContent":["\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar LocalVideoSourceType;\n(function (LocalVideoSourceType) {\n LocalVideoSourceType[\"CAMERA\"] = \"CAMERA\";\n LocalVideoSourceType[\"CAMERA_FRONT\"] = \"CAMERA_FRONT\";\n LocalVideoSourceType[\"DESKTOP_SHARE\"] = \"DESKTOP_SHARE\";\n})(LocalVideoSourceType = exports.LocalVideoSourceType || (exports.LocalVideoSourceType = {}));\nvar ConstraintType;\n(function (ConstraintType) {\n ConstraintType[\"MIN\"] = \"min\";\n ConstraintType[\"IDEAL\"] = \"ideal\";\n})(ConstraintType = exports.ConstraintType || (exports.ConstraintType = {}));\nvar CameraTypes;\n(function (CameraTypes) {\n CameraTypes[\"FRONT\"] = \"front\";\n CameraTypes[\"BACK\"] = \"back\";\n})(CameraTypes = exports.CameraTypes || (exports.CameraTypes = {}));\nvar MediaServiceType;\n(function (MediaServiceType) {\n MediaServiceType[\"OPENTOK\"] = \"OPENTOK\";\n MediaServiceType[\"TURNSERVER\"] = \"TURN_SERVER\";\n MediaServiceType[\"MEDIASERVER\"] = \"MEDIA_SERVER\";\n})(MediaServiceType = exports.MediaServiceType || (exports.MediaServiceType = {}));\nvar SessionClientRole;\n(function (SessionClientRole) {\n SessionClientRole[\"AGENT\"] = \"AGENT\";\n SessionClientRole[\"OBSERVER\"] = \"OBSERVER\";\n SessionClientRole[\"USER\"] = \"USER\";\n})(SessionClientRole = exports.SessionClientRole || (exports.SessionClientRole = {}));\nvar SessionClientType;\n(function (SessionClientType) {\n SessionClientType[\"INITIATOR\"] = \"publisher\";\n SessionClientType[\"GUEST\"] = \"subscriber\";\n})(SessionClientType = exports.SessionClientType || (exports.SessionClientType = {}));\nvar MediaRequestErrorCode;\n(function (MediaRequestErrorCode) {\n MediaRequestErrorCode[\"Overconstrained\"] = \"Overconstrained\";\n MediaRequestErrorCode[\"PermissionDenied\"] = \"PermissionDenied\";\n MediaRequestErrorCode[\"GeneralError\"] = \"GeneralError\";\n})(MediaRequestErrorCode = exports.MediaRequestErrorCode || (exports.MediaRequestErrorCode = {}));\nvar KnownMediaStreamKind;\n(function (KnownMediaStreamKind) {\n KnownMediaStreamKind[\"Audio\"] = \"audio\";\n KnownMediaStreamKind[\"Video\"] = \"video\";\n})(KnownMediaStreamKind = exports.KnownMediaStreamKind || (exports.KnownMediaStreamKind = {}));\nvar KnownMediaStream;\n(function (KnownMediaStream) {\n KnownMediaStream[\"AGENT_AUDIO_STREAM\"] = \"DASHBOARD_AUDIO_STREAM\";\n KnownMediaStream[\"OBSERVER_AUDIO_STREAM\"] = \"OBSERVER_AUDIO_STREAM\";\n KnownMediaStream[\"USER_AUDIO_STREAM\"] = \"MOBILE_CLIENT_AUDIO_STREAM\";\n KnownMediaStream[\"USER_VIDEO_STREAM\"] = \"MOBILE_CLIENT_VIDEO_STREAM\";\n KnownMediaStream[\"USER_SCREEN_SHARE_STREAM\"] = \"USER_SCREEN_SHARE_STREAM\";\n})(KnownMediaStream = exports.KnownMediaStream || (exports.KnownMediaStream = {}));\nvar MediaSessionDisconnectReason;\n(function (MediaSessionDisconnectReason) {\n //Raised on initiator peer when guest peer was disconnected from signaling\n MediaSessionDisconnectReason[\"PeerDisconnected\"] = \"PeerDisconnected\";\n MediaSessionDisconnectReason[\"PeerConnectionInterrupted\"] = \"PeerConnectionInterrupted\";\n MediaSessionDisconnectReason[\"PeerConnectionStateChangeTimeout\"] = \"PeerConnectionStateChangeTimeout\";\n MediaSessionDisconnectReason[\"InitiatorPeerReconnected\"] = \"InitiatorPeerReconnected\";\n MediaSessionDisconnectReason[\"PublishedStreamDestroyed\"] = \"PublishedStreamDestroyed\";\n MediaSessionDisconnectReason[\"ForcedByConsumer\"] = \"ForcedByConsumer\";\n MediaSessionDisconnectReason[\"SignalingChannelDisconnect\"] = \"SignalingChannelDisconnect\";\n})(MediaSessionDisconnectReason = exports.MediaSessionDisconnectReason || (exports.MediaSessionDisconnectReason = {}));\nvar MediaStreamUnregisterReason;\n(function (MediaStreamUnregisterReason) {\n MediaStreamUnregisterReason[\"NativeEvent\"] = \"NativeEvent\";\n MediaStreamUnregisterReason[\"ReplacingStream\"] = \"ReplacingStream\";\n MediaStreamUnregisterReason[\"ClosedRemotely\"] = \"ClosedRemotely\";\n MediaStreamUnregisterReason[\"ServiceCleanUp\"] = \"ServiceCleanUp\";\n})(MediaStreamUnregisterReason = exports.MediaStreamUnregisterReason || (exports.MediaStreamUnregisterReason = {}));\nexports.DEFAULT_VIDEO_RESOLUTION = '640x480';\nexports.DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;\nexports.DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;\nexports.DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;\nexports.DEFAULT_VIDEO_CONSTRAINTS = {\n resolution: exports.DEFAULT_VIDEO_RESOLUTION,\n constraintType: exports.DEFAULT_VIDEO_CONSTRAINT_TYPE\n};\nexports.POSSIBLE_LOOPBACK_RESOLUTIONS = [\n { resolution: '1920x1080', constraintType: ConstraintType.MIN },\n { resolution: '1280x720', constraintType: ConstraintType.MIN },\n exports.DEFAULT_VIDEO_CONSTRAINTS // fallback\n];\n\n//# sourceMappingURL=MediaConstants.js.map\n","import {VideoStreamResolution} from './MediaContracts';\n\nexport enum LocalVideoSourceType {\n CAMERA = 'CAMERA',\n CAMERA_FRONT = 'CAMERA_FRONT',\n DESKTOP_SHARE = 'DESKTOP_SHARE'\n}\n\nexport enum ConstraintType {\n MIN = 'min',\n IDEAL = 'ideal'\n}\n\nexport enum CameraTypes {\n FRONT = 'front',\n BACK = 'back'\n}\n\nexport enum MediaServiceType {\n OPENTOK = 'OPENTOK',\n TURNSERVER = 'TURN_SERVER',\n MEDIASERVER = 'MEDIA_SERVER'\n}\n\nexport enum SessionClientRole {\n AGENT = 'AGENT',\n OBSERVER = 'OBSERVER',\n USER = 'USER'\n}\n\nexport enum SessionClientType {\n INITIATOR = 'publisher',\n GUEST = 'subscriber'\n}\n\nexport enum MediaRequestErrorCode {\n Overconstrained = 'Overconstrained',\n PermissionDenied = 'PermissionDenied',\n GeneralError = 'GeneralError'\n}\n\nexport enum KnownMediaStreamKind {\n Audio = 'audio',\n Video = 'video'\n}\n\nexport enum KnownMediaStream {\n AGENT_AUDIO_STREAM = 'DASHBOARD_AUDIO_STREAM',\n OBSERVER_AUDIO_STREAM = 'OBSERVER_AUDIO_STREAM',\n USER_AUDIO_STREAM = 'MOBILE_CLIENT_AUDIO_STREAM',\n USER_VIDEO_STREAM = 'MOBILE_CLIENT_VIDEO_STREAM',\n USER_SCREEN_SHARE_STREAM = 'USER_SCREEN_SHARE_STREAM'\n}\n\nexport enum MediaSessionDisconnectReason {\n //Raised on initiator peer when guest peer was disconnected from signaling\n PeerDisconnected = 'PeerDisconnected',\n PeerConnectionInterrupted = 'PeerConnectionInterrupted',\n PeerConnectionStateChangeTimeout = 'PeerConnectionStateChangeTimeout',\n InitiatorPeerReconnected = 'InitiatorPeerReconnected',\n PublishedStreamDestroyed = 'PublishedStreamDestroyed',\n ForcedByConsumer = 'ForcedByConsumer',\n SignalingChannelDisconnect = 'SignalingChannelDisconnect'\n}\n\nexport enum MediaStreamUnregisterReason {\n NativeEvent = 'NativeEvent',\n ReplacingStream = 'ReplacingStream',\n ClosedRemotely = 'ClosedRemotely',\n ServiceCleanUp = 'ServiceCleanUp'\n}\n\nexport const DEFAULT_VIDEO_RESOLUTION = '640x480';\nexport const DEFAULT_VIDEO_CONSTRAINT_TYPE = ConstraintType.IDEAL;\nexport const DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS = 10;\nexport const DEFAULT_VIDEO_WAIT_TIMEOUT_SECONDS = 30;\n\nexport const DEFAULT_VIDEO_CONSTRAINTS: VideoStreamResolution = {\n resolution: DEFAULT_VIDEO_RESOLUTION,\n constraintType: DEFAULT_VIDEO_CONSTRAINT_TYPE\n};\n\nexport const POSSIBLE_LOOPBACK_RESOLUTIONS: VideoStreamResolution[] = [\n {resolution: '1920x1080', constraintType: ConstraintType.MIN}, // FHD\n {resolution: '1280x720', constraintType: ConstraintType.MIN}, // HD\n DEFAULT_VIDEO_CONSTRAINTS // fallback\n];\n"]}
@@ -43,6 +43,8 @@ export interface MediaSessionParams {
43
43
  clientType: SessionClientType;
44
44
  clientRole: SessionClientRole;
45
45
  credentials: MediaSessionIceCredentials;
46
+ initHandlers?: () => void;
47
+ removeHandlers?: () => void;
46
48
  }
47
49
  export interface MediaSessionConfiguration {
48
50
  peerConnectivityTimeoutSeconds: number;
@@ -96,11 +98,13 @@ export interface RemoteTrackStats {
96
98
  export interface IMediaSession {
97
99
  connect(connectOnly?: boolean): Promise<void>;
98
100
  disconnect(): Promise<void>;
101
+ sessionDisconnect(): void;
99
102
  getRemoteTrackStats(mediaTrack: MediaStreamTrack): Promise<RemoteTrackStats>;
100
103
  onMediaStreamDestroyed(clientRole: SessionClientRole): Promise<void>;
101
104
  onMediaStreamRenewed(clientRole: SessionClientRole, mediaStream: MediaStream): Promise<void>;
102
105
  replaceStreamTracks(mediaStream: Nullable<MediaStream>): Promise<void>;
103
106
  registerEventCallback(event: string, cb: (eventArgs: any) => void): void;
107
+ switchCamera?(clientRole: SessionClientRole): Promise<any>;
104
108
  }
105
109
  export interface RemoteMediaTrack {
106
110
  mediaTrack: MediaStreamTrack;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/MediaContracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,MAAM,CAAC;CAC9B;AAED,OAAO,EACH,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,4BAA4B,EAC5B,2BAA2B,EAC3B,iBAAiB,EACjB,iBAAiB,EACpB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,OAAO,GAAG,2BAA2B,CAAC;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,WAAW,2BAA2B;IACxC,eAAe,CAAC,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAAC;IACnD,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACtC,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,sBAAsB,CAAC;IACnC,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,qBAAqB,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACnC,qBAAqB,CAAC,eAAe,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;IAE1F,mBAAmB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjE,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,mBAAmB;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IAEnC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IAGxC,8BAA8B,CAAC,EAAE,MAAM,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,WAAW,EAAE,0BAA0B,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IAEtC,8BAA8B,EAAE,MAAM,CAAC;CAC1C;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,cAAc,CAAC;IAC1B,UAAU,EAAE,gBAAgB,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,eAAe,EAAE,iBAAiB,CAAC;CACtC;AAED,MAAM,WAAW,gBAAgB;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,6BAA6B,EAAE,OAAO,CAAC;IACvC,iCAAiC,EAAE,OAAO,CAAC;IAC3C,uBAAuB,EAAE,OAAO,CAAC;IACjC,2BAA2B,EAAE,OAAO,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAElC,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAE3C,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CACzC;AAED,oBAAY,0BAA0B,GAAG,GAAG,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACjC,qBAAqB,EAAE,+BAA+B,CAAC;CAC1D;AAED,oBAAY,+BAA+B,GAAG,CAAC,MAAM,EAAE,4BAA4B,KAAK,IAAI,CAAA;AAE5F,MAAM,WAAW,iBAAiB;IAC9B,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAE1B,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,mBAAmB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE7E,sBAAsB,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE,oBAAoB,CAAC,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7F,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvE,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,SAAS,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;CAC5E;AAED,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,CAAC;IACR,CAAC,CAAC,EAAE,GAAG,CAAC;IACR,CAAC,CAAC,EAAE,GAAG,CAAC;IACR,CAAC,CAAC,EAAE,GAAG,CAAC;CACX;AAED,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,EAAE,2BAA2B,CAAC;CACvC;AAED,MAAM,WAAW,sBAAsB;IACnC,UAAU,EAAE,gBAAgB,CAAC;CAChC","file":"MediaContracts.d.ts","sourcesContent":["import {Nullable} from '@techsee/techsee-common';\n\nexport interface IMediaEnvironment {\n isIOS: () => boolean;\n isIE11: () => boolean;\n majorVersion: () => number;\n}\n\nimport {\n ConstraintType,\n KnownMediaStream,\n LocalVideoSourceType,\n MediaRequestErrorCode,\n MediaServiceType,\n MediaSessionDisconnectReason,\n MediaStreamUnregisterReason,\n SessionClientRole,\n SessionClientType\n} from './MediaConstants';\n\nexport interface LocalMediaConstraints {\n video: boolean | LocalVideoStreamConstraints;\n audio?: boolean;\n}\n\nexport interface VideoStreamResolution {\n resolution: string;\n constraintType: ConstraintType;\n}\n\nexport interface LocalVideoStreamConstraints {\n videoResolution?: string | VideoStreamResolution[];\n videoSourceType?: LocalVideoSourceType;\n facingMode?: string;\n}\n\nexport interface MediaRequestSuccessResult {\n mediaStream: MediaStream;\n constraint: MediaStreamConstraints;\n constraintType: ConstraintType;\n isNew: boolean;\n}\n\nexport interface MediaRequestFailResult {\n message: string;\n errorCode: MediaRequestErrorCode;\n}\n\nexport interface ISessionStreamsManager {\n getMediaStreamForRole(destinationRole: SessionClientRole): Promise<Nullable<MediaStream>>;\n\n addRemoteMediaTrack(mediaTrack: RemoteMediaTrack): Promise<void>;\n\n removeMediaTrack(mediaTrack: MediaStreamTrack): Promise<void>;\n}\n\nexport interface MediaServiceOptions {\n mediaServiceType: MediaServiceType;\n //How much to wait until raise \"peerConnectionTimeout\" if WebRTC connection events not arriving\n peerConnectivityTimeoutSeconds?: number;\n\n //How much to wait totally for video stream to arrive, before making fallback to image upload\n videoNotReceivedTimeoutSeconds?: number;\n}\n\nexport interface MediaSessionParams {\n sessionId: string;\n clientType: SessionClientType;\n clientRole: SessionClientRole;\n credentials: MediaSessionIceCredentials;\n}\n\nexport interface MediaSessionConfiguration {\n //How much to wait until raise \"peerConnectionTimeout\" if WebRTC connection events not arriving\n peerConnectivityTimeoutSeconds: number;\n}\n\nexport interface MediaSubscriberParams {\n container: HTMLDivElement;\n streamType: KnownMediaStream;\n}\n\nexport interface MediaPublisherParams {\n streamTypes: KnownMediaStream[];\n destinationRole: SessionClientRole;\n}\n\nexport interface ClientWebRtcInfo {\n isWebRTCSupported: boolean;\n isWebsiteHasWebcamPermissions: boolean;\n isWebsiteHasMicrophonePermissions: boolean;\n isGetUserMediaSupported: boolean;\n isApplyConstraintsSupported: boolean;\n}\n\nexport interface IMediaSubscriber {\n readonly streamType: KnownMediaStream;\n readonly container: HTMLDivElement;\n readonly isPlaying: boolean;\n readonly isSoundMuted: boolean;\n readonly hasAudio: boolean;\n readonly hasVideo: boolean;\n readonly mediaElement: Nullable<HTMLVideoElement>;\n readonly videoWidth: number;\n readonly videoHeight: number;\n readonly renderWidth: number;\n readonly renderHeight: number;\n\n muteSound(isMuted: boolean): void;\n\n onStateChanged(callback: () => void): void;\n\n onDispose(callback: () => void): void;\n}\n\nexport type MediaSessionIceCredentials = any;//TODO - Define type for credentials\n\nexport interface MediaSessionHandlers {\n onDisconnectedHandler: MediaSessionDisconnectedHandler;\n}\n\nexport type MediaSessionDisconnectedHandler = (reason: MediaSessionDisconnectReason) => void\n\nexport interface DeviceSupportInfo {\n webRtcSupportInfo: ClientWebRtcInfo;\n hasCamera: boolean;\n hasMicrophone: boolean;\n videoPlayback: boolean;\n}\n\nexport interface RemoteTrackStats {\n trackId: string;\n trackStats: any;\n}\n\nexport interface IMediaSession {\n //Boolean parameter is used for supporting \"RTC Test\" application\n connect(connectOnly?: boolean): Promise<void>;\n\n disconnect(): Promise<void>;\n\n getRemoteTrackStats(mediaTrack: MediaStreamTrack): Promise<RemoteTrackStats>;\n\n onMediaStreamDestroyed(clientRole: SessionClientRole): Promise<void>;\n\n onMediaStreamRenewed(clientRole: SessionClientRole, mediaStream: MediaStream): Promise<void>;\n\n replaceStreamTracks(mediaStream: Nullable<MediaStream>): Promise<void>;\n\n registerEventCallback(event: string, cb: (eventArgs: any) => void): void;\n}\n\nexport interface RemoteMediaTrack {\n mediaTrack: MediaStreamTrack;\n trackType: KnownMediaStream;\n isRegistered: boolean;\n}\n\nexport interface SnapshotResult {\n base64img: string;\n objectUrl: string;\n imageBlob: Blob;\n mimeType: string;\n}\n\nexport interface SnapshotOptions {\n format?: string;\n quality?: number;\n x?: any;\n y?: any;\n w?: any;\n h?: any;\n}\n\nexport interface StreamDestroyedEventArgs {\n streamType: KnownMediaStream;\n reason: MediaStreamUnregisterReason;\n}\n\nexport interface StreamCreatedEventArgs {\n streamType: KnownMediaStream;\n}\n"]}
1
+ {"version":3,"sources":["../src/MediaContracts.ts"],"names":[],"mappings":"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","file":"MediaContracts.d.ts","sourcesContent":["import {Nullable} from '@techsee/techsee-common';\n\nexport interface IMediaEnvironment {\n isIOS: () => boolean;\n isIE11: () => boolean;\n majorVersion: () => number;\n}\n\nimport {\n ConstraintType,\n KnownMediaStream,\n LocalVideoSourceType,\n MediaRequestErrorCode,\n MediaServiceType,\n MediaSessionDisconnectReason,\n MediaStreamUnregisterReason,\n SessionClientRole,\n SessionClientType\n} from './MediaConstants';\n\nexport interface LocalMediaConstraints {\n video: boolean | LocalVideoStreamConstraints;\n audio?: boolean;\n}\n\nexport interface VideoStreamResolution {\n resolution: string;\n constraintType: ConstraintType;\n}\n\nexport interface LocalVideoStreamConstraints {\n videoResolution?: string | VideoStreamResolution[];\n videoSourceType?: LocalVideoSourceType;\n facingMode?: string;\n}\n\nexport interface MediaRequestSuccessResult {\n mediaStream: MediaStream;\n constraint: MediaStreamConstraints;\n constraintType: ConstraintType;\n isNew: boolean;\n}\n\nexport interface MediaRequestFailResult {\n message: string;\n errorCode: MediaRequestErrorCode;\n}\n\nexport interface ISessionStreamsManager {\n getMediaStreamForRole(destinationRole: SessionClientRole): Promise<Nullable<MediaStream>>;\n\n addRemoteMediaTrack(mediaTrack: RemoteMediaTrack): Promise<void>;\n\n removeMediaTrack(mediaTrack: MediaStreamTrack): Promise<void>;\n}\n\nexport interface MediaServiceOptions {\n mediaServiceType: MediaServiceType;\n //How much to wait until raise \"peerConnectionTimeout\" if WebRTC connection events not arriving\n peerConnectivityTimeoutSeconds?: number;\n\n //How much to wait totally for video stream to arrive, before making fallback to image upload\n videoNotReceivedTimeoutSeconds?: number;\n}\n\nexport interface MediaSessionParams {\n sessionId: string;\n clientType: SessionClientType;\n clientRole: SessionClientRole;\n credentials: MediaSessionIceCredentials;\n initHandlers?: () => void;\n removeHandlers?: () => void;\n}\n\nexport interface MediaSessionConfiguration {\n //How much to wait until raise \"peerConnectionTimeout\" if WebRTC connection events not arriving\n peerConnectivityTimeoutSeconds: number;\n}\n\nexport interface MediaSubscriberParams {\n container: HTMLDivElement;\n streamType: KnownMediaStream;\n}\n\nexport interface MediaPublisherParams {\n streamTypes: KnownMediaStream[];\n destinationRole: SessionClientRole;\n}\n\nexport interface ClientWebRtcInfo {\n isWebRTCSupported: boolean;\n isWebsiteHasWebcamPermissions: boolean;\n isWebsiteHasMicrophonePermissions: boolean;\n isGetUserMediaSupported: boolean;\n isApplyConstraintsSupported: boolean;\n}\n\nexport interface IMediaSubscriber {\n readonly streamType: KnownMediaStream;\n readonly container: HTMLDivElement;\n readonly isPlaying: boolean;\n readonly isSoundMuted: boolean;\n readonly hasAudio: boolean;\n readonly hasVideo: boolean;\n readonly mediaElement: Nullable<HTMLVideoElement>;\n readonly videoWidth: number;\n readonly videoHeight: number;\n readonly renderWidth: number;\n readonly renderHeight: number;\n\n muteSound(isMuted: boolean): void;\n\n onStateChanged(callback: () => void): void;\n\n onDispose(callback: () => void): void;\n}\n\nexport type MediaSessionIceCredentials = any;//TODO - Define type for credentials\n\nexport interface MediaSessionHandlers {\n onDisconnectedHandler: MediaSessionDisconnectedHandler;\n}\n\nexport type MediaSessionDisconnectedHandler = (reason: MediaSessionDisconnectReason) => void\n\nexport interface DeviceSupportInfo {\n webRtcSupportInfo: ClientWebRtcInfo;\n hasCamera: boolean;\n hasMicrophone: boolean;\n videoPlayback: boolean;\n}\n\nexport interface RemoteTrackStats {\n trackId: string;\n trackStats: any;\n}\n\nexport interface IMediaSession {\n //Boolean parameter is used for supporting \"RTC Test\" application\n connect(connectOnly?: boolean): Promise<void>;\n\n disconnect(): Promise<void>;\n\n sessionDisconnect(): void;\n\n getRemoteTrackStats(mediaTrack: MediaStreamTrack): Promise<RemoteTrackStats>;\n\n onMediaStreamDestroyed(clientRole: SessionClientRole): Promise<void>;\n\n onMediaStreamRenewed(clientRole: SessionClientRole, mediaStream: MediaStream): Promise<void>;\n\n replaceStreamTracks(mediaStream: Nullable<MediaStream>): Promise<void>;\n\n registerEventCallback(event: string, cb: (eventArgs: any) => void): void;\n\n switchCamera?(clientRole: SessionClientRole): Promise<any>;\n}\n\nexport interface RemoteMediaTrack {\n mediaTrack: MediaStreamTrack;\n trackType: KnownMediaStream;\n isRegistered: boolean;\n}\n\nexport interface SnapshotResult {\n base64img: string;\n objectUrl: string;\n imageBlob: Blob;\n mimeType: string;\n}\n\nexport interface SnapshotOptions {\n format?: string;\n quality?: number;\n x?: any;\n y?: any;\n w?: any;\n h?: any;\n}\n\nexport interface StreamDestroyedEventArgs {\n streamType: KnownMediaStream;\n reason: MediaStreamUnregisterReason;\n}\n\nexport interface StreamCreatedEventArgs {\n streamType: KnownMediaStream;\n}\n"]}
@@ -17,6 +17,7 @@ export declare abstract class TechseeMediaServiceBase {
17
17
  private readonly _publisherPromises;
18
18
  protected _serviceOptions: Nullable<MediaServiceOptions>;
19
19
  private _isIOS_13_orLater;
20
+ private _isIOS_14_orLater;
20
21
  private _autoReconnectEnabled;
21
22
  private readonly _emitter;
22
23
  private _initLocalStreamsPromise;
@@ -42,6 +43,7 @@ export declare abstract class TechseeMediaServiceBase {
42
43
  switchCamera(revertCameraWhenFailed?: boolean): Promise<any>;
43
44
  private replaceStreamTracks;
44
45
  protected registerStreamResult(constraints: Nullable<LocalMediaConstraints>, streamResult: MediaRequestSuccessResult, switchCamera?: boolean, addStreamType?: KnownMediaStream): Promise<any[]>;
46
+ disconnectFromMediaSession(): void;
45
47
  readonly supportSwitchCameras: boolean;
46
48
  private _connectToSession;
47
49
  connectToSession(sessionParams: MediaSessionParams): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/MediaServiceBase.ts"],"names":[],"mappings":"AAMA,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAC,sBAAsB,EAAC,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EACH,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAEjB,gBAAgB,EAChB,sBAAsB,EAAE,qBAAqB,EAErB,yBAAyB,EACjD,mBAAmB,EAGnB,0BAA0B,EAC1B,kBAAkB,EAClB,qBAAqB,EAErB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EAC3B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAEH,gBAAgB,EAIhB,4BAA4B,EAE5B,iBAAiB,EACpB,MAAM,kBAAkB,CAAC;AAa1B,8BAAsB,uBAAuB;IAGzC,SAAS,CAAC,QAAQ,CAAC,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/D,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,eAAe,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAErH,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACnD,SAAS,CAAC,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB,CAAC;IAClE,SAAS,CAAC,QAAQ,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;IAE5D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAoB;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0D;IACvF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4D;IACxF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqE;IACxG,SAAS,CAAC,eAAe,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAQ;IAChE,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,qBAAqB,CAAiB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,wBAAwB,CAAiC;IACjE,OAAO,CAAC,mBAAmB,CAAiC;IAC5D,OAAO,CAAC,kBAAkB,CAAwD;IAClF,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAIN;IAEV,SAAS,aAAa,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB;aA8BrF,iBAAiB,EAAI,iBAAiB;aAMtC,aAAa,EAAI,OAAO;aAIxB,eAAe,EAAI,OAAO;aAI1B,wBAAwB,EAAI,OAAO;IASvC,gBAAgB,CAAC,cAAc,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CpE,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBtC,gBAAgB,CAAC,gBAAgB,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuBpF,iBAAiB,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3D,iBAAiB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,wBAAwB,KAAK,IAAI,GAAG,IAAI;IAIhF,eAAe,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,sBAAsB,KAAK,IAAI,GAAG,IAAI;IAI5E,eAAe,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAMzD,eAAe,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAMzD,cAAc,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAMxD,OAAO,CAAC,0BAA0B;IAoBlC,YAAY,CAAC,sBAAsB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;IAsC5D,OAAO,CAAC,mBAAmB;IAQ3B,SAAS,CAAC,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,YAAY,EAAE,yBAAyB,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,gBAAgB;aAkB1K,oBAAoB;IAIxB,OAAO,CAAC,iBAAiB;IA4EzB,gBAAgB,CAAC,aAAa,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlE,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC,wBAAwB,CAAC,WAAW,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhF,uBAAuB,IAAI,IAAI;IAQ/B,SAAS,CAAC,6BAA6B,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5F,SAAS,CAAC,sBAAsB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsBzF,OAAO,CAAC,0BAA0B;IA0BlC,gBAAgB,CAAC,KAAK,EAAE,OAAO;IAc/B,kBAAkB,CAAC,UAAU,EAAE,kBAAkB;IAgBjD,0BAA0B,CAAC,YAAY,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAqDtH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAc7B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;uBAUV,WAAW,EAAI,GAAG,CAAC,cAAc,EAAE,sBAAsB,CAAC;IAIxE,SAAS,CAAC,wBAAwB,CAAC,aAAa,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASpF,SAAS,CAAC,yBAAyB,CAAC,UAAU,EAAE,gBAAgB,GAAG,QAAQ,CAAC,kBAAkB,CAAC;IAI/F,SAAS,CAAC,0BAA0B,CAAC,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAoB3F,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIzF,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,GAAG,IAAI;IAUzD,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,4BAA4B;IAoCpC,OAAO,CAAC,0BAA0B;IAYlC,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,2BAA2B;IAyCnC,OAAO,CAAC,8BAA8B;IAmBtC,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,eAAe;IAevB,SAAS,CAAC,gBAAgB,CAAC,WAAW,UAAO,GAAG,OAAO;IAIvD,SAAS,CAAC,kBAAkB,CAAC,WAAW,UAAO,GAAG,OAAO;CAO5D","file":"MediaServiceBase.d.ts","sourcesContent":["import filter from 'lodash/filter';\nimport cloneDeep from 'lodash/cloneDeep';\nimport values from 'lodash/values';\nimport debounce from 'lodash/debounce';\nimport includes from 'lodash/includes';\nimport {EventEmitter} from 'events';\nimport {Nullable} from '@techsee/techsee-common';\nimport {TechseeMediaSubscriber} from './MediaSubscriber';\nimport {TechseeMediaPublisher} from './MediaPublisher';\nimport {LocalStreamManager} from './LocalStreamManager';\nimport {TechseeMediaStream} from './TechseeMediaStream';\nimport {TurnWebRtcSession} from './MediaSession/SessionTurn';\nimport {getSnapshotFromMediaStream} from './MediaUtils/MediaDomUtils';\nimport {\n ClientWebRtcInfo,\n DeviceSupportInfo,\n IMediaEnvironment,\n IMediaSession,\n IMediaSubscriber,\n ISessionStreamsManager, LocalMediaConstraints,\n LocalVideoStreamConstraints,\n MediaRequestFailResult, MediaRequestSuccessResult,\n MediaServiceOptions,\n MediaSessionConfiguration,\n MediaSessionHandlers,\n MediaSessionIceCredentials,\n MediaSessionParams,\n MediaSubscriberParams,\n RemoteMediaTrack,\n RemoteTrackStats,\n SnapshotOptions,\n SnapshotResult,\n StreamCreatedEventArgs,\n StreamDestroyedEventArgs\n} from './MediaContracts';\nimport {enumerateMediaDevices, isVideoPlaySupportedOnDevice} from './MediaUtils/Compatibility';\nimport {OpentokSession} from './MediaSession/SessionOpentok';\nimport {\n DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS,\n KnownMediaStream,\n KnownMediaStreamKind,\n LocalVideoSourceType,\n MediaServiceType,\n MediaSessionDisconnectReason,\n MediaStreamUnregisterReason,\n SessionClientRole\n} from './MediaConstants';\nimport {throwableGuard} from '@techsee/techsee-common/lib/core/guards';\nimport {MediaServerSession, recordingEvents} from './MediaSession/MediaServer';\nimport {getMediaTracer} from './MediaUtils/MediaTracer';\n\nconst trace = getMediaTracer('MediaServiceBase');\nconst traceStatsInfo = debounce(trace.info, 1000 * 5, {leading: true, maxWait: 1000 * 30});\n\nenum privateEvents {\n STREAM_CREATED = 'STREAM_CREATED',\n STREAM_DESTROYED = 'STREAM_DESTROYED'\n}\n\nexport abstract class TechseeMediaServiceBase {\n //This method should not be called. The only place that allowed to use it, is initLocalMediaStreams method.\n //Everyone who need to initialize MediaStream should use initLocalMediaStreams method.\n protected abstract getLocalMediaImplementation(): Promise<void>;\n\n protected abstract createMediaPublisher(destinationRole: SessionClientRole): Promise<Nullable<TechseeMediaPublisher>>;\n\n protected readonly _environment: IMediaEnvironment;\n protected readonly _sessionStreamsManager: ISessionStreamsManager;\n protected readonly _localStreamsManager: LocalStreamManager;\n\n private readonly _deviceSupportFlags: DeviceSupportInfo;\n private readonly _subscribers: Map<HTMLDivElement, TechseeMediaSubscriber> = new Map();\n private readonly _publishers: Map<SessionClientRole, TechseeMediaPublisher> = new Map();\n private readonly _publisherPromises: Map<SessionClientRole, Promise<Nullable<MediaStream>>> = new Map();\n protected _serviceOptions: Nullable<MediaServiceOptions> = null;\n private _isIOS_13_orLater: boolean = false;\n private _autoReconnectEnabled: boolean = true;\n private readonly _emitter: EventEmitter;\n private _initLocalStreamsPromise: Nullable<Promise<void>> = null;\n private _initServicePromise: Nullable<Promise<void>> = null;\n private _registeredStreams: Map<KnownMediaStream, TechseeMediaStream> = new Map();\n private _isVoipEnabled: boolean = false;\n private _session: Nullable<{\n params: MediaSessionParams;\n connectPromise?: Promise<void>;\n instance?: IMediaSession;\n }> = null;\n\n protected constructor(environment: IMediaEnvironment, webRtcSupportInfo: ClientWebRtcInfo) {\n trace.info('TechseeMediaServiceBase created');\n\n this.bindClassMethods();\n\n this._emitter = new EventEmitter();\n this._environment = environment;\n this._deviceSupportFlags = {\n videoPlayback: false,\n hasCamera: false,\n hasMicrophone: false,\n webRtcSupportInfo: webRtcSupportInfo\n };\n\n this._localStreamsManager = new LocalStreamManager(this._environment);\n\n // TODO: Hack as IOS 13.3 and above sometimes do not return the video/audio device. This\n // is a hack to work around the issue until Apple resolve it\n this._isIOS_13_orLater = this._environment.isIOS() &&\n (!this._environment.majorVersion() || (this._environment.majorVersion() >= 13));\n\n trace.info(`TechseeMediaServiceBase: isIOS_13_orLater: ${this._isIOS_13_orLater}`);\n\n this._sessionStreamsManager = {\n getMediaStreamForRole: this.getStreamForDestinationRole,\n addRemoteMediaTrack: this.registerRemoteMediaTrack,\n removeMediaTrack: this.unregisterRemoteMediaTrack\n };\n }\n\n get deviceSupportInfo(): DeviceSupportInfo {\n this.serviceInitGuard(false);\n\n return cloneDeep(this._deviceSupportFlags);\n }\n\n get isVoipEnabled(): boolean {\n return this._isVoipEnabled;\n }\n\n get isSessionActive(): boolean {\n return this._session !== null;\n }\n\n get isLocalStreamInitialized(): boolean {\n return this._initLocalStreamsPromise !== null;\n }\n\n /*\n Initializes media service. Before using anything from this service it should be initialized first.\n All of serviceOptions should be retrieved from account settings and by evaluating application state.\n For example, when initializing service, accountSettings is already loaded, and we know if FS session is audio enabled.\n */\n initMediaService(serviceOptions: MediaServiceOptions): Promise<void> {\n trace.info('TechseeMediaServiceBase.initMediaService', serviceOptions);\n const warnMessage = 'Multiple initialization does not supposed to happen. Not rejecting, but check the flow for correctness.';\n\n if (this._initServicePromise || this._serviceOptions) {\n console.warn(warnMessage);\n\n return this._initServicePromise ? this._initServicePromise : Promise.resolve();\n }\n\n this._serviceOptions = cloneDeep(serviceOptions);\n this._initServicePromise = Promise.all([\n isVideoPlaySupportedOnDevice(this._serviceOptions.mediaServiceType)\n .then((isSupported: boolean) => this._deviceSupportFlags.videoPlayback = isSupported),\n enumerateMediaDevices()\n .catch((error) => {\n trace.warn(error);\n\n return [];\n })\n .then((localDevicesList: MediaDeviceInfo[]) => {\n const groupedDevices = {\n video: filter(localDevicesList, (device) => device.kind.toLowerCase() === 'videoinput'),\n audio: filter(localDevicesList, (device) => device.kind.toLowerCase() === 'audioinput')\n };\n\n this._localStreamsManager.setGroupedDevices(groupedDevices);\n this._deviceSupportFlags.hasCamera = this._isIOS_13_orLater || (groupedDevices.video.length > 0);\n this._deviceSupportFlags.hasMicrophone = this._isIOS_13_orLater || (groupedDevices.audio.length > 0);\n\n })\n ]).then(() => undefined);\n\n\n return this._initServicePromise;\n }\n\n //#region Media Streams Management\n\n /*\n The main method to start the initialization of local media streams.\n This method can be executed many times and it will insure all calls are synced and only relevant stream will be created.\n DO NOT USE ANY OTHER METHOD THAT FORCES \"navigator.getUserMedia\" OTHER THAN THIS ONE.\n */\n initLocalMediaStreams(): Promise<void> {\n this.serviceInitGuard();\n\n if (!this._initLocalStreamsPromise) {\n trace.info('initLocalMediaStreams creating media streams');\n this._initLocalStreamsPromise = this.getLocalMediaImplementation()\n .catch((mediaRequestFailResult: MediaRequestFailResult) => {\n trace.error('initLocalMediaStreams failure: ', mediaRequestFailResult);\n\n throw mediaRequestFailResult;\n });\n } else {\n trace.info('initLocalMediaStreams already done or in progress');\n }\n\n return this._initLocalStreamsPromise;\n }\n\n /*\n Creates an instance of subscriber that will \"listen\" to the requested stream.\n Whenever requested stream is available, subscriber will render it.\n */\n createSubscriber(subscriberParams: MediaSubscriberParams): Promise<IMediaSubscriber> {\n if (this._subscribers.has(subscriberParams.container)) {\n return Promise.reject('Subscriber for provided DIV element already exists');\n }\n\n const subscriber = new TechseeMediaSubscriber(subscriberParams);\n\n this._subscribers.set(subscriberParams.container, subscriber);\n const streamForSubscriber = this.getRegisteredStreamByType(subscriber.streamType);\n\n if (streamForSubscriber) {\n trace.info(`Stream for ${subscriberParams.streamType} is ready.`);\n subscriber.renderStream(streamForSubscriber);\n } else {\n trace.info(`Stream for ${subscriberParams.streamType} not created yet`);\n }\n\n return Promise.resolve(subscriber);\n }\n\n /*\n Destroys the subscriber for provided HTML DIV container\n */\n destroySubscriber(container: HTMLDivElement): Promise<void> {\n if (this._subscribers.has(container)) {\n const subscriber = this._subscribers.get(container);\n\n subscriber!.dispose();\n }\n\n this._subscribers.delete(container);\n\n return Promise.resolve();\n }\n\n onStreamDestroyed(callback: (eventArgs: StreamDestroyedEventArgs) => void): void {\n this.registerEventCallback(privateEvents.STREAM_DESTROYED, callback);\n }\n\n onStreamCreated(callback: (eventArgs: StreamCreatedEventArgs) => void): void {\n this.registerEventCallback(privateEvents.STREAM_CREATED, callback);\n }\n\n onRecordStarted(callback: (eventArgs: any) => void): void {\n if (this._session && this._session.instance) {\n this._session.instance.registerEventCallback(recordingEvents.RECORD_STARTED, callback);\n }\n }\n\n onRecordStopped(callback: (eventArgs: any) => void): void {\n if (this._session && this._session.instance) {\n this._session.instance.registerEventCallback(recordingEvents.RECORD_STOPPED, callback);\n }\n }\n\n onReconnecting(callback: (eventArgs: any) => void): void {\n if (this._session && this._session.instance) {\n this._session.instance.registerEventCallback(recordingEvents.RECONNECTING, callback);\n }\n }\n\n private getSwitchCameraConstraints() {\n const constraints = cloneDeep(window.latestLocalMediaConstraints);\n\n if (!constraints) {\n throw new Error('getSwitchCameraConstraints: unexpected use case constraints is null.');\n }\n\n trace.info('getSwitchCameraConstraints - Start switch camera with constraints:', constraints);\n\n const videoSourceType = (constraints.video as LocalVideoStreamConstraints).videoSourceType === LocalVideoSourceType.CAMERA\n ? LocalVideoSourceType.CAMERA_FRONT\n : LocalVideoSourceType.CAMERA;\n\n trace.info(`getSwitchCameraConstraints - switch to videoSourceType: ${videoSourceType}`);\n\n (constraints.video as LocalVideoStreamConstraints).videoSourceType = videoSourceType;\n\n return constraints;\n }\n\n switchCamera(revertCameraWhenFailed?: boolean): Promise<any> {\n trace.info('switchCamera: start');\n\n const latestLocalMediaConstraints = cloneDeep(window.latestLocalMediaConstraints);\n const constraints = !revertCameraWhenFailed ? this.getSwitchCameraConstraints() : latestLocalMediaConstraints;\n\n if (!constraints) {\n throw new Error('switchCamera - unexpected use case constraints is null.');\n }\n\n return this._localStreamsManager.destroyUserMediaStream()\n .then(() => this._localStreamsManager.getUserMediaStream(constraints)\n .then((streamResult: MediaRequestSuccessResult) => {\n const stream = streamResult.mediaStream;\n\n trace.info('switchCamera: new stream: ', stream);\n\n return this.replaceStreamTracks(stream)\n .then(() => this.registerStreamResult(constraints, streamResult, true)\n .then(() => ({\n revertCameraWhenFailed,\n constraints,\n streamResult\n })));\n }))\n .catch((err) => {\n trace.error('switchCamera: Failed to switch camera: ', err);\n\n if (!revertCameraWhenFailed) {\n window.latestLocalMediaConstraints = latestLocalMediaConstraints;\n\n return this.switchCamera(true);\n }\n\n return Promise.reject('Failed to switch camera.');\n });\n }\n\n private replaceStreamTracks(mediaStream: Nullable<MediaStream>): Promise<void> {\n if (this._session!.instance) {\n return this._session!.instance.replaceStreamTracks(mediaStream);\n }\n\n return Promise.reject('replaceStreamTracks - session instance is not exists.');\n }\n\n protected registerStreamResult(constraints: Nullable<LocalMediaConstraints>, streamResult: MediaRequestSuccessResult, switchCamera?: boolean, addStreamType?: KnownMediaStream) {\n const regPromises: any[] = [];\n\n if (streamResult.isNew) {\n trace.info('registerStreamResult: stream result from getUserMediaStream:', streamResult.mediaStream);\n streamResult.mediaStream.getTracks().forEach((mediaTrack) => {\n trace.info('registerStreamResult: stream result from mediaTrack:', mediaTrack);\n const streamType = addStreamType || (mediaTrack.kind === 'video'\n ? KnownMediaStream.USER_VIDEO_STREAM : KnownMediaStream.USER_AUDIO_STREAM);\n const newDedicatedStream = new TechseeMediaStream(mediaTrack, streamType, false);\n\n regPromises.push(switchCamera ? this.registerTrack(newDedicatedStream) : this.registerLocalMediaStream(newDedicatedStream));\n });\n }\n\n return Promise.all(regPromises);\n }\n\n get supportSwitchCameras() {\n return this._isIOS_13_orLater || this._localStreamsManager.groupedDevices.camerasCount > 1;\n }\n\n private _connectToSession(sessionParams: MediaSessionParams): Promise<void> {\n this.serviceInitGuard();\n\n if (!this._session) {\n this._session = {params: cloneDeep(sessionParams)};\n this._session.connectPromise = new Promise((resolve, reject) => {\n const doAsyncReject = (error: any): void => {\n\n /*\n Reject with timeout, to change JS 'execution flow'.\n If timeout removed, session is assigned to null, before promise returns, and \"catch\" will not\n work on promise that is returned.\n */\n setTimeout(() => {\n this._session = null;\n reject(error);\n });\n };\n\n const sessionHandlers: MediaSessionHandlers = {\n onDisconnectedHandler: this.onSessionDisconnectHandler\n };\n const mediaSessionParams: MediaSessionParams & MediaSessionConfiguration = {\n ...sessionParams,\n peerConnectivityTimeoutSeconds: this._serviceOptions!.peerConnectivityTimeoutSeconds || DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS\n };\n\n trace.info('connectToSession', sessionParams);\n\n const allowedValues = values(MediaServiceType);\n\n switch (this._serviceOptions!.mediaServiceType) {\n case MediaServiceType.TURNSERVER:\n this._session!.instance = new TurnWebRtcSession(mediaSessionParams, sessionHandlers, this._sessionStreamsManager);\n break;\n case MediaServiceType.OPENTOK:\n this._session!.instance = new OpentokSession(mediaSessionParams, this._sessionStreamsManager);\n break;\n case MediaServiceType.MEDIASERVER:\n this._session!.instance = new MediaServerSession(mediaSessionParams, this._sessionStreamsManager);\n break;\n default:\n trace.error(`mediaServiceType '${this._serviceOptions!.mediaServiceType}' is not supported.`, {allowedValues});\n doAsyncReject(new Error('mediaServiceType is not supported'));\n }\n\n if (this._session && this._session.instance) {\n this._session!.instance.connect()\n .then(() => {\n trace.info('Session is connected');\n resolve();\n })\n .catch((error: any) => {\n trace.error('Failed to connect to session', error);\n doAsyncReject(error);\n });\n }\n\n });\n } else {\n trace.warn('Session connected already. Disconnect before connect to new session again');\n }\n\n //TODO - Alex: Change a structure of this function to be more safe\n //(when we return, there should not be case when session or promise is null)\n //To fix, need to return promise immediately, then execute process in setTimeout(fn, 0);\n return this._session!.connectPromise!;\n }\n\n //#endregion Media Streams Management\n\n //#region Session Management\n\n /*\n Creates instance of WebRTC session which connects to (signaling server), and begins to listen to WebRTC events.\n */\n connectToSession(sessionParams: MediaSessionParams): Promise<void> {\n return this._connectToSession(sessionParams);\n }\n\n /*\n Disconnects from WebRTC session.\n */\n disconnectFromSession(): Promise<void> {\n return this.disconnectFromSessionInternal(MediaSessionDisconnectReason.ForcedByConsumer);\n }\n\n /*\n Updates a credentials for turn server\n */\n updateSessionCredentials(credentials: MediaSessionIceCredentials): Promise<void> {\n trace.info('updateSessionCredentials');\n if (!this.sessionExistsGuard(false)) {\n return Promise.reject('There no session to update credentials');\n }\n\n this._session!.params.credentials = cloneDeep(credentials);\n\n return Promise.resolve();\n }\n\n enableVoipDuringSession(): void {\n if (!this._isVoipEnabled && this.isLocalStreamInitialized) {\n throw new Error('Voip support cannot be enabled after local stream where initialized');\n }\n\n this._isVoipEnabled = true;\n }\n\n protected disconnectFromSessionInternal(reason: MediaSessionDisconnectReason): Promise<void> {\n if (!this._session) {\n return Promise.resolve();\n }\n\n trace.info('Disconnecting from session', reason);\n\n const lastSession = this._session;\n\n this._session = null;\n\n return Promise.all([\n lastSession.instance!.disconnect(),\n this.clearPublishers()\n ]).then(() => undefined);\n }\n\n protected getStatsForRemoteTrack(streamType: KnownMediaStream): Promise<RemoteTrackStats> {\n if (!this.sessionExistsGuard(false)) {\n return Promise.reject(new Error('Media session not started'));\n }\n\n const streamForStats = this.getRegisteredStreamByType(streamType);\n\n if (!streamForStats) {\n return Promise.reject(new Error('Stream for requested type was not found'));\n }\n\n return this._session!.instance!.getRemoteTrackStats(streamForStats.mediaTrack)\n .then((trackStats: RemoteTrackStats) => {\n traceStatsInfo(`MediaTrackStats for ${streamType}: ${JSON.stringify(trackStats)}`);\n\n return {\n trackId: streamForStats.mediaTrack.id,\n trackStats: trackStats\n };\n });\n }\n\n private onSessionDisconnectHandler(reason: MediaSessionDisconnectReason): void {\n trace.info('onSessionDisconnectHandler', reason);\n if (reason !== MediaSessionDisconnectReason.ForcedByConsumer) {\n const lastParams = this._session && this._session.params ? this._session.params : null;\n\n this.disconnectFromSessionInternal(reason).then(() => {\n const reconnectReasons = [\n MediaSessionDisconnectReason.InitiatorPeerReconnected,\n MediaSessionDisconnectReason.SignalingChannelDisconnect,\n MediaSessionDisconnectReason.PeerConnectionInterrupted,\n MediaSessionDisconnectReason.PeerConnectionStateChangeTimeout\n ];\n\n if (lastParams && includes(reconnectReasons, reason) && this._autoReconnectEnabled) {\n this.reconnectToSession(lastParams);\n } else if (!this._autoReconnectEnabled) {\n trace.info('No reconnection- auto reconnect disabled');\n } else {\n trace.info('No params for reconnection to media session');\n }\n });\n } else {\n trace.info('Ignore Session disconnect event');\n }\n }\n\n setAutoReconnect(state: boolean) {\n this._autoReconnectEnabled = state;\n trace.info('_autoReconnectEnabled:', state);\n\n if (this._autoReconnectEnabled && !this.isSessionActive) {\n const lastParams = this._session && this._session.params ? this._session.params : null;\n\n if (lastParams) {\n trace.info('setAutoReconnect - reconnect to session');\n this.reconnectToSession(lastParams);\n }\n }\n }\n\n reconnectToSession(lastParams: MediaSessionParams) {\n trace.info('Reconnecting to media session, sessionParams:', lastParams);\n\n this._connectToSession(lastParams)\n .then(() => {\n trace.info('Media session reconnected');\n })\n .catch((error: any) => {\n trace.error('Error while reconnecting to media session', error);\n });\n }\n\n //#endregion Session Management\n\n //#region Utils\n\n getSnapshotFromKnownStream(sourceStream: KnownMediaStream, snapshotOptions?: SnapshotOptions): Promise<SnapshotResult> {\n return new Promise((resolve, reject) => {\n if (sourceStream !== KnownMediaStream.USER_VIDEO_STREAM &&\n sourceStream !== KnownMediaStream.USER_SCREEN_SHARE_STREAM) {\n trace.error('The requested stream is not video stream, and cannot be used for snapshot');\n reject(new Error('INCOMPATIBLE_STREAM_FOR_SNAPSHOT'));\n\n return;\n }\n\n const snapshotStream = this.getRegisteredStreamByType(sourceStream);\n\n if (!snapshotStream) {\n trace.error('Cannot make snapshot: The requested stream not exists yet.');\n reject(new Error('NO_REQUESTED_STREAM'));\n\n return;\n }\n\n getSnapshotFromMediaStream(snapshotStream.mediaStream, snapshotOptions)\n .then((imageData: any) => {\n const urlComponents = imageData.split(';base64,');\n const mimeType = urlComponents[0].split(':')[1];\n const bytes = atob(urlComponents[1]);\n const buffer = new ArrayBuffer(bytes.length);\n const rawData = new Uint8Array(buffer);\n\n for (let i = 0; i < bytes.length; i++) {\n rawData[i] = bytes.charCodeAt(i);\n }\n\n const blob = new Blob([rawData], {type: mimeType});\n const objectUrl = window.URL.createObjectURL(blob);\n\n trace.info('Snapshot created successfully');\n\n const result: SnapshotResult = {\n base64img: imageData,\n objectUrl: objectUrl,\n imageBlob: blob,\n mimeType: mimeType\n };\n\n resolve(result);\n })\n .catch((error: any) => {\n trace.error('Error creating snapshot', error);\n reject(error);\n });\n });\n }\n\n //Will clean streams, publishers and subscribers, but will not remove event listeners\n clearService(): Promise<void> {\n trace.info('MediaService clearing all resources');\n\n return this.disconnectFromSessionInternal(MediaSessionDisconnectReason.ForcedByConsumer)\n .then(this.clearSubscribers)\n .then(this.clearRegisteredStreams)\n .then(this._localStreamsManager.clearAllStreams)\n .then(() => {\n this._initLocalStreamsPromise = null;\n this._isVoipEnabled = false;\n }).then(() => undefined);\n }\n\n //Will clear the service and remove all event listeners\n dispose(): Promise<void> {\n return this.clearService().catch(() => undefined).then(() => {\n this._emitter.removeAllListeners();\n });\n }\n\n //#endregion\n\n //#region Protected Methods\n\n protected get subscribers(): Map<HTMLDivElement, TechseeMediaSubscriber> {\n return this._subscribers;\n }\n\n protected registerLocalMediaStream(tsMediaStream: TechseeMediaStream): Promise<void> {\n trace.info('Registering local stream', tsMediaStream.streamType);\n if (this._registeredStreams.has(tsMediaStream.streamType)) {\n return Promise.reject(new Error(`Stream ${tsMediaStream.streamType} already registered`));\n }\n\n return this.registerStream(tsMediaStream);\n }\n\n protected getRegisteredStreamByType(streamType: KnownMediaStream): Nullable<TechseeMediaStream> {\n return this._registeredStreams.get(streamType) || null;\n }\n\n protected changeEnableForKnownStream(streamType: KnownMediaStream, isPaused: boolean): void {\n const streamToChangeState = this.getRegisteredStreamByType(streamType);\n\n if (!streamToChangeState) {\n trace.warn('There no stream found to change enable state', streamType);\n } else {\n streamToChangeState.mediaTrack.enabled = !isPaused;\n\n if (streamToChangeState.isRemote && streamToChangeState.streamKind === KnownMediaStreamKind.Audio) {\n this.subscribers.forEach((subscriber) => {\n if (subscriber.streamType === streamType) {\n subscriber.muteSound(isPaused);\n }\n });\n }\n\n trace.info('Local stream enable state is changed', {streamType, isPaused});\n }\n }\n\n protected registerEventCallback(event: string, callback: (eventArgs?: any) => void): void {\n this._emitter.on(event, callback);\n }\n\n protected emitEvent(event: string, eventArgs?: any): void {\n setTimeout(() => {\n this._emitter.emit(event, eventArgs);\n });\n }\n\n //#endregion Protected Methods\n\n //#region Private Methods\n\n private registerRemoteMediaTrack(remoteMediaTrack: RemoteMediaTrack): Promise<void> {\n trace.info(`Registering remote ${remoteMediaTrack.trackType} MediaStreamTrack`, remoteMediaTrack.mediaTrack);\n const currentStream = this._registeredStreams.get(remoteMediaTrack.trackType);\n\n if (currentStream && !currentStream.isRemote) {\n return Promise.reject(new Error('Cannot register remote stream with the same type as local stream'));\n }\n\n const newDedicatedStream = new TechseeMediaStream(remoteMediaTrack.mediaTrack, remoteMediaTrack.trackType, true);\n\n return this.registerStream(newDedicatedStream);\n }\n\n private registerTrack(mediaStream: TechseeMediaStream): Promise<void> {\n mediaStream.mediaTrack.onended = () =>\n this.unregisterTechseeMediaStream(mediaStream, MediaStreamUnregisterReason.NativeEvent);\n\n this._registeredStreams.set(mediaStream.streamType, mediaStream);\n\n trace.info(`TechseeMediaStream registered - ${mediaStream.streamType}`, TechseeMediaStream);\n\n return this.updateSubscribersWithNewStream(mediaStream).then(() => {\n const eventArgs: StreamCreatedEventArgs = {streamType: mediaStream.streamType};\n\n this.emitEvent(privateEvents.STREAM_CREATED, eventArgs);\n });\n }\n\n private registerStream(mediaStream: TechseeMediaStream): Promise<void> {\n const currentStream = this._registeredStreams.get(mediaStream.streamType);\n\n if (currentStream) {\n return this.unregisterTechseeMediaStream(currentStream, MediaStreamUnregisterReason.ReplacingStream).then(() => this.registerTrack(mediaStream));\n }\n\n return this.registerTrack(mediaStream);\n }\n\n private unregisterTechseeMediaStream(streamToUnregister: TechseeMediaStream, reason: MediaStreamUnregisterReason): Promise<void> {\n const traceError = (error: any): void => {\n trace.warn('Unregister TechseeMediaStream error:', error);\n };\n\n const promises: any = [];\n\n trace.info('Unregister TechseeMediaStream: ', streamToUnregister.streamType);\n\n this._subscribers.forEach((subscriber) => {\n if (subscriber.streamType === streamToUnregister.streamType) {\n promises.push(subscriber.stopRendering().catch(traceError));\n }\n });\n\n if (!streamToUnregister.isRemote) {\n this._publishers.forEach((publisher: TechseeMediaPublisher) => {\n if (publisher.streamTypes.find((streamType) => streamType === streamToUnregister.streamType)) {\n if (this._session && this._session!.instance) {\n promises.push(this._session.instance.onMediaStreamDestroyed(publisher.destinationRole).catch(traceError));\n }\n }\n });\n }\n\n return Promise.all(promises)\n .then(() => {\n this._registeredStreams.delete(streamToUnregister.streamType);\n trace.info('Stream deleted', streamToUnregister.streamType);\n\n const eventArgs: StreamDestroyedEventArgs = {streamType: streamToUnregister.streamType, reason: reason};\n\n this.emitEvent(privateEvents.STREAM_DESTROYED, eventArgs);\n });\n }\n\n private unregisterRemoteMediaTrack(mediaTrack: MediaStreamTrack): Promise<void> {\n const promises: any = [];\n\n this._registeredStreams.forEach((registeredStream: TechseeMediaStream) => {\n if (registeredStream.mediaTrack.id === mediaTrack.id) {\n promises.push(this.unregisterTechseeMediaStream(registeredStream, MediaStreamUnregisterReason.ClosedRemotely));\n }\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n private removePublisher(publisher: TechseeMediaPublisher): Promise<void> {\n this._publishers.delete(publisher.destinationRole);\n if (this._session && this._session.instance) {\n trace.info('Removing publisher', publisher.destinationRole);\n\n return this._session.instance.onMediaStreamDestroyed(publisher.destinationRole)\n .catch((error: any) => {\n trace.warn('Error while removing publisher', error);\n });\n }\n\n return Promise.resolve();\n }\n\n private getStreamForDestinationRole(destinationRole: SessionClientRole): Promise<Nullable<MediaStream>> {\n this.serviceInitGuard();\n\n if (this._publishers.has(destinationRole)) {\n trace.info(`Publisher for ${destinationRole} already exists`);\n\n return Promise.resolve(this._publishers.get(destinationRole)!.mediaStream);\n }\n\n if (!this._publisherPromises.get(destinationRole)) {\n trace.info(`Creating publisher for ${destinationRole}`);\n const publisherPromise = this.initLocalMediaStreams()\n .then(() => this.createMediaPublisher(destinationRole))\n .then((mediaPublisher: Nullable<TechseeMediaPublisher>) => {\n if (mediaPublisher) {\n this._publishers.set(destinationRole, mediaPublisher);\n }\n\n this._publisherPromises.delete(destinationRole);\n\n return mediaPublisher ? mediaPublisher.mediaStream : null;\n })\n .catch((ex: any) => {\n if (ex && ex.message === 'audioStreamFailed') {\n this._isVoipEnabled = false;\n\n return null;\n }\n\n this._publisherPromises.delete(destinationRole);\n throw ex;\n });\n\n this._publisherPromises.set(destinationRole, publisherPromise);\n } else {\n trace.info(`Create publisher promise for ${destinationRole} already exists`);\n }\n\n return this._publisherPromises.get(destinationRole)!;\n }\n\n private updateSubscribersWithNewStream(registeredStream: TechseeMediaStream): Promise<void> {\n trace.info(`Updating subscribers of ${registeredStream.streamType} with new stream`);\n\n if (this._subscribers.size === 0) {\n trace.warn(`No subscribers exists for the ${registeredStream.streamType}.`);\n } else {\n trace.info(`Total ${this._subscribers.size} subscribers exists, will check if rerender needed.`);\n }\n\n this._subscribers.forEach((subscriber) => {\n if (subscriber.streamType === registeredStream.streamType) {\n trace.info(`${registeredStream.streamType} rendering on subscriber`);\n subscriber.renderStream(registeredStream);\n }\n });\n\n return Promise.resolve();\n }\n\n private bindClassMethods(): void {\n this.updateSessionCredentials = this.updateSessionCredentials.bind(this);\n this.getStreamForDestinationRole = this.getStreamForDestinationRole.bind(this);\n this.registerRemoteMediaTrack = this.registerRemoteMediaTrack.bind(this);\n this.unregisterRemoteMediaTrack = this.unregisterRemoteMediaTrack.bind(this);\n this.createMediaPublisher = this.createMediaPublisher.bind(this);\n this.updateSubscribersWithNewStream = this.updateSubscribersWithNewStream.bind(this);\n this.initLocalMediaStreams = this.initLocalMediaStreams.bind(this);\n this.onSessionDisconnectHandler = this.onSessionDisconnectHandler.bind(this);\n this.clearService = this.clearService.bind(this);\n this.clearRegisteredStreams = this.clearRegisteredStreams.bind(this);\n this.clearPublishers = this.clearPublishers.bind(this);\n this.clearSubscribers = this.clearSubscribers.bind(this);\n this._connectToSession = this._connectToSession.bind(this);\n }\n\n //region Cleanup\n\n private clearRegisteredStreams(): Promise<void> {\n trace.info('Clearing registered streams');\n const promises: any = [];\n\n this._registeredStreams.forEach((streamToUnregister: TechseeMediaStream) => {\n promises.push(this.unregisterTechseeMediaStream(streamToUnregister, MediaStreamUnregisterReason.ServiceCleanUp));\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n private clearSubscribers(): Promise<void> {\n trace.info('Clearing subscribers');\n const promises: any = [];\n\n this._subscribers.forEach((subscriber) => {\n promises.push(this.destroySubscriber(subscriber.container));\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n private clearPublishers(): Promise<void> {\n trace.info('Clearing publishers');\n const promises: any = [];\n\n this._publishers.forEach((publisher) => {\n promises.push(this.removePublisher(publisher));\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n //#endregion Cleanup\n\n //#region Simple Validation Methods\n\n protected serviceInitGuard(shouldThrow = true): boolean {\n return throwableGuard(!!this._serviceOptions, 'Media service is not initialized', shouldThrow);\n }\n\n protected sessionExistsGuard(shouldThrow = true): boolean {\n return throwableGuard(!!this._session, 'There no active session', shouldThrow);\n }\n\n //#endregion\n\n //#endregion Private Methods\n}\n"]}
1
+ {"version":3,"sources":["../src/MediaServiceBase.ts"],"names":[],"mappings":"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","file":"MediaServiceBase.d.ts","sourcesContent":["import filter from 'lodash/filter';\nimport cloneDeep from 'lodash/cloneDeep';\nimport values from 'lodash/values';\nimport debounce from 'lodash/debounce';\nimport includes from 'lodash/includes';\nimport {EventEmitter} from 'events';\nimport {Nullable} from '@techsee/techsee-common';\nimport {TechseeMediaSubscriber} from './MediaSubscriber';\nimport {TechseeMediaPublisher} from './MediaPublisher';\nimport {LocalStreamManager} from './LocalStreamManager';\nimport {TechseeMediaStream} from './TechseeMediaStream';\nimport {TurnWebRtcSession} from './MediaSession/SessionTurn';\nimport {getSnapshotFromMediaStream} from './MediaUtils/MediaDomUtils';\nimport {\n ClientWebRtcInfo,\n DeviceSupportInfo,\n IMediaEnvironment,\n IMediaSession,\n IMediaSubscriber,\n ISessionStreamsManager,\n LocalMediaConstraints,\n LocalVideoStreamConstraints,\n MediaRequestFailResult,\n MediaRequestSuccessResult,\n MediaServiceOptions,\n MediaSessionConfiguration,\n MediaSessionHandlers,\n MediaSessionIceCredentials,\n MediaSessionParams,\n MediaSubscriberParams,\n RemoteMediaTrack,\n RemoteTrackStats,\n SnapshotOptions,\n SnapshotResult,\n StreamCreatedEventArgs,\n StreamDestroyedEventArgs\n} from './MediaContracts';\nimport {enumerateMediaDevices, isVideoPlaySupportedOnDevice} from './MediaUtils/Compatibility';\nimport {OpentokSession} from './MediaSession/SessionOpentok';\nimport {\n DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS,\n KnownMediaStream,\n KnownMediaStreamKind,\n LocalVideoSourceType,\n MediaServiceType,\n MediaSessionDisconnectReason,\n MediaStreamUnregisterReason,\n SessionClientRole\n} from './MediaConstants';\nimport {throwableGuard} from '@techsee/techsee-common/lib/core/guards';\nimport {MediaServerSession} from './MediaSession/MediaServer';\nimport {getMediaTracer} from './MediaUtils/MediaTracer';\nimport {recordingEvents} from './MediaSession/MediaSessionBase';\n\nconst trace = getMediaTracer('MediaServiceBase');\nconst traceStatsInfo = debounce(trace.info, 1000 * 5, {leading: true, maxWait: 1000 * 30});\n\nenum privateEvents {\n STREAM_CREATED = 'STREAM_CREATED',\n STREAM_DESTROYED = 'STREAM_DESTROYED'\n}\n\nexport abstract class TechseeMediaServiceBase {\n //This method should not be called. The only place that allowed to use it, is initLocalMediaStreams method.\n //Everyone who need to initialize MediaStream should use initLocalMediaStreams method.\n protected abstract getLocalMediaImplementation(): Promise<void>;\n\n protected abstract createMediaPublisher(destinationRole: SessionClientRole): Promise<Nullable<TechseeMediaPublisher>>;\n\n protected readonly _environment: IMediaEnvironment;\n protected readonly _sessionStreamsManager: ISessionStreamsManager;\n protected readonly _localStreamsManager: LocalStreamManager;\n\n private readonly _deviceSupportFlags: DeviceSupportInfo;\n private readonly _subscribers: Map<HTMLDivElement, TechseeMediaSubscriber> = new Map();\n private readonly _publishers: Map<SessionClientRole, TechseeMediaPublisher> = new Map();\n private readonly _publisherPromises: Map<SessionClientRole, Promise<Nullable<MediaStream>>> = new Map();\n protected _serviceOptions: Nullable<MediaServiceOptions> = null;\n private _isIOS_13_orLater: boolean = false;\n private _isIOS_14_orLater: boolean = false;\n private _autoReconnectEnabled: boolean = true;\n private readonly _emitter: EventEmitter;\n private _initLocalStreamsPromise: Nullable<Promise<void>> = null;\n private _initServicePromise: Nullable<Promise<void>> = null;\n private _registeredStreams: Map<KnownMediaStream, TechseeMediaStream> = new Map();\n private _isVoipEnabled: boolean = false;\n private _session: Nullable<{\n params: MediaSessionParams;\n connectPromise?: Promise<void>;\n instance?: IMediaSession;\n }> = null;\n\n protected constructor(environment: IMediaEnvironment, webRtcSupportInfo: ClientWebRtcInfo) {\n trace.info('TechseeMediaServiceBase created');\n\n this.bindClassMethods();\n\n this._emitter = new EventEmitter();\n this._environment = environment;\n this._deviceSupportFlags = {\n videoPlayback: false,\n hasCamera: false,\n hasMicrophone: false,\n webRtcSupportInfo: webRtcSupportInfo\n };\n\n this._localStreamsManager = new LocalStreamManager(this._environment);\n\n // TODO: Hack as IOS 13.3 and above sometimes do not return the video/audio device. This\n // is a hack to work around the issue until Apple resolve it\n this._isIOS_13_orLater = this._environment.isIOS() &&\n (!this._environment.majorVersion() || (this._environment.majorVersion() >= 13));\n\n this._isIOS_14_orLater = this._environment.isIOS() &&\n (!this._environment.majorVersion() || (this._environment.majorVersion() >= 14));\n\n trace.info(`TechseeMediaServiceBase: isIOS_13_orLater: ${this._isIOS_13_orLater}`);\n trace.info(`TechseeMediaServiceBase: isIOS_14_orLater: ${this._isIOS_14_orLater}`);\n\n this._sessionStreamsManager = {\n getMediaStreamForRole: this.getStreamForDestinationRole,\n addRemoteMediaTrack: this.registerRemoteMediaTrack,\n removeMediaTrack: this.unregisterRemoteMediaTrack\n };\n }\n\n get deviceSupportInfo(): DeviceSupportInfo {\n this.serviceInitGuard(false);\n\n return cloneDeep(this._deviceSupportFlags);\n }\n\n get isVoipEnabled(): boolean {\n return this._isVoipEnabled;\n }\n\n get isSessionActive(): boolean {\n return this._session !== null;\n }\n\n get isLocalStreamInitialized(): boolean {\n return this._initLocalStreamsPromise !== null;\n }\n\n /*\n Initializes media service. Before using anything from this service it should be initialized first.\n All of serviceOptions should be retrieved from account settings and by evaluating application state.\n For example, when initializing service, accountSettings is already loaded, and we know if FS session is audio enabled.\n */\n initMediaService(serviceOptions: MediaServiceOptions): Promise<void> {\n trace.info('TechseeMediaServiceBase.initMediaService', serviceOptions);\n const warnMessage = 'Multiple initialization does not supposed to happen. Not rejecting, but check the flow for correctness.';\n\n if (this._initServicePromise || this._serviceOptions) {\n console.warn(warnMessage);\n\n return this._initServicePromise ? this._initServicePromise : Promise.resolve();\n }\n\n this._serviceOptions = cloneDeep(serviceOptions);\n this._initServicePromise = Promise.all([\n isVideoPlaySupportedOnDevice(this._serviceOptions.mediaServiceType)\n .then((isSupported: boolean) => this._deviceSupportFlags.videoPlayback = isSupported),\n (this._isIOS_14_orLater ? Promise.resolve([]) : enumerateMediaDevices())\n .catch((error) => {\n trace.warn(error);\n\n return [];\n })\n .then((localDevicesList: MediaDeviceInfo[]) => {\n const groupedDevices = {\n video: filter(localDevicesList, (device) => device.kind.toLowerCase() === 'videoinput'),\n audio: filter(localDevicesList, (device) => device.kind.toLowerCase() === 'audioinput')\n };\n\n this._localStreamsManager.setGroupedDevices(groupedDevices);\n this._deviceSupportFlags.hasCamera = this._isIOS_13_orLater || (groupedDevices.video.length > 0);\n this._deviceSupportFlags.hasMicrophone = this._isIOS_13_orLater || (groupedDevices.audio.length > 0);\n\n })\n ]).then(() => undefined);\n\n\n return this._initServicePromise;\n }\n\n //#region Media Streams Management\n\n /*\n The main method to start the initialization of local media streams.\n This method can be executed many times and it will insure all calls are synced and only relevant stream will be created.\n DO NOT USE ANY OTHER METHOD THAT FORCES \"navigator.getUserMedia\" OTHER THAN THIS ONE.\n */\n initLocalMediaStreams(): Promise<void> {\n this.serviceInitGuard();\n\n // This hack for IOS 14 force a recreation of stream on seemingly unnecessary occasions (like agent page refresh).\n // we're not sure why but the stream breaks\n if (!this._initLocalStreamsPromise || this._isIOS_14_orLater) {\n trace.info('initLocalMediaStreams creating media streams');\n this._initLocalStreamsPromise = this.getLocalMediaImplementation()\n .catch((mediaRequestFailResult: MediaRequestFailResult) => {\n trace.error('initLocalMediaStreams failure: ', mediaRequestFailResult);\n\n throw mediaRequestFailResult;\n });\n } else {\n trace.info('initLocalMediaStreams already done or in progress');\n }\n\n return this._initLocalStreamsPromise;\n }\n\n /*\n Creates an instance of subscriber that will \"listen\" to the requested stream.\n Whenever requested stream is available, subscriber will render it.\n */\n createSubscriber(subscriberParams: MediaSubscriberParams): Promise<IMediaSubscriber> {\n if (this._subscribers.has(subscriberParams.container)) {\n return Promise.reject('Subscriber for provided DIV element already exists');\n }\n\n const subscriber = new TechseeMediaSubscriber(subscriberParams);\n\n this._subscribers.set(subscriberParams.container, subscriber);\n const streamForSubscriber = this.getRegisteredStreamByType(subscriber.streamType);\n\n if (streamForSubscriber) {\n trace.info(`Stream for ${subscriberParams.streamType} is ready.`);\n subscriber.renderStream(streamForSubscriber);\n } else {\n trace.info(`Stream for ${subscriberParams.streamType} not created yet`);\n }\n\n return Promise.resolve(subscriber);\n }\n\n /*\n Destroys the subscriber for provided HTML DIV container\n */\n destroySubscriber(container: HTMLDivElement): Promise<void> {\n if (this._subscribers.has(container)) {\n const subscriber = this._subscribers.get(container);\n\n subscriber!.dispose();\n }\n\n this._subscribers.delete(container);\n\n return Promise.resolve();\n }\n\n onStreamDestroyed(callback: (eventArgs: StreamDestroyedEventArgs) => void): void {\n this.registerEventCallback(privateEvents.STREAM_DESTROYED, callback);\n }\n\n onStreamCreated(callback: (eventArgs: StreamCreatedEventArgs) => void): void {\n this.registerEventCallback(privateEvents.STREAM_CREATED, callback);\n }\n\n onRecordStarted(callback: (eventArgs: any) => void): void {\n if (this._session && this._session.instance) {\n this._session.instance.registerEventCallback(recordingEvents.RECORD_STARTED, callback);\n }\n }\n\n onRecordStopped(callback: (eventArgs: any) => void): void {\n if (this._session && this._session.instance) {\n this._session.instance.registerEventCallback(recordingEvents.RECORD_STOPPED, callback);\n }\n }\n\n onReconnecting(callback: (eventArgs: any) => void): void {\n if (this._session && this._session.instance) {\n this._session.instance.registerEventCallback(recordingEvents.RECONNECTING, callback);\n }\n }\n\n private getSwitchCameraConstraints() {\n const constraints = cloneDeep(window.latestLocalMediaConstraints);\n\n if (!constraints) {\n throw new Error('getSwitchCameraConstraints: unexpected use case constraints is null.');\n }\n\n trace.info('getSwitchCameraConstraints - Start switch camera with constraints:', constraints);\n\n const videoSourceType = (constraints.video as LocalVideoStreamConstraints).videoSourceType === LocalVideoSourceType.CAMERA\n ? LocalVideoSourceType.CAMERA_FRONT\n : LocalVideoSourceType.CAMERA;\n\n trace.info(`getSwitchCameraConstraints - switch to videoSourceType: ${videoSourceType}`);\n\n (constraints.video as LocalVideoStreamConstraints).videoSourceType = videoSourceType;\n\n return constraints;\n }\n\n switchCamera(revertCameraWhenFailed?: boolean): Promise<any> {\n trace.info('switchCamera: start');\n\n if (this._session && this._session.instance && this._session.instance.switchCamera) {\n return this._session.instance.switchCamera(SessionClientRole.USER);\n }\n\n const latestLocalMediaConstraints = cloneDeep(window.latestLocalMediaConstraints);\n const constraints = !revertCameraWhenFailed ? this.getSwitchCameraConstraints() : latestLocalMediaConstraints;\n\n if (!constraints) {\n throw new Error('switchCamera - unexpected use case constraints is null.');\n }\n\n return this._localStreamsManager.destroyUserMediaStream()\n .then(() => this._localStreamsManager.getUserMediaStream(constraints)\n .then((streamResult: MediaRequestSuccessResult) => {\n const stream = streamResult.mediaStream;\n\n trace.info('switchCamera: new stream: ', stream);\n\n return this.replaceStreamTracks(stream)\n .then(() => this.registerStreamResult(constraints, streamResult, true)\n .then(() => ({\n revertCameraWhenFailed,\n constraints,\n streamResult\n })));\n }))\n .catch((err) => {\n trace.error('switchCamera: Failed to switch camera: ', err);\n\n if (!revertCameraWhenFailed) {\n window.latestLocalMediaConstraints = latestLocalMediaConstraints;\n\n return this.switchCamera(true);\n }\n\n return Promise.reject('Failed to switch camera.');\n });\n }\n\n private replaceStreamTracks(mediaStream: Nullable<MediaStream>): Promise<void> {\n if (this._session!.instance) {\n return this._session!.instance.replaceStreamTracks(mediaStream);\n }\n\n return Promise.reject('replaceStreamTracks - session instance is not exists.');\n }\n\n protected registerStreamResult(constraints: Nullable<LocalMediaConstraints>, streamResult: MediaRequestSuccessResult, switchCamera?: boolean, addStreamType?: KnownMediaStream) {\n const regPromises: any[] = [];\n\n if (streamResult.isNew) {\n trace.info('registerStreamResult: stream result from getUserMediaStream:', streamResult.mediaStream);\n streamResult.mediaStream.getTracks().forEach((mediaTrack) => {\n trace.info('registerStreamResult: stream result from mediaTrack:', mediaTrack);\n const streamType = addStreamType || (mediaTrack.kind === 'video'\n ? KnownMediaStream.USER_VIDEO_STREAM : KnownMediaStream.USER_AUDIO_STREAM);\n const newDedicatedStream = new TechseeMediaStream(mediaTrack, streamType, false);\n\n regPromises.push(switchCamera ? this.registerTrack(newDedicatedStream) : this.registerLocalMediaStream(newDedicatedStream));\n });\n }\n\n return Promise.all(regPromises);\n }\n\n disconnectFromMediaSession() {\n if (this._session && this._session.instance) {\n return this._session.instance.sessionDisconnect();\n }\n }\n\n get supportSwitchCameras() {\n return this._isIOS_13_orLater || this._localStreamsManager.groupedDevices.camerasCount > 1;\n }\n\n private _connectToSession(sessionParams: MediaSessionParams): Promise<void> {\n this.serviceInitGuard();\n\n if (!this._session) {\n this._session = {params: cloneDeep(sessionParams)};\n this._session.connectPromise = new Promise((resolve, reject) => {\n const doAsyncReject = (error: any): void => {\n\n /*\n Reject with timeout, to change JS 'execution flow'.\n If timeout removed, session is assigned to null, before promise returns, and \"catch\" will not\n work on promise that is returned.\n */\n setTimeout(() => {\n this._session = null;\n reject(error);\n });\n };\n\n const sessionHandlers: MediaSessionHandlers = {\n onDisconnectedHandler: this.onSessionDisconnectHandler\n };\n const mediaSessionParams: MediaSessionParams & MediaSessionConfiguration = {\n ...sessionParams,\n peerConnectivityTimeoutSeconds: this._serviceOptions!.peerConnectivityTimeoutSeconds || DEFAULT_PEER_CONNECTIVITY_TIMEOUT_SECONDS\n };\n\n trace.info('connectToSession', sessionParams);\n\n const allowedValues = values(MediaServiceType);\n\n switch (this._serviceOptions!.mediaServiceType) {\n case MediaServiceType.TURNSERVER:\n this._session!.instance = new TurnWebRtcSession(mediaSessionParams, sessionHandlers, this._sessionStreamsManager);\n break;\n case MediaServiceType.OPENTOK:\n this._session!.instance = new OpentokSession(mediaSessionParams, this._sessionStreamsManager);\n break;\n case MediaServiceType.MEDIASERVER:\n this._session!.instance = new MediaServerSession(mediaSessionParams, this._sessionStreamsManager);\n break;\n default:\n trace.error(`mediaServiceType '${this._serviceOptions!.mediaServiceType}' is not supported.`, {allowedValues});\n doAsyncReject(new Error('mediaServiceType is not supported'));\n }\n\n if (this._session && this._session.instance) {\n this._session!.instance.connect()\n .then(() => {\n trace.info('Session is connected');\n resolve();\n })\n .catch((error: any) => {\n trace.error('Failed to connect to session', error);\n doAsyncReject(error);\n });\n }\n\n });\n } else {\n trace.warn('Session connected already. Disconnect before connect to new session again');\n }\n\n //TODO - Alex: Change a structure of this function to be more safe\n //(when we return, there should not be case when session or promise is null)\n //To fix, need to return promise immediately, then execute process in setTimeout(fn, 0);\n return this._session!.connectPromise!;\n }\n\n //#endregion Media Streams Management\n\n //#region Session Management\n\n /*\n Creates instance of WebRTC session which connects to (signaling server), and begins to listen to WebRTC events.\n */\n connectToSession(sessionParams: MediaSessionParams): Promise<void> {\n return this._connectToSession(sessionParams);\n }\n\n /*\n Disconnects from WebRTC session.\n */\n disconnectFromSession(): Promise<void> {\n return this.disconnectFromSessionInternal(MediaSessionDisconnectReason.ForcedByConsumer);\n }\n\n /*\n Updates a credentials for turn server\n */\n updateSessionCredentials(credentials: MediaSessionIceCredentials): Promise<void> {\n trace.info('updateSessionCredentials');\n if (!this.sessionExistsGuard(false)) {\n return Promise.reject('There no session to update credentials');\n }\n\n this._session!.params.credentials = cloneDeep(credentials);\n\n return Promise.resolve();\n }\n\n enableVoipDuringSession(): void {\n if (!this._isVoipEnabled && this.isLocalStreamInitialized) {\n this._initLocalStreamsPromise = null;\n }\n\n this._isVoipEnabled = true;\n }\n\n protected disconnectFromSessionInternal(reason: MediaSessionDisconnectReason): Promise<void> {\n if (!this._session) {\n return Promise.resolve();\n }\n\n trace.info('Disconnecting from session', reason);\n\n const lastSession = this._session;\n\n this._session = null;\n\n return Promise.all([\n lastSession.instance!.disconnect(),\n this.clearPublishers()\n ]).then(() => undefined);\n }\n\n protected getStatsForRemoteTrack(streamType: KnownMediaStream): Promise<RemoteTrackStats> {\n if (!this.sessionExistsGuard(false)) {\n return Promise.reject(new Error('Media session not started'));\n }\n\n const streamForStats = this.getRegisteredStreamByType(streamType);\n\n if (!streamForStats) {\n return Promise.reject(new Error('Stream for requested type was not found'));\n }\n\n return this._session!.instance!.getRemoteTrackStats(streamForStats.mediaTrack)\n .then((trackStats: RemoteTrackStats) => {\n traceStatsInfo(`MediaTrackStats for ${streamType}: ${JSON.stringify(trackStats)}`);\n\n return {\n trackId: streamForStats.mediaTrack.id,\n trackStats: trackStats\n };\n });\n }\n\n private onSessionDisconnectHandler(reason: MediaSessionDisconnectReason): void {\n trace.info('onSessionDisconnectHandler', reason);\n if (reason !== MediaSessionDisconnectReason.ForcedByConsumer) {\n const lastParams = this._session && this._session.params ? this._session.params : null;\n\n this.disconnectFromSessionInternal(reason).then(() => {\n const reconnectReasons = [\n MediaSessionDisconnectReason.InitiatorPeerReconnected,\n MediaSessionDisconnectReason.SignalingChannelDisconnect,\n MediaSessionDisconnectReason.PeerConnectionInterrupted,\n MediaSessionDisconnectReason.PeerConnectionStateChangeTimeout\n ];\n\n if (lastParams && includes(reconnectReasons, reason) && this._autoReconnectEnabled) {\n this.reconnectToSession(lastParams);\n } else if (!this._autoReconnectEnabled) {\n trace.info('No reconnection- auto reconnect disabled');\n } else {\n trace.info('No params for reconnection to media session');\n }\n });\n } else {\n trace.info('Ignore Session disconnect event');\n }\n }\n\n setAutoReconnect(state: boolean) {\n this._autoReconnectEnabled = state;\n trace.info('_autoReconnectEnabled:', state);\n\n if (this._autoReconnectEnabled && !this.isSessionActive) {\n const lastParams = this._session && this._session.params ? this._session.params : null;\n\n if (lastParams) {\n trace.info('setAutoReconnect - reconnect to session');\n this.reconnectToSession(lastParams);\n }\n }\n }\n\n reconnectToSession(lastParams: MediaSessionParams) {\n trace.info('Reconnecting to media session, sessionParams:', lastParams);\n\n this._connectToSession(lastParams)\n .then(() => {\n trace.info('Media session reconnected');\n })\n .catch((error: any) => {\n trace.error('Error while reconnecting to media session', error);\n });\n }\n\n //#endregion Session Management\n\n //#region Utils\n\n getSnapshotFromKnownStream(sourceStream: KnownMediaStream, snapshotOptions?: SnapshotOptions): Promise<SnapshotResult> {\n return new Promise((resolve, reject) => {\n if (sourceStream !== KnownMediaStream.USER_VIDEO_STREAM &&\n sourceStream !== KnownMediaStream.USER_SCREEN_SHARE_STREAM) {\n trace.error('The requested stream is not video stream, and cannot be used for snapshot');\n reject(new Error('INCOMPATIBLE_STREAM_FOR_SNAPSHOT'));\n\n return;\n }\n\n const snapshotStream = this.getRegisteredStreamByType(sourceStream);\n\n if (!snapshotStream) {\n trace.error('Cannot make snapshot: The requested stream not exists yet.');\n reject(new Error('NO_REQUESTED_STREAM'));\n\n return;\n }\n\n getSnapshotFromMediaStream(snapshotStream.mediaStream, snapshotOptions)\n .then((imageData: any) => {\n const urlComponents = imageData.split(';base64,');\n const mimeType = urlComponents[0].split(':')[1];\n const bytes = atob(urlComponents[1]);\n const buffer = new ArrayBuffer(bytes.length);\n const rawData = new Uint8Array(buffer);\n\n for (let i = 0; i < bytes.length; i++) {\n rawData[i] = bytes.charCodeAt(i);\n }\n\n const blob = new Blob([rawData], {type: mimeType});\n const objectUrl = window.URL.createObjectURL(blob);\n\n trace.info('Snapshot created successfully');\n\n const result: SnapshotResult = {\n base64img: imageData,\n objectUrl: objectUrl,\n imageBlob: blob,\n mimeType: mimeType\n };\n\n resolve(result);\n })\n .catch((error: any) => {\n trace.error('Error creating snapshot', error);\n reject(error);\n });\n });\n }\n\n //Will clean streams, publishers and subscribers, but will not remove event listeners\n clearService(): Promise<void> {\n trace.info('MediaService clearing all resources');\n\n return this.disconnectFromSessionInternal(MediaSessionDisconnectReason.ForcedByConsumer)\n .then(this.clearSubscribers)\n .then(this.clearRegisteredStreams)\n .then(this._localStreamsManager.clearAllStreams)\n .then(() => {\n this._initLocalStreamsPromise = null;\n this._isVoipEnabled = false;\n }).then(() => undefined);\n }\n\n //Will clear the service and remove all event listeners\n dispose(): Promise<void> {\n return this.clearService().catch(() => undefined).then(() => {\n this._emitter.removeAllListeners();\n });\n }\n\n //#endregion\n\n //#region Protected Methods\n\n protected get subscribers(): Map<HTMLDivElement, TechseeMediaSubscriber> {\n return this._subscribers;\n }\n\n protected registerLocalMediaStream(tsMediaStream: TechseeMediaStream): Promise<void> {\n trace.info('Registering local stream', tsMediaStream.streamType);\n if (this._registeredStreams.has(tsMediaStream.streamType)) {\n return Promise.reject(new Error(`Stream ${tsMediaStream.streamType} already registered`));\n }\n\n return this.registerStream(tsMediaStream);\n }\n\n protected getRegisteredStreamByType(streamType: KnownMediaStream): Nullable<TechseeMediaStream> {\n return this._registeredStreams.get(streamType) || null;\n }\n\n protected changeEnableForKnownStream(streamType: KnownMediaStream, isPaused: boolean): void {\n const streamToChangeState = this.getRegisteredStreamByType(streamType);\n\n if (!streamToChangeState) {\n trace.warn('There no stream found to change enable state', streamType);\n } else {\n streamToChangeState.mediaTrack.enabled = !isPaused;\n\n if (streamToChangeState.isRemote && streamToChangeState.streamKind === KnownMediaStreamKind.Audio) {\n this.subscribers.forEach((subscriber) => {\n if (subscriber.streamType === streamType) {\n subscriber.muteSound(isPaused);\n }\n });\n }\n\n trace.info('Local stream enable state is changed', {streamType, isPaused});\n }\n }\n\n protected registerEventCallback(event: string, callback: (eventArgs?: any) => void): void {\n this._emitter.on(event, callback);\n }\n\n protected emitEvent(event: string, eventArgs?: any): void {\n setTimeout(() => {\n this._emitter.emit(event, eventArgs);\n });\n }\n\n //#endregion Protected Methods\n\n //#region Private Methods\n\n private registerRemoteMediaTrack(remoteMediaTrack: RemoteMediaTrack): Promise<void> {\n trace.info(`Registering remote ${remoteMediaTrack.trackType} MediaStreamTrack`, remoteMediaTrack.mediaTrack);\n const currentStream = this._registeredStreams.get(remoteMediaTrack.trackType);\n\n if (currentStream && !currentStream.isRemote) {\n return Promise.reject(new Error('Cannot register remote stream with the same type as local stream'));\n }\n\n const newDedicatedStream = new TechseeMediaStream(remoteMediaTrack.mediaTrack, remoteMediaTrack.trackType, true);\n\n return this.registerStream(newDedicatedStream);\n }\n\n private registerTrack(mediaStream: TechseeMediaStream): Promise<void> {\n mediaStream.mediaTrack.onended = () =>\n this.unregisterTechseeMediaStream(mediaStream, MediaStreamUnregisterReason.NativeEvent);\n\n this._registeredStreams.set(mediaStream.streamType, mediaStream);\n\n trace.info(`TechseeMediaStream registered - ${mediaStream.streamType}`, TechseeMediaStream);\n\n return this.updateSubscribersWithNewStream(mediaStream).then(() => {\n const eventArgs: StreamCreatedEventArgs = {streamType: mediaStream.streamType};\n\n this.emitEvent(privateEvents.STREAM_CREATED, eventArgs);\n });\n }\n\n private registerStream(mediaStream: TechseeMediaStream): Promise<void> {\n const currentStream = this._registeredStreams.get(mediaStream.streamType);\n\n if (currentStream) {\n return this.unregisterTechseeMediaStream(currentStream, MediaStreamUnregisterReason.ReplacingStream).then(() => this.registerTrack(mediaStream));\n }\n\n return this.registerTrack(mediaStream);\n }\n\n private unregisterTechseeMediaStream(streamToUnregister: TechseeMediaStream, reason: MediaStreamUnregisterReason): Promise<void> {\n const traceError = (error: any): void => {\n trace.warn('Unregister TechseeMediaStream error:', error);\n };\n\n const promises: any = [];\n\n trace.info('Unregister TechseeMediaStream: ', streamToUnregister.streamType);\n\n this._subscribers.forEach((subscriber) => {\n if (subscriber.streamType === streamToUnregister.streamType) {\n promises.push(subscriber.stopRendering().catch(traceError));\n }\n });\n\n if (!streamToUnregister.isRemote) {\n this._publishers.forEach((publisher: TechseeMediaPublisher) => {\n if (publisher.streamTypes.find((streamType) => streamType === streamToUnregister.streamType)) {\n if (this._session && this._session!.instance) {\n promises.push(this._session.instance.onMediaStreamDestroyed(publisher.destinationRole).catch(traceError));\n }\n }\n });\n }\n\n return Promise.all(promises)\n .then(() => {\n this._registeredStreams.delete(streamToUnregister.streamType);\n trace.info('Stream deleted', streamToUnregister.streamType);\n\n const eventArgs: StreamDestroyedEventArgs = {streamType: streamToUnregister.streamType, reason: reason};\n\n this.emitEvent(privateEvents.STREAM_DESTROYED, eventArgs);\n });\n }\n\n private unregisterRemoteMediaTrack(mediaTrack: MediaStreamTrack): Promise<void> {\n const promises: any = [];\n\n this._registeredStreams.forEach((registeredStream: TechseeMediaStream) => {\n if (registeredStream.mediaTrack.id === mediaTrack.id) {\n promises.push(this.unregisterTechseeMediaStream(registeredStream, MediaStreamUnregisterReason.ClosedRemotely));\n }\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n private removePublisher(publisher: TechseeMediaPublisher): Promise<void> {\n this._publishers.delete(publisher.destinationRole);\n if (this._session && this._session.instance) {\n trace.info('Removing publisher', publisher.destinationRole);\n\n return this._session.instance.onMediaStreamDestroyed(publisher.destinationRole)\n .catch((error: any) => {\n trace.warn('Error while removing publisher', error);\n });\n }\n\n return Promise.resolve();\n }\n\n private getStreamForDestinationRole(destinationRole: SessionClientRole): Promise<Nullable<MediaStream>> {\n this.serviceInitGuard();\n\n if (this._publishers.has(destinationRole)) {\n trace.info(`Publisher for ${destinationRole} already exists`);\n\n return Promise.resolve(this._publishers.get(destinationRole)!.mediaStream);\n }\n\n if (!this._publisherPromises.get(destinationRole)) {\n trace.info(`Creating publisher for ${destinationRole}`);\n const publisherPromise = this.initLocalMediaStreams()\n .then(() => this.createMediaPublisher(destinationRole))\n .then((mediaPublisher: Nullable<TechseeMediaPublisher>) => {\n if (mediaPublisher) {\n this._publishers.set(destinationRole, mediaPublisher);\n }\n\n this._publisherPromises.delete(destinationRole);\n\n return mediaPublisher ? mediaPublisher.mediaStream : null;\n })\n .catch((ex: any) => {\n if (ex && ex.message === 'audioStreamFailed') {\n this._isVoipEnabled = false;\n\n return null;\n }\n\n this._publisherPromises.delete(destinationRole);\n throw ex;\n });\n\n this._publisherPromises.set(destinationRole, publisherPromise);\n } else {\n trace.info(`Create publisher promise for ${destinationRole} already exists`);\n }\n\n return this._publisherPromises.get(destinationRole)!;\n }\n\n private updateSubscribersWithNewStream(registeredStream: TechseeMediaStream): Promise<void> {\n trace.info(`Updating subscribers of ${registeredStream.streamType} with new stream`);\n\n if (this._subscribers.size === 0) {\n trace.warn(`No subscribers exists for the ${registeredStream.streamType}.`);\n } else {\n trace.info(`Total ${this._subscribers.size} subscribers exists, will check if rerender needed.`);\n }\n\n this._subscribers.forEach((subscriber) => {\n if (subscriber.streamType === registeredStream.streamType) {\n trace.info(`${registeredStream.streamType} rendering on subscriber`);\n subscriber.renderStream(registeredStream);\n }\n });\n\n return Promise.resolve();\n }\n\n private bindClassMethods(): void {\n this.updateSessionCredentials = this.updateSessionCredentials.bind(this);\n this.getStreamForDestinationRole = this.getStreamForDestinationRole.bind(this);\n this.registerRemoteMediaTrack = this.registerRemoteMediaTrack.bind(this);\n this.unregisterRemoteMediaTrack = this.unregisterRemoteMediaTrack.bind(this);\n this.createMediaPublisher = this.createMediaPublisher.bind(this);\n this.updateSubscribersWithNewStream = this.updateSubscribersWithNewStream.bind(this);\n this.initLocalMediaStreams = this.initLocalMediaStreams.bind(this);\n this.onSessionDisconnectHandler = this.onSessionDisconnectHandler.bind(this);\n this.clearService = this.clearService.bind(this);\n this.clearRegisteredStreams = this.clearRegisteredStreams.bind(this);\n this.clearPublishers = this.clearPublishers.bind(this);\n this.clearSubscribers = this.clearSubscribers.bind(this);\n this._connectToSession = this._connectToSession.bind(this);\n this.disconnectFromMediaSession = this.disconnectFromMediaSession.bind(this);\n }\n\n //region Cleanup\n\n private clearRegisteredStreams(): Promise<void> {\n trace.info('Clearing registered streams');\n const promises: any = [];\n\n this._registeredStreams.forEach((streamToUnregister: TechseeMediaStream) => {\n promises.push(this.unregisterTechseeMediaStream(streamToUnregister, MediaStreamUnregisterReason.ServiceCleanUp));\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n private clearSubscribers(): Promise<void> {\n trace.info('Clearing subscribers');\n const promises: any = [];\n\n this._subscribers.forEach((subscriber) => {\n promises.push(this.destroySubscriber(subscriber.container));\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n private clearPublishers(): Promise<void> {\n trace.info('Clearing publishers');\n const promises: any = [];\n\n this._publishers.forEach((publisher) => {\n promises.push(this.removePublisher(publisher));\n });\n\n return Promise.all(promises).then(() => undefined);\n }\n\n //#endregion Cleanup\n\n //#region Simple Validation Methods\n\n protected serviceInitGuard(shouldThrow = true): boolean {\n return throwableGuard(!!this._serviceOptions, 'Media service is not initialized', shouldThrow);\n }\n\n protected sessionExistsGuard(shouldThrow = true): boolean {\n return throwableGuard(!!this._session, 'There no active session', shouldThrow);\n }\n\n //#endregion\n\n //#endregion Private Methods\n}\n"]}
@@ -33,6 +33,7 @@ var MediaConstants_1 = require("./MediaConstants");
33
33
  var guards_1 = require("@techsee/techsee-common/lib/core/guards");
34
34
  var MediaServer_1 = require("./MediaSession/MediaServer");
35
35
  var MediaTracer_1 = require("./MediaUtils/MediaTracer");
36
+ var MediaSessionBase_1 = require("./MediaSession/MediaSessionBase");
36
37
  var trace = MediaTracer_1.getMediaTracer('MediaServiceBase');
37
38
  var traceStatsInfo = debounce_1.default(trace.info, 1000 * 5, { leading: true, maxWait: 1000 * 30 });
38
39
  var privateEvents;
@@ -47,6 +48,7 @@ var TechseeMediaServiceBase = /** @class */function () {
47
48
  this._publisherPromises = new Map();
48
49
  this._serviceOptions = null;
49
50
  this._isIOS_13_orLater = false;
51
+ this._isIOS_14_orLater = false;
50
52
  this._autoReconnectEnabled = true;
51
53
  this._initLocalStreamsPromise = null;
52
54
  this._initServicePromise = null;
@@ -67,7 +69,9 @@ var TechseeMediaServiceBase = /** @class */function () {
67
69
  // TODO: Hack as IOS 13.3 and above sometimes do not return the video/audio device. This
68
70
  // is a hack to work around the issue until Apple resolve it
69
71
  this._isIOS_13_orLater = this._environment.isIOS() && (!this._environment.majorVersion() || this._environment.majorVersion() >= 13);
72
+ this._isIOS_14_orLater = this._environment.isIOS() && (!this._environment.majorVersion() || this._environment.majorVersion() >= 14);
70
73
  trace.info("TechseeMediaServiceBase: isIOS_13_orLater: " + this._isIOS_13_orLater);
74
+ trace.info("TechseeMediaServiceBase: isIOS_14_orLater: " + this._isIOS_14_orLater);
71
75
  this._sessionStreamsManager = {
72
76
  getMediaStreamForRole: this.getStreamForDestinationRole,
73
77
  addRemoteMediaTrack: this.registerRemoteMediaTrack,
@@ -119,7 +123,7 @@ var TechseeMediaServiceBase = /** @class */function () {
119
123
  this._serviceOptions = cloneDeep_1.default(serviceOptions);
120
124
  this._initServicePromise = Promise.all([Compatibility_1.isVideoPlaySupportedOnDevice(this._serviceOptions.mediaServiceType).then(function (isSupported) {
121
125
  return _this._deviceSupportFlags.videoPlayback = isSupported;
122
- }), Compatibility_1.enumerateMediaDevices().catch(function (error) {
126
+ }), (this._isIOS_14_orLater ? Promise.resolve([]) : Compatibility_1.enumerateMediaDevices()).catch(function (error) {
123
127
  trace.warn(error);
124
128
  return [];
125
129
  }).then(function (localDevicesList) {
@@ -147,7 +151,9 @@ var TechseeMediaServiceBase = /** @class */function () {
147
151
  */
148
152
  TechseeMediaServiceBase.prototype.initLocalMediaStreams = function () {
149
153
  this.serviceInitGuard();
150
- if (!this._initLocalStreamsPromise) {
154
+ // This hack for IOS 14 force a recreation of stream on seemingly unnecessary occasions (like agent page refresh).
155
+ // we're not sure why but the stream breaks
156
+ if (!this._initLocalStreamsPromise || this._isIOS_14_orLater) {
151
157
  trace.info('initLocalMediaStreams creating media streams');
152
158
  this._initLocalStreamsPromise = this.getLocalMediaImplementation().catch(function (mediaRequestFailResult) {
153
159
  trace.error('initLocalMediaStreams failure: ', mediaRequestFailResult);
@@ -196,17 +202,17 @@ var TechseeMediaServiceBase = /** @class */function () {
196
202
  };
197
203
  TechseeMediaServiceBase.prototype.onRecordStarted = function (callback) {
198
204
  if (this._session && this._session.instance) {
199
- this._session.instance.registerEventCallback(MediaServer_1.recordingEvents.RECORD_STARTED, callback);
205
+ this._session.instance.registerEventCallback(MediaSessionBase_1.recordingEvents.RECORD_STARTED, callback);
200
206
  }
201
207
  };
202
208
  TechseeMediaServiceBase.prototype.onRecordStopped = function (callback) {
203
209
  if (this._session && this._session.instance) {
204
- this._session.instance.registerEventCallback(MediaServer_1.recordingEvents.RECORD_STOPPED, callback);
210
+ this._session.instance.registerEventCallback(MediaSessionBase_1.recordingEvents.RECORD_STOPPED, callback);
205
211
  }
206
212
  };
207
213
  TechseeMediaServiceBase.prototype.onReconnecting = function (callback) {
208
214
  if (this._session && this._session.instance) {
209
- this._session.instance.registerEventCallback(MediaServer_1.recordingEvents.RECONNECTING, callback);
215
+ this._session.instance.registerEventCallback(MediaSessionBase_1.recordingEvents.RECONNECTING, callback);
210
216
  }
211
217
  };
212
218
  TechseeMediaServiceBase.prototype.getSwitchCameraConstraints = function () {
@@ -223,6 +229,9 @@ var TechseeMediaServiceBase = /** @class */function () {
223
229
  TechseeMediaServiceBase.prototype.switchCamera = function (revertCameraWhenFailed) {
224
230
  var _this = this;
225
231
  trace.info('switchCamera: start');
232
+ if (this._session && this._session.instance && this._session.instance.switchCamera) {
233
+ return this._session.instance.switchCamera(MediaConstants_1.SessionClientRole.USER);
234
+ }
226
235
  var latestLocalMediaConstraints = cloneDeep_1.default(window.latestLocalMediaConstraints);
227
236
  var constraints = !revertCameraWhenFailed ? this.getSwitchCameraConstraints() : latestLocalMediaConstraints;
228
237
  if (!constraints) {
@@ -271,6 +280,11 @@ var TechseeMediaServiceBase = /** @class */function () {
271
280
  }
272
281
  return Promise.all(regPromises);
273
282
  };
283
+ TechseeMediaServiceBase.prototype.disconnectFromMediaSession = function () {
284
+ if (this._session && this._session.instance) {
285
+ return this._session.instance.sessionDisconnect();
286
+ }
287
+ };
274
288
  Object.defineProperty(TechseeMediaServiceBase.prototype, "supportSwitchCameras", {
275
289
  get: function get() {
276
290
  return this._isIOS_13_orLater || this._localStreamsManager.groupedDevices.camerasCount > 1;
@@ -360,7 +374,7 @@ var TechseeMediaServiceBase = /** @class */function () {
360
374
  };
361
375
  TechseeMediaServiceBase.prototype.enableVoipDuringSession = function () {
362
376
  if (!this._isVoipEnabled && this.isLocalStreamInitialized) {
363
- throw new Error('Voip support cannot be enabled after local stream where initialized');
377
+ this._initLocalStreamsPromise = null;
364
378
  }
365
379
  this._isVoipEnabled = true;
366
380
  };
@@ -679,6 +693,7 @@ var TechseeMediaServiceBase = /** @class */function () {
679
693
  this.clearPublishers = this.clearPublishers.bind(this);
680
694
  this.clearSubscribers = this.clearSubscribers.bind(this);
681
695
  this._connectToSession = this._connectToSession.bind(this);
696
+ this.disconnectFromMediaSession = this.disconnectFromMediaSession.bind(this);
682
697
  };
683
698
  //region Cleanup
684
699
  TechseeMediaServiceBase.prototype.clearRegisteredStreams = function () {