diff --git a/android/build.gradle b/android/build.gradle index a5815a80b..7c0ff4414 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -27,7 +27,6 @@ def safeExtGet(prop, fallback) { android { compileSdkVersion safeExtGet('Hmssdk_compileSdkVersion', 29) - buildToolsVersion safeExtGet('Hmssdk_buildToolsVersion', '29.0.2') defaultConfig { minSdkVersion safeExtGet('Hmssdk_minSdkVersion', 21) targetSdkVersion safeExtGet('Hmssdk_targetSdkVersion', 29) @@ -64,6 +63,6 @@ dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // From node_modules - implementation 'com.github.100mslive:android-sdk:2.2.3' + implementation 'com.github.100mslive:android-sdk:2.2.4' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' } diff --git a/android/src/main/java/com/reactnativehmssdk/HmsDecoder.kt b/android/src/main/java/com/reactnativehmssdk/HmsDecoder.kt index 198f36ef3..30e54cfa5 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmsDecoder.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmsDecoder.kt @@ -1,10 +1,9 @@ package com.reactnativehmssdk import com.facebook.react.bridge.* -import java.util.* import live.hms.video.error.HMSException -import live.hms.video.media.codec.HMSVideoCodec import live.hms.video.media.settings.HMSAudioTrackSettings +import live.hms.video.media.settings.HMSVideoResolution import live.hms.video.media.settings.HMSVideoTrackSettings import live.hms.video.media.tracks.* import live.hms.video.sdk.models.* @@ -32,11 +31,8 @@ object HmsDecoder { "serverRecordingState", this.getHMSServerRecordingState(hmsRoom.serverRecordingState) ) - var peers: WritableArray = Arguments.createArray() - for (peer in hmsRoom.peerList) { - peers.pushMap(getHmsPeer(peer)) - } - room.putArray("peers", peers) + room.putMap("localPeer", this.getHmsLocalPeer(hmsRoom.localPeer)) + room.putArray("peers", this.getAllPeers(hmsRoom.peerList)) } return room } @@ -47,26 +43,20 @@ object HmsDecoder { peer.putString("peerID", hmsPeer.peerID) peer.putString("name", hmsPeer.name) peer.putBoolean("isLocal", hmsPeer.isLocal) - peer.putString( - "customerUserID", - if (hmsPeer.customerUserID == null) hmsPeer.customerUserID else "" - ) - peer.putString("metadata", if (hmsPeer.metadata == null) hmsPeer.metadata else "") - peer.putMap("audioTrack", getHmsAudioTrack(hmsPeer.audioTrack)) - peer.putMap("videoTrack", getHmsVideoTrack(hmsPeer.videoTrack)) - peer.putMap("role", getHmsRole(hmsPeer.hmsRole)) - var auxiliaryTracks: WritableArray = Arguments.createArray() - for (track in hmsPeer.auxiliaryTracks) { - auxiliaryTracks.pushMap(getHmsTrack(track)) - } - peer.putArray("auxiliaryTracks", auxiliaryTracks) + peer.putString("customerUserID", hmsPeer.customerUserID) + peer.putString("metadata", hmsPeer.metadata) + peer.putMap("audioTrack", this.getHmsAudioTrack(hmsPeer.audioTrack)) + peer.putMap("videoTrack", this.getHmsVideoTrack(hmsPeer.videoTrack)) + peer.putMap("role", this.getHmsRole(hmsPeer.hmsRole)) + peer.putArray("auxiliaryTracks", this.getAllTracks(hmsPeer.auxiliaryTracks)) } return peer } - fun getHmsAudioTrack(hmsAudioTrack: HMSAudioTrack?): WritableMap { + private fun getHmsAudioTrack(hmsAudioTrack: HMSAudioTrack?): WritableMap { val hmsTrack: WritableMap = Arguments.createMap() if (hmsAudioTrack != null) { + hmsTrack.putString("type", hmsAudioTrack.type.name) hmsTrack.putString("trackId", hmsAudioTrack.trackId) hmsTrack.putString("source", hmsAudioTrack.source) hmsTrack.putString("trackDescription", hmsAudioTrack.description) @@ -75,9 +65,10 @@ object HmsDecoder { return hmsTrack } - fun getHmsVideoTrack(hmsVideoTrack: HMSVideoTrack?): WritableMap { + private fun getHmsVideoTrack(hmsVideoTrack: HMSVideoTrack?): WritableMap { val hmsTrack: WritableMap = Arguments.createMap() if (hmsVideoTrack != null) { + hmsTrack.putString("type", hmsVideoTrack.type.name) hmsTrack.putString("trackId", hmsVideoTrack.trackId) hmsTrack.putString("source", hmsVideoTrack.source) hmsTrack.putString("trackDescription", hmsVideoTrack.description) @@ -94,105 +85,63 @@ object HmsDecoder { hmsTrack.putString("source", track.source) hmsTrack.putString("trackDescription", track.description) hmsTrack.putBoolean("isMute", track.isMute) - hmsTrack.putString("type", track.type.toString()) + hmsTrack.putString("type", track.type.name) } return hmsTrack } fun getAllRoles(roles: List?): WritableArray { val decodedRoles: WritableArray = Arguments.createArray() - if (roles != null) { for (role in roles) { - val decodedRole = getHmsRole(role) - + val decodedRole = this.getHmsRole(role) decodedRoles.pushMap(decodedRole) } } - return decodedRoles } - fun getHmsRole(hmsRole: HMSRole?): WritableMap { + private fun getHmsRole(hmsRole: HMSRole?): WritableMap { val role: WritableMap = Arguments.createMap() - // val emptyMap: WritableArray = Arguments.createMap(); if (hmsRole != null) { role.putString("name", hmsRole.name) - role.putMap("permissions", getHmsPermissions(hmsRole.permission)) - role.putMap("publishSettings", getHmsPublishSettings(hmsRole.publishParams)) + role.putMap("permissions", this.getHmsPermissions(hmsRole.permission)) + role.putMap("publishSettings", this.getHmsPublishSettings(hmsRole.publishParams)) + role.putMap("subscribeSettings", this.getHmsSubscribeSettings(hmsRole.subscribeParams)) role.putInt("priority", hmsRole.priority) - // role.putArray("generalPermissions", - // if(hmsRole.generalPermissions!=null)hmsRole.generalPermissions else emptyMap); - // role.putArray("internalPlugins", - // if(hmsRole.internalPlugins!=null)hmsRole.internalPlugins else emptyMap); - // role.putArray("externalPlugins", - // if(hmsRole.externalPlugins!=null)hmsRole.externalPlugins else emptyMap); } return role } - fun getHmsPermissions(hmsPermissions: PermissionsParams?): WritableMap { + private fun getHmsPermissions(hmsPermissions: PermissionsParams?): WritableMap { val permissions: WritableMap = Arguments.createMap() if (hmsPermissions != null) { - permissions.putBoolean( - "endRoom", - if (hmsPermissions.endRoom != null) hmsPermissions.endRoom else false - ) - permissions.putBoolean( - "removeOthers", - if (hmsPermissions.removeOthers != null) hmsPermissions.removeOthers else false - ) - permissions.putBoolean( - "mute", - if (hmsPermissions.mute != null) hmsPermissions.mute else false - ) - permissions.putBoolean( - "changeRoleForce", - if (hmsPermissions.changeRoleForce != null) hmsPermissions.changeRoleForce else false - ) - permissions.putBoolean( - "unmute", - if (hmsPermissions.unmute != null) hmsPermissions.unmute else false - ) - permissions.putBoolean( - "recording", - if (hmsPermissions.recording != null) hmsPermissions.recording else false - ) - permissions.putBoolean( - "rtmp", - if (hmsPermissions.rtmp != null) hmsPermissions.rtmp else false - ) - permissions.putBoolean( - "changeRole", - if (hmsPermissions.changeRole != null) hmsPermissions.changeRole else false - ) + permissions.putBoolean("endRoom", hmsPermissions.endRoom) + permissions.putBoolean("removeOthers", hmsPermissions.removeOthers) + permissions.putBoolean("mute", hmsPermissions.mute) + permissions.putBoolean("changeRoleForce", hmsPermissions.changeRoleForce) + permissions.putBoolean("unmute", hmsPermissions.unmute) + permissions.putBoolean("recording", hmsPermissions.recording) + permissions.putBoolean("rtmp", hmsPermissions.rtmp) + permissions.putBoolean("changeRole", hmsPermissions.changeRole) } return permissions } - fun getHmsPublishSettings(hmsPublishSettings: PublishParams?): WritableMap { + private fun getHmsPublishSettings(hmsPublishSettings: PublishParams?): WritableMap { val publishSettings: WritableMap = Arguments.createMap() - val emptyArray: WritableArray = Arguments.createArray() if (hmsPublishSettings != null) { - publishSettings.putMap("audio", getHmsAudioSettings(hmsPublishSettings.audio)) - publishSettings.putMap("video", getHmsVideoSettings(hmsPublishSettings.video)) - publishSettings.putMap("screen", getHmsVideoSettings(hmsPublishSettings.screen)) - // publishSettings.putMap("videoSimulcastLayers", - // getHmsSimulcastLayers(hmsPublishSettings.videoSimulcastLayers)); - // publishSettings.putMap("screenSimulcastLayers", - // getHmsSimulcastLayers(hmsPublishSettings.screenSimulcastLayers)); + publishSettings.putMap("audio", this.getHmsAudioSettings(hmsPublishSettings.audio)) + publishSettings.putMap("video", this.getHmsVideoSettings(hmsPublishSettings.video)) + publishSettings.putMap("screen", this.getHmsVideoSettings(hmsPublishSettings.screen)) publishSettings.putMap("videoSimulcastLayers", null) publishSettings.putMap("screenSimulcastLayers", null) - publishSettings.putArray( - "allowed", - if (hmsPublishSettings.allowed != null) getWriteableArray(hmsPublishSettings.allowed) - else emptyArray - ) + publishSettings.putArray("allowed", this.getWriteableArray(hmsPublishSettings.allowed)) } return publishSettings } - fun getWriteableArray(array: List?): WritableArray { + private fun getWriteableArray(array: List?): WritableArray { val decodedArray: WritableArray = Arguments.createArray() if (array != null) { for (value in array) { @@ -202,165 +151,116 @@ object HmsDecoder { return decodedArray } - fun getHmsAudioSettings(hmsAudioSettings: AudioParams?): WritableMap { + private fun getHmsAudioSettings(hmsAudioSettings: AudioParams?): WritableMap { val audioSettings: WritableMap = Arguments.createMap() if (hmsAudioSettings != null) { audioSettings.putInt("bitRate", hmsAudioSettings.bitRate) - audioSettings.putString("codec", hmsAudioSettings.codec.toString()) + audioSettings.putString("codec", hmsAudioSettings.codec.name) } return audioSettings } - fun getHmsVideoSettings(hmsVideoSettings: VideoParams?): WritableMap { + private fun getHmsVideoSettings(hmsVideoSettings: VideoParams?): WritableMap { val videoSettings: WritableMap = Arguments.createMap() if (hmsVideoSettings != null) { videoSettings.putInt("bitRate", hmsVideoSettings.bitRate) videoSettings.putInt("frameRate", hmsVideoSettings.frameRate) videoSettings.putInt("width", hmsVideoSettings.width) videoSettings.putInt("height", hmsVideoSettings.height) - videoSettings.putString("codec", hmsVideoSettings.codec.toString()) + videoSettings.putString("codec", hmsVideoSettings.codec.name) } return videoSettings } - // fun getHmsSimulcastLayers(videoSimulcastLayers: HMSSimulcastSettingsPolicy?): WritableMap { - // val videoLayers: WritableMap = Arguments.createMap(); - // if(videoSimulcastLayers != null) { - // videoLayers.putInt("width", videoSimulcastLayers.width); - // videoLayers.putString("height", videoSimulcastLayers.height); - // videoLayers.putArray("layers", - // getHmsSimulcastLayerSettingsPolicy(videoSimulcastLayers.layers)); - // } - // return videoLayers; - // } - - // fun getHmsSimulcastLayerSettingsPolicy(layers: HMSSimulcastLayerSettingsPolicy?): - // WritableArray { - // val layersSettingsPolicy: WritableArray = Arguments.createArray(); - // val hmsLayersSettingsPolicy: WritableMap = Arguments.createMap(); - // if(layers != null) { - // hmsLayersSettingsPolicy.putString("rid", layers.rid); - // hmsLayersSettingsPolicy.putInt("scaleResolutionDownBy", if (layers.scaleResolutionDownBy - // != null) layers.scaleResolutionDownBy else 0); - // hmsLayersSettingsPolicy.putInt("maxBitrate", if (layers.maxBitrate != null) - // layers.maxBitrate else -1); - // hmsLayersSettingsPolicy.putInt("maxFramerate", if (layers.maxFramerate != null) - // layers.maxFramerate else -1); - // } - // layersSettingsPolicy.pushMap(hmsLayersSettingsPolicy) - // return layersSettingsPolicy; - // } - fun getHmsLocalPeer(hmsLocalPeer: HMSLocalPeer?): WritableMap { val peer: WritableMap = Arguments.createMap() if (hmsLocalPeer != null) { peer.putString("peerID", hmsLocalPeer.peerID) peer.putString("name", hmsLocalPeer.name) peer.putBoolean("isLocal", hmsLocalPeer.isLocal) - peer.putString( - "customerUserID", - if (hmsLocalPeer.customerUserID != null) hmsLocalPeer.customerUserID else "" - ) - peer.putString("metadata", if (hmsLocalPeer.metadata != null) hmsLocalPeer.metadata else "") - peer.putMap("audioTrack", getHmsAudioTrack(hmsLocalPeer.audioTrack)) - peer.putMap("videoTrack", getHmsVideoTrack(hmsLocalPeer.videoTrack)) - peer.putMap("role", getHmsRole(hmsLocalPeer.hmsRole)) - - var auxiliaryTracks: WritableArray = Arguments.createArray() - for (track in hmsLocalPeer.auxiliaryTracks) { - auxiliaryTracks.pushMap(getHmsTrack(track)) - } - peer.putArray("auxiliaryTracks", auxiliaryTracks) - - val localAudioTrack = hmsLocalPeer.audioTrack - var localAudioTrackData: WritableMap = Arguments.createMap() - localAudioTrackData.putString("trackId", localAudioTrack?.trackId) - localAudioTrackData.putString("source", localAudioTrack?.source) - localAudioTrackData.putString("trackDescription", localAudioTrack?.description) - localAudioTrackData.putMap("settings", getHmsAudioTrackSettings(localAudioTrack?.settings)) - if (localAudioTrack != null) { - localAudioTrackData.putBoolean("isMute", localAudioTrack.isMute) - } - peer.putMap("localAudioTrackData", localAudioTrackData) - - val localVideoTrack = hmsLocalPeer.videoTrack - var localVideoTrackData: WritableMap = Arguments.createMap() - localVideoTrackData.putString("trackId", localVideoTrack?.trackId) - localVideoTrackData.putString("source", localVideoTrack?.source) - localVideoTrackData.putString("trackDescription", localVideoTrack?.description) - localVideoTrackData.putMap("settings", getHmsVideoTrackSettings(localVideoTrack?.settings)) - if (localVideoTrack != null) { - localVideoTrackData.putBoolean("isMute", localVideoTrack.isMute) - } - peer.putMap("localVideoTrackData", localVideoTrackData) + peer.putString("customerUserID", hmsLocalPeer.customerUserID) + peer.putString("metadata", hmsLocalPeer.metadata) + peer.putMap("audioTrack", this.getHmsAudioTrack(hmsLocalPeer.audioTrack)) + peer.putMap("videoTrack", this.getHmsVideoTrack(hmsLocalPeer.videoTrack)) + peer.putMap("role", this.getHmsRole(hmsLocalPeer.hmsRole)) + peer.putArray("auxiliaryTracks", this.getAllTracks(hmsLocalPeer.auxiliaryTracks)) + peer.putMap("localAudioTrackData", this.getHmsLocalAudioTrack(hmsLocalPeer.audioTrack)) + peer.putMap("localVideoTrackData", this.getHmsLocalVideoTrack(hmsLocalPeer.videoTrack)) } return peer } - fun getHmsAudioTrackSettings(hmsAudioTrackSettings: HMSAudioTrackSettings?): WritableMap { + private fun getHmsLocalAudioTrack(track: HMSLocalAudioTrack?): WritableMap { + val hmsTrack: WritableMap = Arguments.createMap() + if (track != null) { + hmsTrack.putDouble("volume", track.volume) + hmsTrack.putMap("settings", this.getHmsAudioTrackSettings(track.settings)) + hmsTrack.putString("trackId", track.trackId) + hmsTrack.putString("source", track.source) + hmsTrack.putString("trackDescription", track.description) + hmsTrack.putBoolean("isMute", track.isMute) + hmsTrack.putString("type", track.type.name) + } + return hmsTrack + } + + private fun getHmsLocalVideoTrack(track: HMSLocalVideoTrack?): WritableMap { + val hmsTrack: WritableMap = Arguments.createMap() + if (track != null) { + hmsTrack.putBoolean("isDegraded", track.isDegraded) + hmsTrack.putMap("settings", this.getHmsVideoTrackSettings(track.settings)) + hmsTrack.putString("trackId", track.trackId) + hmsTrack.putString("source", track.source) + hmsTrack.putString("trackDescription", track.description) + hmsTrack.putBoolean("isMute", track.isMute) + hmsTrack.putString("type", track.type.name) + } + return hmsTrack + } + + private fun getHmsAudioTrackSettings(hmsAudioTrackSettings: HMSAudioTrackSettings?): WritableMap { val settings: WritableMap = Arguments.createMap() if (hmsAudioTrackSettings != null) { settings.putInt("maxBitrate", hmsAudioTrackSettings.maxBitrate) - // settings.putString("trackDescription", hmsAudioTrackSettings.trackDescription); + settings.putDouble("volume", hmsAudioTrackSettings.volume) + settings.putBoolean( + "useHardwareAcousticEchoCanceler", + hmsAudioTrackSettings.useHardwareAcousticEchoCanceler + ) + settings.putString("codec", hmsAudioTrackSettings.codec.name) settings.putString("trackDescription", "") } return settings } - fun getHmsVideoTrackSettings(hmsVideoTrackSettings: HMSVideoTrackSettings?): WritableMap { + private fun getHmsVideoTrackSettings(hmsVideoTrackSettings: HMSVideoTrackSettings?): WritableMap { val settings: WritableMap = Arguments.createMap() if (hmsVideoTrackSettings != null) { - settings.putString("codec", getHmsVideoTrackCodec(hmsVideoTrackSettings.codec)) - - val resolution: WritableMap = Arguments.createMap() - resolution.putInt("height", hmsVideoTrackSettings.resolution.height) - resolution.putInt("width", hmsVideoTrackSettings.resolution.width) - settings.putMap("resolution", resolution) - + settings.putString("codec", hmsVideoTrackSettings.codec.name) settings.putInt("maxBitrate", hmsVideoTrackSettings.maxBitRate) settings.putInt("maxFrameRate", hmsVideoTrackSettings.maxFrameRate) - settings.putString( - "cameraFacing", - getHmsVideoTrackCameraFacing(hmsVideoTrackSettings.cameraFacing) + settings.putString("cameraFacing", hmsVideoTrackSettings.cameraFacing.name) + settings.putString("trackDescription", hmsVideoTrackSettings.codec.name) + settings.putMap( + "resolution", + this.getHmsVideoTrackResolution(hmsVideoTrackSettings.resolution) ) - // settings.putString("trackDescription", - // if(hmsVideoTrackSettings.trackDescription!==null)hmsVideoTrackSettings.trackDescription - // else ""); - settings.putString("trackDescription", "") } return settings } - fun getHmsVideoTrackCodec(codec: HMSVideoCodec): String { - return when (codec) { - HMSVideoCodec.H264 -> { - "h264" - } - HMSVideoCodec.VP9 -> { - "vp9" - } - HMSVideoCodec.VP8 -> { - "vp8" - } - } - } - - fun getHmsVideoTrackCameraFacing(cameraFacing: HMSVideoTrackSettings.CameraFacing): String { - return when (cameraFacing) { - HMSVideoTrackSettings.CameraFacing.FRONT -> { - "FRONT" - } - HMSVideoTrackSettings.CameraFacing.BACK -> { - "BACK" - } - } + private fun getHmsVideoTrackResolution(hmsResolution: HMSVideoResolution): WritableMap { + val resolution: WritableMap = Arguments.createMap() + resolution.putInt("height", hmsResolution.height) + resolution.putInt("width", hmsResolution.width) + return resolution } fun getHmsRemotePeers(remotePeers: Array?): WritableArray { val peers: WritableArray = Arguments.createArray() if (remotePeers != null) { for (peer in remotePeers) { - peers.pushMap(getHmsRemotePeer(peer)) + peers.pushMap(this.getHmsRemotePeer(peer)) } } return peers @@ -372,70 +272,54 @@ object HmsDecoder { peer.putString("peerID", hmsRemotePeer.peerID) peer.putString("name", hmsRemotePeer.name) peer.putBoolean("isLocal", hmsRemotePeer.isLocal) - peer.putString( - "customerUserID", - if (hmsRemotePeer.customerUserID != null) hmsRemotePeer.customerUserID else "" - ) - peer.putString("metadata", if (hmsRemotePeer.metadata != null) hmsRemotePeer.metadata else "") - peer.putMap("audioTrack", getHmsAudioTrack(hmsRemotePeer.audioTrack)) - peer.putMap("videoTrack", getHmsVideoTrack(hmsRemotePeer.videoTrack)) - peer.putMap("role", getHmsRole(hmsRemotePeer.hmsRole)) - - var auxiliaryTracks: WritableArray = Arguments.createArray() - for (track in hmsRemotePeer.auxiliaryTracks) { - auxiliaryTracks.pushMap(getHmsTrack(track)) - } - peer.putArray("auxiliaryTracks", auxiliaryTracks) - - val remoteAudioTrack = hmsRemotePeer.audioTrack - var remoteAudioTrackData: WritableMap = Arguments.createMap() - remoteAudioTrackData.putString("trackId", remoteAudioTrack?.trackId) - remoteAudioTrackData.putString("source", remoteAudioTrack?.source) - remoteAudioTrackData.putString("trackDescription", remoteAudioTrack?.description) - if (remoteAudioTrack != null) { - remoteAudioTrackData.putBoolean("playbackAllowed", remoteAudioTrack.isPlaybackAllowed) - remoteAudioTrackData.putBoolean("isMute", remoteAudioTrack.isMute) - } - // remoteAudioTrackData.putMap("settings", - // getHmsAudioTrackSettings(remoteAudioTrack.settings)); - remoteAudioTrackData.putMap("settings", null) - peer.putMap("remoteAudioTrackData", remoteAudioTrackData) - - val remoteVideoTrack = hmsRemotePeer.videoTrack - var remoteVideoTrackData: WritableMap = Arguments.createMap() - remoteVideoTrackData.putString("trackId", remoteVideoTrack?.trackId) - remoteVideoTrackData.putString("source", remoteVideoTrack?.source) - remoteVideoTrackData.putString("trackDescription", remoteVideoTrack?.description) - if (remoteVideoTrack != null) { - remoteVideoTrackData.putBoolean("playbackAllowed", remoteVideoTrack.isPlaybackAllowed) - remoteVideoTrackData.putBoolean("isMute", remoteVideoTrack.isMute) - } - // remoteVideoTrackData.putMap("settings", - // getHmsVideoTrackSettings(remoteVideoTrack.settings)); - remoteVideoTrackData.putMap("settings", null) - peer.putMap("remoteVideoTrackData", remoteVideoTrackData) + peer.putString("customerUserID", hmsRemotePeer.customerUserID) + peer.putString("metadata", hmsRemotePeer.metadata) + peer.putMap("audioTrack", this.getHmsAudioTrack(hmsRemotePeer.audioTrack)) + peer.putMap("videoTrack", this.getHmsVideoTrack(hmsRemotePeer.videoTrack)) + peer.putMap("role", this.getHmsRole(hmsRemotePeer.hmsRole)) + peer.putArray("auxiliaryTracks", this.getAllTracks(hmsRemotePeer.auxiliaryTracks)) + peer.putMap("remoteAudioTrackData", this.getHmsRemoteAudioTrack(hmsRemotePeer.audioTrack)) + peer.putMap("remoteVideoTrackData", this.getHmsRemoteVideoTrack(hmsRemotePeer.videoTrack)) } return peer } + private fun getHmsRemoteAudioTrack(track: HMSRemoteAudioTrack?): WritableMap { + val hmsTrack: WritableMap = Arguments.createMap() + if (track != null) { + hmsTrack.putBoolean("isPlaybackAllowed", track.isPlaybackAllowed) + hmsTrack.putString("trackId", track.trackId) + hmsTrack.putString("source", track.source) + hmsTrack.putString("trackDescription", track.description) + hmsTrack.putBoolean("isMute", track.isMute) + hmsTrack.putString("type", track.type.name) + } + return hmsTrack + } + + private fun getHmsRemoteVideoTrack(track: HMSRemoteVideoTrack?): WritableMap { + val hmsTrack: WritableMap = Arguments.createMap() + if (track != null) { + hmsTrack.putBoolean("isDegraded", track.isDegraded) + hmsTrack.putBoolean("isPlaybackAllowed", track.isPlaybackAllowed) + hmsTrack.putString("trackId", track.trackId) + hmsTrack.putString("source", track.source) + hmsTrack.putString("trackDescription", track.description) + hmsTrack.putBoolean("isMute", track.isMute) + hmsTrack.putString("type", track.type.name) + } + return hmsTrack + } + fun getPreviewTracks(tracks: Array?): WritableMap { val hmsTracks: WritableMap = Arguments.createMap() if (tracks != null) { for (track: HMSTrack in tracks) { if (track is HMSLocalVideoTrack) { - val localVideoTrackData: WritableMap = Arguments.createMap() - localVideoTrackData.putString("trackId", track.trackId) - localVideoTrackData.putString("source", track.source) - localVideoTrackData.putString("trackDescription", track.description) - localVideoTrackData.putMap("settings", getHmsVideoTrackSettings(track.settings)) - hmsTracks.putMap("videoTrack", localVideoTrackData) + hmsTracks.putMap("videoTrack", this.getHmsLocalVideoTrack(track)) } if (track is HMSLocalAudioTrack) { - val localAudioTrackData: WritableMap = Arguments.createMap() - localAudioTrackData.putString("trackId", track.trackId) - localAudioTrackData.putString("source", track.source) - localAudioTrackData.putMap("settings", getHmsAudioTrackSettings(track.settings)) - hmsTracks.putMap("audioTrack", localAudioTrackData) + hmsTracks.putMap("audioTrack", this.getHmsLocalAudioTrack(track)) } } } @@ -445,19 +329,20 @@ object HmsDecoder { fun getHmsRoleChangeRequest(request: HMSRoleChangeRequest, id: String?): WritableMap { val roleChangeRequest: WritableMap = Arguments.createMap() if (id != null) { - roleChangeRequest.putMap("requestedBy", getHmsPeer(request.requestedBy)) - roleChangeRequest.putMap("suggestedRole", getHmsRole(request.suggestedRole)) + roleChangeRequest.putMap("requestedBy", this.getHmsPeer(request.requestedBy)) + roleChangeRequest.putMap("suggestedRole", this.getHmsRole(request.suggestedRole)) roleChangeRequest.putString("id", id) return roleChangeRequest } return roleChangeRequest } - fun getHmsChangeTrackStateRequest(request: HMSChangeTrackStateRequest): WritableMap { + fun getHmsChangeTrackStateRequest(request: HMSChangeTrackStateRequest, id: String): WritableMap { val changeTrackStateRequest: WritableMap = Arguments.createMap() - changeTrackStateRequest.putMap("requestedBy", getHmsPeer(request.requestedBy)) + changeTrackStateRequest.putMap("requestedBy", this.getHmsPeer(request.requestedBy)) changeTrackStateRequest.putString("trackType", request.track.type.name) + changeTrackStateRequest.putString("id", id) return changeTrackStateRequest } @@ -475,7 +360,7 @@ object HmsDecoder { return decodedError } - fun getHMSBrowserRecordingState(data: HMSBrowserRecordingState?): ReadableMap { + private fun getHMSBrowserRecordingState(data: HMSBrowserRecordingState?): ReadableMap { val input = Arguments.createMap() if (data !== null) { input.putBoolean("running", data.running) @@ -484,7 +369,7 @@ object HmsDecoder { return input } - fun getHMSRtmpStreamingState(data: HMSRtmpStreamingState?): ReadableMap { + private fun getHMSRtmpStreamingState(data: HMSRtmpStreamingState?): ReadableMap { val input = Arguments.createMap() if (data !== null) { input.putBoolean("running", data.running) @@ -493,7 +378,7 @@ object HmsDecoder { return input } - fun getHMSServerRecordingState(data: HMSServerRecordingState?): ReadableMap { + private fun getHMSServerRecordingState(data: HMSServerRecordingState?): ReadableMap { val input = Arguments.createMap() if (data !== null) { input.putBoolean("running", data.running) @@ -501,4 +386,63 @@ object HmsDecoder { } return input } + + private fun getHmsSubscribeSettings(hmsSubscribeSettings: SubscribeParams?): WritableMap { + val subscribeSettings: WritableMap = Arguments.createMap() + if (hmsSubscribeSettings != null) { + subscribeSettings.putInt("maxSubsBitRate", hmsSubscribeSettings.maxSubsBitRate) + subscribeSettings.putMap( + "subscribeDegradationParam", + this.getHmsSubscribeDegradationSettings(hmsSubscribeSettings.subscribeDegradationParam) + ) + subscribeSettings.putArray( + "subscribeTo", + this.getWriteableArray(hmsSubscribeSettings.subscribeTo) + ) + } + return subscribeSettings + } + + private fun getHmsSubscribeDegradationSettings( + hmsSubscribeDegradationParams: SubscribeDegradationParams? + ): WritableMap { + val subscribeDegradationParams: WritableMap = Arguments.createMap() + if (hmsSubscribeDegradationParams != null) { + subscribeDegradationParams.putString( + "degradeGracePeriodSeconds", + hmsSubscribeDegradationParams.degradeGracePeriodSeconds.toString() + ) + subscribeDegradationParams.putString( + "packetLossThreshold", + hmsSubscribeDegradationParams.packetLossThreshold.toString() + ) + subscribeDegradationParams.putString( + "recoverGracePeriodSeconds", + hmsSubscribeDegradationParams.recoverGracePeriodSeconds.toString() + ) + } + return subscribeDegradationParams + } + + private fun getAllPeers(peers: Array?): WritableArray { + val decodedPeers: WritableArray = Arguments.createArray() + if (peers != null) { + for (peer in peers) { + val decodedPeer = this.getHmsPeer(peer) + decodedPeers.pushMap(decodedPeer) + } + } + return decodedPeers + } + + private fun getAllTracks(tracks: MutableList?): WritableArray { + val decodedTracks: WritableArray = Arguments.createArray() + if (tracks != null) { + for (track in tracks) { + val decodedTrack = this.getHmsTrack(track) + decodedTracks.pushMap(decodedTrack) + } + } + return decodedTracks + } } diff --git a/android/src/main/java/com/reactnativehmssdk/HmsHelper.kt b/android/src/main/java/com/reactnativehmssdk/HmsHelper.kt index 6f9c3718b..2bb050dfc 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmsHelper.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmsHelper.kt @@ -28,26 +28,11 @@ object HmsHelper { return false } } - "Float" -> { - if (map.getDouble(key) == null) { - return false - } - } - "Boolean" -> { - if (map.getBoolean(key) == null) { - return false - } - } "Array" -> { if (map.getArray(key) == null) { return false } } - "Int" -> { - if (map.getInt(key) == null) { - return false - } - } "Map" -> { if (map.getMap(key) == null) { return false @@ -174,13 +159,17 @@ object HmsHelper { return null } - fun getAudioTrackSettings(data: ReadableMap?): HMSAudioTrackSettings { - val builder = HMSAudioTrackSettings.Builder() + fun getAudioTrackSettings( + data: ReadableMap?, + useHardwareEchoCancellation: Boolean + ): HMSAudioTrackSettings { + val builder = + HMSAudioTrackSettings.Builder() + .setUseHardwareAcousticEchoCanceler(useHardwareEchoCancellation) if (data != null) { val maxBitrate = data.getInt("maxBitrate") val codec = getAudioCodec(data.getString("codec")) - val trackDescription = data.getString("trackDescription") builder.maxBitrate(maxBitrate) builder.codec(codec) @@ -189,7 +178,7 @@ object HmsHelper { return builder.build() } - // TODO: find out a way to set settings required to create HMSVideTrackSettings + // TODO: find out a way to set settings required to create HMSVideoTrackSettings fun getVideoTrackSettings(data: ReadableMap?): HMSVideoTrackSettings { val builder = HMSVideoTrackSettings.Builder() @@ -199,7 +188,6 @@ object HmsHelper { val maxBitrate = data.getInt("maxBitrate") val maxFrameRate = data.getInt("maxFrameRate") val cameraFacing = getCameraFacing(data.getString("cameraFacing")) - val trackDescription = data.getString("trackDescription") builder.codec(codec) builder.cameraFacing(cameraFacing) @@ -212,7 +200,7 @@ object HmsHelper { return builder.build() } - fun getVideoResolution(map: ReadableMap?): HMSVideoResolution? { + private fun getVideoResolution(map: ReadableMap?): HMSVideoResolution? { val width = map?.getDouble("width") val height = map?.getDouble("height") @@ -223,7 +211,7 @@ object HmsHelper { } } - fun getAudioCodec(codecString: String?): HMSAudioCodec { + private fun getAudioCodec(codecString: String?): HMSAudioCodec { when (codecString) { "opus" -> { return HMSAudioCodec.OPUS @@ -232,22 +220,22 @@ object HmsHelper { return HMSAudioCodec.OPUS } - fun getVideoCodec(codecString: String?): HMSVideoCodec { + private fun getVideoCodec(codecString: String?): HMSVideoCodec { when (codecString) { - "h264" -> { + "H264" -> { return HMSVideoCodec.H264 } - "vp8" -> { + "VP8" -> { return HMSVideoCodec.VP8 } - "vp9" -> { + "VP9" -> { return HMSVideoCodec.VP9 } } return HMSVideoCodec.H264 } - fun getCameraFacing(cameraFacing: String?): HMSVideoTrackSettings.CameraFacing { + private fun getCameraFacing(cameraFacing: String?): HMSVideoTrackSettings.CameraFacing { when (cameraFacing) { "FRONT" -> { return HMSVideoTrackSettings.CameraFacing.FRONT @@ -262,10 +250,10 @@ object HmsHelper { fun getHms(credentials: ReadableMap, hmsCollection: MutableMap): HmsSDK? { val id = credentials.getString("id") - if (id != null) { - return hmsCollection[id] + return if (id != null) { + hmsCollection[id] } else { - return null + null } } diff --git a/android/src/main/java/com/reactnativehmssdk/HmsModule.kt b/android/src/main/java/com/reactnativehmssdk/HmsModule.kt index c6b7f97c3..bf8da0fd5 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmsModule.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmsModule.kt @@ -28,14 +28,14 @@ class HmsModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod if (hasItem) { val uuid = UUID.randomUUID() val randomUUIDString = uuid.toString() - val sdkInstance: HmsSDK = HmsSDK(data, this, randomUUIDString, reactApplicationContext) + val sdkInstance = HmsSDK(data, this, randomUUIDString, reactApplicationContext) hmsCollection[randomUUIDString] = sdkInstance callback?.resolve(randomUUIDString) } else { val randomUUIDString = "12345" - val sdkInstance: HmsSDK = HmsSDK(data, this, randomUUIDString, reactApplicationContext) + val sdkInstance = HmsSDK(data, this, randomUUIDString, reactApplicationContext) hmsCollection[randomUUIDString] = sdkInstance @@ -86,45 +86,45 @@ class HmsModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod } @ReactMethod - fun sendBroadcastMessage(data: ReadableMap) { + fun sendBroadcastMessage(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.sendBroadcastMessage(data) + hms?.sendBroadcastMessage(data, callback) } @ReactMethod - fun sendGroupMessage(data: ReadableMap) { + fun sendGroupMessage(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.sendGroupMessage(data) + hms?.sendGroupMessage(data, callback) } @ReactMethod - fun sendDirectMessage(data: ReadableMap) { + fun sendDirectMessage(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.sendDirectMessage(data) + hms?.sendDirectMessage(data, callback) } @ReactMethod - fun changeRole(data: ReadableMap) { + fun changeRole(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.changeRole(data) + hms?.changeRole(data, callback) } @ReactMethod - fun changeTrackState(data: ReadableMap) { + fun changeTrackState(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.changeTrackState(data) + hms?.changeTrackState(data, callback) } @ReactMethod - fun changeTrackStateRoles(data: ReadableMap) { + fun changeTrackStateRoles(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.changeTrackStateRoles(data) + hms?.changeTrackStateRoles(data, callback) } @ReactMethod @@ -135,10 +135,10 @@ class HmsModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod } @ReactMethod - fun removePeer(data: ReadableMap) { + fun removePeer(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.removePeer(data) + hms?.removePeer(data, callback) } @ReactMethod @@ -163,10 +163,10 @@ class HmsModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod } @ReactMethod - fun endRoom(data: ReadableMap) { + fun endRoom(data: ReadableMap, callback: Promise?) { val hms = HmsHelper.getHms(data, hmsCollection) - hms?.endRoom(data) + hms?.endRoom(data, callback) } @ReactMethod diff --git a/android/src/main/java/com/reactnativehmssdk/HmsSDK.kt b/android/src/main/java/com/reactnativehmssdk/HmsSDK.kt index 336611ad7..194d5569f 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmsSDK.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmsSDK.kt @@ -24,13 +24,18 @@ class HmsSDK( var hmsSDK: HMSSDK? = null private var recentRoleChangeRequest: HMSRoleChangeRequest? = null private var changeTrackStateRequest: HMSChangeTrackStateRequest? = null - val delegate: HmsModule = HmsDelegate - val id: String = sdkId - val self = this + private var delegate: HmsModule = HmsDelegate + private var id: String = sdkId + private var self = this init { + var useHardwareEchoCancellation = data?.getBoolean("useHardwareEchoCancellation") + if (useHardwareEchoCancellation == null) { + useHardwareEchoCancellation = false + } val videoSettings = HmsHelper.getVideoTrackSettings(data?.getMap("video")) - val audioSettings = HmsHelper.getAudioTrackSettings(data?.getMap("audio")) + val audioSettings = + HmsHelper.getAudioTrackSettings(data?.getMap("audio"), useHardwareEchoCancellation) val trackSettingsBuilder = HMSTrackSettings.Builder() val trackSettings = trackSettingsBuilder.audio(audioSettings).video(videoSettings).build() @@ -38,7 +43,7 @@ class HmsSDK( this.hmsSDK = HMSSDK.Builder(reactApplicationContext).setTrackSettings(trackSettings).build() } - fun emitRequiredKeysError() { + private fun emitRequiredKeysError() { val data: WritableMap = Arguments.createMap() val hmsError = HMSException( @@ -62,6 +67,15 @@ class HmsSDK( delegate.emitEvent("ON_ERROR", data) } + fun emitHMSSuccess(message: HMSMessage? = null): ReadableMap { + val hmsMessage = + if (message !== null) message.message else "function call executed successfully" + val data: WritableMap = Arguments.createMap() + data.putBoolean("success", true) + data.putString("message", hmsMessage) + return data + } + fun preview(credentials: ReadableMap) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable( @@ -75,40 +89,35 @@ class HmsSDK( credentials.getString("authToken") as String, ) - if (HmsHelper.areAllRequiredKeysAvailable( - credentials, - arrayOf(Pair("endpoint", "String"), Pair("metadata", "String")) - ) - ) { - config = - HMSConfig( - credentials.getString("username") as String, - credentials.getString("authToken") as String, - initEndpoint = credentials.getString("endpoint") as String, - metadata = credentials.getString("metadata") as String, - ) - } else if (HmsHelper.areAllRequiredKeysAvailable( - credentials, - arrayOf(Pair("endpoint", "String")) - ) - ) { - config = - HMSConfig( - credentials.getString("username") as String, - credentials.getString("authToken") as String, - initEndpoint = credentials.getString("endpoint") as String, - ) - } else if (HmsHelper.areAllRequiredKeysAvailable( - credentials, - arrayOf(Pair("metadata", "String")) - ) - ) { - config = - HMSConfig( - credentials.getString("username") as String, - credentials.getString("authToken") as String, - metadata = credentials.getString("metadata") as String, - ) + when { + HmsHelper.areAllRequiredKeysAvailable( + credentials, + arrayOf(Pair("endpoint", "String"), Pair("metadata", "String")) + ) -> { + config = + HMSConfig( + credentials.getString("username") as String, + credentials.getString("authToken") as String, + initEndpoint = credentials.getString("endpoint") as String, + metadata = credentials.getString("metadata") as String, + ) + } + HmsHelper.areAllRequiredKeysAvailable(credentials, arrayOf(Pair("endpoint", "String"))) -> { + config = + HMSConfig( + credentials.getString("username") as String, + credentials.getString("authToken") as String, + initEndpoint = credentials.getString("endpoint") as String, + ) + } + HmsHelper.areAllRequiredKeysAvailable(credentials, arrayOf(Pair("metadata", "String"))) -> { + config = + HMSConfig( + credentials.getString("username") as String, + credentials.getString("authToken") as String, + metadata = credentials.getString("metadata") as String, + ) + } } hmsSDK?.preview( @@ -150,40 +159,35 @@ class HmsSDK( credentials.getString("authToken") as String ) - if (HmsHelper.areAllRequiredKeysAvailable( - credentials, - arrayOf(Pair("endpoint", "String"), Pair("metadata", "String")) - ) - ) { - config = - HMSConfig( - credentials.getString("username") as String, - credentials.getString("authToken") as String, - initEndpoint = credentials.getString("endpoint") as String, - metadata = credentials.getString("metadata") as String, - ) - } else if (HmsHelper.areAllRequiredKeysAvailable( - credentials, - arrayOf(Pair("endpoint", "String")) - ) - ) { - config = - HMSConfig( - credentials.getString("username") as String, - credentials.getString("authToken") as String, - initEndpoint = credentials.getString("endpoint") as String, - ) - } else if (HmsHelper.areAllRequiredKeysAvailable( - credentials, - arrayOf(Pair("metadata", "String")) - ) - ) { - config = - HMSConfig( - credentials.getString("username") as String, - credentials.getString("authToken") as String, - metadata = credentials.getString("metadata") as String, - ) + when { + HmsHelper.areAllRequiredKeysAvailable( + credentials, + arrayOf(Pair("endpoint", "String"), Pair("metadata", "String")) + ) -> { + config = + HMSConfig( + credentials.getString("username") as String, + credentials.getString("authToken") as String, + initEndpoint = credentials.getString("endpoint") as String, + metadata = credentials.getString("metadata") as String, + ) + } + HmsHelper.areAllRequiredKeysAvailable(credentials, arrayOf(Pair("endpoint", "String"))) -> { + config = + HMSConfig( + credentials.getString("username") as String, + credentials.getString("authToken") as String, + initEndpoint = credentials.getString("endpoint") as String, + ) + } + HmsHelper.areAllRequiredKeysAvailable(credentials, arrayOf(Pair("metadata", "String"))) -> { + config = + HMSConfig( + credentials.getString("username") as String, + credentials.getString("authToken") as String, + metadata = credentials.getString("metadata") as String, + ) + } } HMSCoroutineScope.launch { @@ -191,14 +195,14 @@ class HmsSDK( hmsSDK?.join( config, object : HMSUpdateListener { - override fun onChangeTrackStateRequest(request: HMSChangeTrackStateRequest) { + override fun onChangeTrackStateRequest(details: HMSChangeTrackStateRequest) { val decodedChangeTrackStateRequest = - HmsDecoder.getHmsChangeTrackStateRequest(request) + HmsDecoder.getHmsChangeTrackStateRequest(details, id) delegate.emitEvent( "ON_CHANGE_TRACK_STATE_REQUEST", decodedChangeTrackStateRequest ) - changeTrackStateRequest = request + changeTrackStateRequest = details } override fun onRemovedFromRoom(notification: HMSRemovedFromRoom) { @@ -238,16 +242,18 @@ class HmsSDK( delegate.emitEvent("ON_JOIN", data) } - override fun onPeerUpdate(type: HMSPeerUpdate, hmsPeer: HMSPeer) { - val type = type.name + override fun onPeerUpdate(type: HMSPeerUpdate, peer: HMSPeer) { + val updateType = type.name val roomData = HmsDecoder.getHmsRoom(hmsSDK?.getRoom()) val localPeerData = HmsDecoder.getHmsLocalPeer(hmsSDK?.getLocalPeer()) val remotePeerData = HmsDecoder.getHmsRemotePeers(hmsSDK?.getRemotePeers()) + val hmsPeer = HmsDecoder.getHmsPeer(peer) val data: WritableMap = Arguments.createMap() + data.putMap("peer", hmsPeer) data.putMap("room", roomData) - data.putString("type", type) + data.putString("type", updateType) data.putMap("localPeer", localPeerData) data.putArray("remotePeers", remotePeerData) data.putString("id", id) @@ -255,14 +261,14 @@ class HmsSDK( } override fun onRoomUpdate(type: HMSRoomUpdate, hmsRoom: HMSRoom) { - val type = type.name + val updateType = type.name val roomData = HmsDecoder.getHmsRoom(hmsRoom) val localPeerData = HmsDecoder.getHmsLocalPeer(hmsSDK?.getLocalPeer()) val remotePeerData = HmsDecoder.getHmsRemotePeers(hmsSDK?.getRemotePeers()) val data: WritableMap = Arguments.createMap() - data.putString("type", type) + data.putString("type", updateType) data.putMap("room", roomData) data.putMap("localPeer", localPeerData) data.putArray("remotePeers", remotePeerData) @@ -271,15 +277,19 @@ class HmsSDK( } override fun onTrackUpdate(type: HMSTrackUpdate, track: HMSTrack, peer: HMSPeer) { - val type = type.name + val updateType = type.name val localPeerData = HmsDecoder.getHmsLocalPeer(hmsSDK?.getLocalPeer()) val remotePeerData = HmsDecoder.getHmsRemotePeers(hmsSDK?.getRemotePeers()) val roomData = HmsDecoder.getHmsRoom(hmsSDK?.getRoom()) + val hmsPeer = HmsDecoder.getHmsPeer(peer) + val hmsTrack = HmsDecoder.getHmsTrack(track) val data: WritableMap = Arguments.createMap() + data.putMap("peer", hmsPeer) + data.putMap("track", hmsTrack) data.putMap("room", roomData) - data.putString("type", type) + data.putString("type", updateType) data.putMap("localPeer", localPeerData) data.putArray("remotePeers", remotePeerData) data.putString("id", id) @@ -334,9 +344,9 @@ class HmsSDK( val peers: WritableArray = Arguments.createArray() for (speaker in speakers) { val speakerArray: WritableMap = Arguments.createMap() - speakerArray.putMap("peer", HmsDecoder.getHmsPeer(speaker?.peer)) - speakerArray.putInt("level", speaker?.level) - speakerArray.putMap("track", HmsDecoder.getHmsTrack(speaker?.hmsTrack)) + speakerArray.putMap("peer", HmsDecoder.getHmsPeer(speaker.peer)) + speakerArray.putInt("level", speaker.level) + speakerArray.putMap("track", HmsDecoder.getHmsTrack(speaker.hmsTrack)) peers.pushMap(speakerArray) } data.putArray("peers", peers) @@ -359,14 +369,14 @@ class HmsSDK( val remotePeerData = HmsDecoder.getHmsRemotePeers(hmsSDK?.getRemotePeers()) val roomData = HmsDecoder.getHmsRoom(hmsSDK?.getRoom()) - val data: WritableMap = Arguments.createMap() + val map: WritableMap = Arguments.createMap() - data.putMap("room", roomData) - data.putString("type", type) - data.putMap("localPeer", localPeerData) - data.putArray("remotePeers", remotePeerData) - data.putString("id", id) - delegate.emitEvent("ON_TRACK_UPDATE", data) + map.putMap("room", roomData) + map.putString("type", type) + map.putMap("localPeer", localPeerData) + map.putArray("remotePeers", remotePeerData) + map.putString("id", id) + delegate.emitEvent("ON_TRACK_UPDATE", map) } fun setLocalVideoMute(data: ReadableMap) { @@ -375,7 +385,7 @@ class HmsSDK( } fun switchCamera() { - if (hmsSDK?.getLocalPeer()?.videoTrack?.isMute ?: true) {} else { + if (hmsSDK?.getLocalPeer()?.videoTrack?.isMute == false) { HMSCoroutineScope.launch { hmsSDK?.getLocalPeer()?.videoTrack?.switchCamera() } } } @@ -384,18 +394,18 @@ class HmsSDK( hmsSDK?.leave( object : HMSActionResultListener { override fun onSuccess() { - callback?.resolve("") + callback?.resolve(emitHMSSuccess()) } override fun onError(error: HMSException) { - callback?.reject("101", "NOT_FOUND") + callback?.reject(error.code.toString(), error.message) self.emitHMSError(error) } } ) } - fun sendBroadcastMessage(data: ReadableMap) { + fun sendBroadcastMessage(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable(data, arrayOf(Pair("message", "String"))) if (requiredKeys) { @@ -409,16 +419,20 @@ class HmsSDK( object : HMSMessageResultListener { override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) + } + override fun onSuccess(hmsMessage: HMSMessage) { + callback?.resolve(emitHMSSuccess(hmsMessage)) } - override fun onSuccess(hmsMessage: HMSMessage) {} } ) } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun sendGroupMessage(data: ReadableMap) { + fun sendGroupMessage(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable( data, @@ -442,17 +456,21 @@ class HmsSDK( object : HMSMessageResultListener { override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) + } + override fun onSuccess(hmsMessage: HMSMessage) { + callback?.resolve(emitHMSSuccess(hmsMessage)) } - override fun onSuccess(hmsMessage: HMSMessage) {} } ) } } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun sendDirectMessage(data: ReadableMap) { + fun sendDirectMessage(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable( data, @@ -475,17 +493,21 @@ class HmsSDK( object : HMSMessageResultListener { override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) + } + override fun onSuccess(hmsMessage: HMSMessage) { + callback?.resolve(emitHMSSuccess(hmsMessage)) } - override fun onSuccess(hmsMessage: HMSMessage) {} } ) } } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun changeRole(data: ReadableMap) { + fun changeRole(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable( data, @@ -502,13 +524,16 @@ class HmsSDK( if (hmsRole != null && hmsPeer != null) { hmsSDK?.changeRole( - hmsPeer as HMSRemotePeer, + hmsPeer, hmsRole, force, object : HMSActionResultListener { - override fun onSuccess() {} + override fun onSuccess() { + callback?.resolve(emitHMSSuccess()) + } override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) } } ) @@ -516,10 +541,11 @@ class HmsSDK( } } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun changeTrackState(data: ReadableMap) { + fun changeTrackState(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable( data, @@ -535,19 +561,23 @@ class HmsSDK( track, mute, object : HMSActionResultListener { - override fun onSuccess() {} + override fun onSuccess() { + callback?.resolve(emitHMSSuccess()) + } override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) } } ) } } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun changeTrackStateRoles(data: ReadableMap) { + fun changeTrackStateRoles(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable( data, @@ -573,14 +603,18 @@ class HmsSDK( source, encodedTargetedRoles, object : HMSActionResultListener { - override fun onSuccess() {} + override fun onSuccess() { + callback?.resolve(emitHMSSuccess()) + } override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) } } ) } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } @@ -605,11 +639,11 @@ class HmsSDK( callback?.resolve(mute) } } else { - callback?.reject("102", "REQUIRED_KEYS_NOT_AVAILABLE") + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun removePeer(data: ReadableMap) { + fun removePeer(data: ReadableMap, callback: Promise?) { val requiredKeys = HmsHelper.areAllRequiredKeysAvailable(data, arrayOf(Pair("peerId", "String"))) if (requiredKeys) { @@ -629,19 +663,25 @@ class HmsSDK( peer, reason, object : HMSActionResultListener { - override fun onSuccess() {} + override fun onSuccess() { + callback?.resolve(emitHMSSuccess()) + } override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) } } ) + } else { + callback?.reject("101", "PEER_NOT_FOUND") } } else { self.emitRequiredKeysError() + callback?.reject("101", "REQUIRED_KEYS_NOT_FOUND") } } - fun endRoom(data: ReadableMap) { + fun endRoom(data: ReadableMap, callback: Promise?) { val lock = data.getBoolean("lock") var reason = data.getString("reason") if (reason == null) { @@ -652,9 +692,12 @@ class HmsSDK( reason, lock, object : HMSActionResultListener { - override fun onSuccess() {} + override fun onSuccess() { + callback?.resolve(emitHMSSuccess()) + } override fun onError(error: HMSException) { self.emitHMSError(error) + callback?.reject(error.code.toString(), error.message) } } ) @@ -687,19 +730,17 @@ class HmsSDK( for (remotePeer in peers) { val peerId = remotePeer.peerID val peer = HmsHelper.getRemotePeerFromPeerId(peerId, peers) - if (peerId != null) { - peer?.audioTrack?.isPlaybackAllowed = !mute - } + peer?.audioTrack?.isPlaybackAllowed = !mute } val localPeerData = HmsDecoder.getHmsLocalPeer(hmsSDK?.getLocalPeer()) val remotePeerData = HmsDecoder.getHmsRemotePeers(hmsSDK?.getRemotePeers()) - val data: WritableMap = Arguments.createMap() + val map: WritableMap = Arguments.createMap() - data.putMap("localPeer", localPeerData) - data.putArray("remotePeers", remotePeerData) - data.putString("id", id) - delegate.emitEvent("ON_PEER_UPDATE", data) + map.putMap("localPeer", localPeerData) + map.putArray("remotePeers", remotePeerData) + map.putString("id", id) + delegate.emitEvent("ON_PEER_UPDATE", map) } } else { this.emitRequiredKeysError() @@ -736,14 +777,18 @@ class HmsSDK( val remotePeers = hmsSDK?.getRemotePeers() val remoteAudioTrack = HmsHelper.getRemoteAudioTrackFromTrackId(trackId, remotePeers) val remoteVideoTrack = HmsHelper.getRemoteVideoTrackFromTrackId(trackId, remotePeers) - if (remoteAudioTrack != null) { - val isPlaybackAllowed = remoteAudioTrack.isPlaybackAllowed - callback?.resolve(isPlaybackAllowed) - } else if (remoteVideoTrack != null) { - val isPlaybackAllowed = remoteVideoTrack.isPlaybackAllowed - callback?.resolve(isPlaybackAllowed) - } else { - callback?.reject("101", "NOT_FOUND") + when { + remoteAudioTrack != null -> { + val isPlaybackAllowed = remoteAudioTrack.isPlaybackAllowed + callback?.resolve(isPlaybackAllowed) + } + remoteVideoTrack != null -> { + val isPlaybackAllowed = remoteVideoTrack.isPlaybackAllowed + callback?.resolve(isPlaybackAllowed) + } + else -> { + callback?.reject("101", "NOT_FOUND") + } } } else { callback?.reject("101", "TRACK_ID_NOT_FOUND") @@ -752,7 +797,6 @@ class HmsSDK( fun getRoom(callback: Promise?) { val roomData = HmsDecoder.getHmsRoom(hmsSDK?.getRoom()) - callback?.resolve(roomData) } @@ -827,14 +871,10 @@ class HmsSDK( metadata, object : HMSActionResultListener { override fun onSuccess() { - val result: WritableMap = Arguments.createMap() - - result.putBoolean("success", true) - - callback?.resolve(result) + callback?.resolve(emitHMSSuccess()) } override fun onError(error: HMSException) { - callback?.reject(error.message, error.description) + callback?.reject(error.code.toString(), error.message) self.emitHMSError(error) } } @@ -853,7 +893,7 @@ class HmsSDK( ) if (requiredKeys) { val record = data.getBoolean("record") - var meetingURL = data.getString("meetingURL") as String + val meetingURL = data.getString("meetingURL") as String var rtmpURLs = data.getArray("rtmpURLs") if (rtmpURLs == null) { rtmpURLs = Arguments.createArray() @@ -865,12 +905,10 @@ class HmsSDK( config, object : HMSActionResultListener { override fun onSuccess() { - val result: WritableMap = Arguments.createMap() - result.putBoolean("success", true) - callback?.resolve(result) + callback?.resolve(emitHMSSuccess()) } override fun onError(error: HMSException) { - callback?.reject(error.message, error.description) + callback?.reject(error.code.toString(), error.message) self.emitHMSError(error) } } @@ -885,12 +923,10 @@ class HmsSDK( hmsSDK?.stopRtmpAndRecording( object : HMSActionResultListener { override fun onSuccess() { - val result: WritableMap = Arguments.createMap() - result.putBoolean("success", true) - callback?.resolve(result) + callback?.resolve(emitHMSSuccess()) } override fun onError(error: HMSException) { - callback?.reject(error.message, error.description) + callback?.reject(error.code.toString(), error.message) self.emitHMSError(error) } } diff --git a/android/src/main/java/com/reactnativehmssdk/HmsView.kt b/android/src/main/java/com/reactnativehmssdk/HmsView.kt index 44a468ecf..4b7a02879 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmsView.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmsView.kt @@ -1,21 +1,21 @@ package com.reactnativehmssdk +import android.annotation.SuppressLint import android.widget.FrameLayout import com.facebook.react.bridge.ReactContext -import live.hms.video.media.tracks.HMSTrackSource import live.hms.video.media.tracks.HMSTrackType import live.hms.video.media.tracks.HMSVideoTrack import live.hms.video.utils.SharedEglContext import org.webrtc.RendererCommon import org.webrtc.SurfaceViewRenderer +@SuppressLint("ViewConstructor") class HmsView(context: ReactContext) : FrameLayout(context) { - private var surfaceView: SurfaceViewRenderer + private var surfaceView: SurfaceViewRenderer = SurfaceViewRenderer(context) private var videoTrack: HMSVideoTrack? = null private var localTrack: String? = null init { - surfaceView = SurfaceViewRenderer(context) surfaceView.setEnableHardwareScaler(true) surfaceView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT) addView(surfaceView) @@ -58,11 +58,10 @@ class HmsView(context: ReactContext) : FrameLayout(context) { fun setData( id: String?, trackId: String?, - sink: Boolean?, hmsCollection: MutableMap, mirror: Boolean? ) { - var sdkId: String = "12345" + var sdkId = "12345" if (id != null) { sdkId = id @@ -81,26 +80,21 @@ class HmsView(context: ReactContext) : FrameLayout(context) { } val remotePeers = hms.getRemotePeers() - if (remotePeers !== null) { - for (peer in remotePeers) { - val videoTrackId = peer.videoTrack?.trackId + for (peer in remotePeers) { + val videoTrackId = peer.videoTrack?.trackId - val auxiliaryTracks = peer.auxiliaryTracks - for (track in auxiliaryTracks) { - val auxTrackId = track.trackId - if (trackId == auxTrackId && - track.type == HMSTrackType.VIDEO && - !track.isMute - ) { - videoTrack = track as HMSVideoTrack - return - } - } - if (videoTrackId == localTrack) { - videoTrack = peer.videoTrack + val auxiliaryTracks = peer.auxiliaryTracks + for (track in auxiliaryTracks) { + val auxTrackId = track.trackId + if (trackId == auxTrackId && track.type == HMSTrackType.VIDEO && !track.isMute) { + videoTrack = track as HMSVideoTrack return } } + if (videoTrackId == localTrack) { + videoTrack = peer.videoTrack + return + } } } } diff --git a/android/src/main/java/com/reactnativehmssdk/HmssdkPackage.kt b/android/src/main/java/com/reactnativehmssdk/HmssdkPackage.kt index 767dc05b7..40306d2a2 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmssdkPackage.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmssdkPackage.kt @@ -4,7 +4,6 @@ import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager -import java.util.* class HmssdkPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List { @@ -12,6 +11,6 @@ class HmssdkPackage : ReactPackage { } override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return Arrays.asList>(HmssdkViewManager()) + return listOf>(HmssdkViewManager()) } } diff --git a/android/src/main/java/com/reactnativehmssdk/HmssdkViewManager.kt b/android/src/main/java/com/reactnativehmssdk/HmssdkViewManager.kt index abaf93f00..7b20fab30 100644 --- a/android/src/main/java/com/reactnativehmssdk/HmssdkViewManager.kt +++ b/android/src/main/java/com/reactnativehmssdk/HmssdkViewManager.kt @@ -13,26 +13,21 @@ class HmssdkViewManager : SimpleViewManager() { return REACT_CLASS } - override fun onDropViewInstance(view: HmsView) { - super.onDropViewInstance(view) - } - public override fun createViewInstance(reactContext: ThemedReactContext): HmsView { this.reactContext = reactContext - val view = HmsView(reactContext) - return view + return HmsView(reactContext) } @ReactProp(name = "data") fun setData(view: HmsView, data: ReadableMap) { val trackId = data.getString("trackId") - val sink = data.getBoolean("sink") + // val sink = data.getBoolean("sink") val id = data.getString("id") val mirror = data.getBoolean("mirror") val hmsCollection = getHms() if (hmsCollection != null) { - view.setData(id, trackId, sink, hmsCollection, mirror) + view.setData(id, trackId, hmsCollection, mirror) } // do the processing here } @@ -43,8 +38,7 @@ class HmssdkViewManager : SimpleViewManager() { } private fun getHms(): MutableMap? { - val hmsCollection = reactContext?.getNativeModule(HmsModule::class.java)?.getHmsInstance() - return hmsCollection + return reactContext?.getNativeModule(HmsModule::class.java)?.getHmsInstance() } companion object { diff --git a/documentation/features/event-listeners-enums.mdx b/documentation/features/event-listeners-enums.mdx index 2ccd99e82..f2c1bf06e 100644 --- a/documentation/features/event-listeners-enums.mdx +++ b/documentation/features/event-listeners-enums.mdx @@ -15,6 +15,7 @@ hmsInstance?.addEventListener( ); const onPeerListener = ({ type } : { + peer: HMSPeer; room?: HMSRoom; type?: HMSPeerUpdate; localPeer: HMSLocalPeer; @@ -35,6 +36,9 @@ const onPeerListener = ({ type } : { if(type === HMSPeerUpdate.ROLE_CHANGED){ // when a peer's role is changed } + if(type === HMSPeerUpdate.METADATA_CHANGED){ + // when a peer's metadata is changed + } if(type === HMSPeerUpdate.BECAME_DOMINANT_SPEAKER){ // when a peer becomes dominant speaker } @@ -65,6 +69,8 @@ hmsInstance?.addEventListener( ); const onTrackListener = ({ type } : { + peer: HMSPeer; + track: HMSTrack; room?: HMSRoom; type?: HMSTrackUpdate; localPeer: HMSLocalPeer; diff --git a/documentation/features/event-listeners.mdx b/documentation/features/event-listeners.mdx index 051c3b0a9..f01a3cfa6 100644 --- a/documentation/features/event-listeners.mdx +++ b/documentation/features/event-listeners.mdx @@ -11,6 +11,9 @@ import HmsManager, { HMSException, HMSMessage, HMSLeaveRoomRequest, + HMSSpeakerUpdate, + HMSPeer, + HMSTrack } from '@100mslive/react-native-hms'; const hmsInstance = await HmsManager.build(); @@ -39,7 +42,17 @@ hmsInstance.addEventListener( onRoomListener ); -const onRoomListener = ({ localPeer, remotePeers }) => { +const onRoomListener = ({ + room, + type, + localPeer, + remotePeers, +}:{ + room?: HMSRoom; + type?: HMSRoomUpdate; + localPeer: HMSLocalPeer; + remotePeers: HMSRemotePeer[]; +}) => { // gets triggered when room is muted or unmuted. // use these objects to update your local and remote peers. }; @@ -49,7 +62,19 @@ hmsInstance.addEventListener( onPeerListener ); -const onPeerListener = ({ localPeer, remotePeers }) => { +const onPeerListener = ({ + room, + type, + remotePeers, + localPeer, + peer, +}: { + room?: HMSRoom; + type?: HMSPeerUpdate; + localPeer: HMSLocalPeer; + remotePeers: HMSRemotePeer[]; + peer: HMSPeer; +}) => { // gets triggered when peer leaves, joins, peer's audio or video is muted, starts or stops speaking, role is changed or becomes dominant speaker. // use these objects to update your local and remote peers. }; @@ -59,7 +84,21 @@ hmsInstance.addEventListener( onTrackListener ); -const onTrackListener = ({ localPeer, remotePeers }) => { +const onTrackListener = ({ + track, + peer, + room, + type, + remotePeers, + localPeer, +}: { + track: HMSTrack; + peer: HMSPeer; + room?: HMSRoom; + type?: HMSTrackUpdate; + localPeer: HMSLocalPeer; + remotePeers: HMSRemotePeer[]; +}) => { // gets triggered when track is added, removed, muted, unmuted, degraded and restored back. // use these objects to update your local and remote peers. }; @@ -89,7 +128,7 @@ hmsInstance.addEventListener( onSpeakerListener ); -const onSpeakerListener = ({ peers }) => { +const onSpeakerListener = (data: HMSSpeakerUpdate) => { // gets triggered whenever someone speaks // an array of speakers is received. Use it to highlight the speakers. }; diff --git a/documentation/features/recording.mdx b/documentation/features/recording.mdx new file mode 100644 index 000000000..5f498f3c3 --- /dev/null +++ b/documentation/features/recording.mdx @@ -0,0 +1,113 @@ +--- +title: RTMP Streaming / Recording +nav: 3.991 +--- + +Want to preserve your video call for posterity in a recording? Or live stream it out to millions of viewers on Twitch or YouTube or whatever gives you an RTMP injest URL? + +Turn on RTMP Streaming or Recording! + +In 100ms, recording and streaming is usually achieved by having a bot join your room and stream what it sees and hears to a file (recording) or to an rtmp injest url (streaming). + +The topics covered in this doc are: + +1. How to start streaming / recording. +2. How to stop streaming / recording. +3. How to check the current status for streaming / recording. + +### Starting Streaming / Recording + + +To start recording, streaming or both, create an instance of HMSRTMPConfig. + +HMSRTMPConfig takes the following: + +1. meetingUrl: String. The url the 100ms bot user will open to join your room. It must allow access without any user level interaction. +2. rtmpUrls: `Array`. If streaming is required, this has to be one or more RTMP Injest Urls where the stream should go. If only recording, this can be an empty list. +3. record: Boolean. If recording is required, set true. If recording is not required, set false. This value has no effect on streaming. + +* If both rtmpUrls and record = true are provided, both streaming and recording will begin. +* If only rtmpUrls are provided, only streaming will begin. +* If only record true is provided, only recording will begin. + +If either one is started, the other can't be started without first stopping whatever is running. Eg: Only streaming is started. Recording can't be started unless streaming is stopped first. + +If both are required, they have to be started together by providing both RTMP Injest Urls and recording = true. + +The result of the action is returned. On failure to start then an error will be sent in onError listener. + +```js +import { HMSRTMPConfig } from '@100mslive/react-native-hms'; + +const recordingDetails = HMSRTMPConfig({ + record: true, + meetingURL: roomID + '/viewer?token=beam_recording', + rtmpURLs: [], +}); + +const result = await instance?.startRTMPOrRecording(recordingDetails); +``` + + +### Stopping Streaming / Recording + + +To stop streaming AND recording. It is not currently possible to stop just one, whatever is running will be stopped. + +Here's how to stop both: + +The result of the action is returned. On failure to start then an error will be sent in onError listener. + + + +```js +const result = await instance?.stopRtmpAndRecording(); +``` + + +### Current Room Status + +The current status for the room is always reflected in the HMSRoom object that is returned from the `hmsInstance.room`. + +Here are the relevant properties inside the HMSRoom object which you can read to get the current recording/streaming status of the room namely: rtmpHMSRtmpStreamingState, browserRecordingState and serverRecordingState. + +Each of them are objects which contain a boolean running which lets you know if it's active on the room right now and error which lets you know if there was an error. + +Apart from the rtmp stream and the browser recording, which are ones you can start and stop, there is also a serverRecording, which can be turned on for the room for archival purposes and which cannot currently be stopped if enabled for the room from the dashboard. + +1. rtmpHMSRtmpStreamingState an instance of HMSRtmpStreamingState, which looks like: + +```js +class HMSRtmpStreamingState( + val running : Boolean, + val error : HMSException? +) +``` + + +This represents a livestream to one or more RTMP urls. + +2. browserRecordingState an instance of HMSBrowserRecordingState, which looks like: + +```js +class HMSBrowserRecordingState( + val running : Boolean, + val error : HMSException? +) +``` + + +This represents the recording that can be requested to start. + +3. serverRecordingState an instance of HMSServerRecordingState, which looks like: +```js +class HMSServerRecordingState( + val running : Boolean, + val error : HMSException? +) +``` + + +This represents that the room was set to be recorded when it was created and all sessions within it will always be recorded for archival by the server. + + diff --git a/documentation/features/render-video.mdx b/documentation/features/render-video.mdx index 00b444dfe..21b2736c0 100644 --- a/documentation/features/render-video.mdx +++ b/documentation/features/render-video.mdx @@ -100,3 +100,13 @@ const onTrackListener = ({ updateVideoIds(remotePeers, localPeer); }; ``` + + + +## Troubleshooting in HmsView + +If a video renders for the first time and then it doesn't appear at all this can be due to the usage of multiple instances. + +However we will recommend you to use a single instance approach if possible, which means once you call a build method and get a hms instance from that save that instance in a global state. Do not call the build method again and again as it will return a new hms instance every time. + +If you need to use a multiple instance approach according to your usage then we recommend you to use the HmsView from the instance as shown above. Do not use the HmsView from the exports of the package, this export will be discarded in the upcoming versions. diff --git a/documentation/features/track-settings.mdx b/documentation/features/track-settings.mdx index 423aa709c..14d0de300 100644 --- a/documentation/features/track-settings.mdx +++ b/documentation/features/track-settings.mdx @@ -52,7 +52,7 @@ const getTrackSettings = () => { }); let videoSettings = new HMSVideoTrackSettings({ - codec: HMSVideoCodec.vp8, + codec: HMSVideoCodec.VP8, maxBitrate: 512, maxFrameRate: 25, cameraFacing: HMSCameraFacing.FRONT, diff --git a/documentation/foundation/security-and-tokens.mdx b/documentation/foundation/security-and-tokens.mdx index d7ccd615d..30cff60df 100644 --- a/documentation/foundation/security-and-tokens.mdx +++ b/documentation/foundation/security-and-tokens.mdx @@ -5,6 +5,12 @@ nav: 1.3 +## Management Token + +Any service calling 100ms' REST APIs need to authenticate using a management token. The service required to generate this token should be hosted on your server + +### Sample management token generation code + @@ -62,7 +68,7 @@ def generateManagementToken(): 'iat': now, 'exp': exp, 'nbf': now - }, key=app_secret).decode('utf-8') + }, key=app_secret) if __name__ == '__main__': @@ -235,7 +241,7 @@ def generate(room_id, user_id, role): "exp": exp, "iat": now, "nbf": now, - }, key=app_secret).decode("utf-8") + }, key=app_secret) if __name__ == "__main__": if len(sys.argv) == 3: room_id = sys.argv[0] diff --git a/documentation/foundation/templates-and-roles.mdx b/documentation/foundation/templates-and-roles.mdx index 0b437e878..7aa9901e2 100644 --- a/documentation/foundation/templates-and-roles.mdx +++ b/documentation/foundation/templates-and-roles.mdx @@ -4,3 +4,7 @@ nav: 1.2 --- + +## API reference + +Apart from the dashboard, a programmatic way to interact with templates is via [API](/server-side/v2/foundation/templates-and-roles#api-reference). diff --git a/documentation/guides/token.mdx b/documentation/guides/token.mdx index be0198458..afda82a2f 100644 --- a/documentation/guides/token.mdx +++ b/documentation/guides/token.mdx @@ -1,6 +1,6 @@ --- title: Auth Token Quickstart Guide -nav: 2.5 +nav: 2.2 --- diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 1bcc94718..0e66e7dc7 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -136,8 +136,8 @@ android { applicationId "live.hms.rn" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 28 - versionName "1.0.28" + versionCode 31 + versionName "1.0.31" } splits { abi { diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 84277f410..29a85c212 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -18,7 +18,8 @@ android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + android:requestLegacyExternalStorage="true"> =0.10.0" } }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + }, "node_modules/base/node_modules/define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", @@ -11463,6 +11470,11 @@ "react": "^17.0.0" } }, + "node_modules/react-native-share": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-7.3.2.tgz", + "integrity": "sha512-1E2xxTzHYrV74WMuBz6VLx6Y9slBBNI9s0NxXDEYb0VsFT6DcHnbiaY4ExW5E6vw37s3gfZxm4zsv9/TwFEukA==" + }, "node_modules/react-native-simple-toast": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/react-native-simple-toast/-/react-native-simple-toast-1.1.3.tgz", @@ -12399,6 +12411,31 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rn-fetch-blob": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz", + "integrity": "sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==", + "dependencies": { + "base-64": "0.1.0", + "glob": "7.0.6" + } + }, + "node_modules/rn-fetch-blob/node_modules/glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, "node_modules/rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -17849,6 +17886,11 @@ } } }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -23607,6 +23649,11 @@ } } }, + "react-native-share": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-7.3.2.tgz", + "integrity": "sha512-1E2xxTzHYrV74WMuBz6VLx6Y9slBBNI9s0NxXDEYb0VsFT6DcHnbiaY4ExW5E6vw37s3gfZxm4zsv9/TwFEukA==" + }, "react-native-simple-toast": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/react-native-simple-toast/-/react-native-simple-toast-1.1.3.tgz", @@ -24057,6 +24104,30 @@ "glob": "^7.1.3" } }, + "rn-fetch-blob": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz", + "integrity": "sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==", + "requires": { + "base-64": "0.1.0", + "glob": "7.0.6" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", diff --git a/example/package.json b/example/package.json index b67f0feda..26ffb463d 100644 --- a/example/package.json +++ b/example/package.json @@ -25,11 +25,13 @@ "react-native-permissions": "^3.0.5", "react-native-safe-area-context": "^3.3.0", "react-native-screens": "^3.5.0", + "react-native-share": "^7.3.2", "react-native-simple-toast": "^1.1.3", "react-native-vector-icons": "^8.1.0", "react-redux": "^7.2.4", "redux": "^4.1.0", - "redux-devtools-extension": "^2.13.9" + "redux-devtools-extension": "^2.13.9", + "rn-fetch-blob": "^0.12.0" }, "devDependencies": { "@babel/core": "^7.12.9", diff --git a/example/src/navigator/index.tsx b/example/src/navigator/index.tsx index 51c7ad776..518701856 100644 --- a/example/src/navigator/index.tsx +++ b/example/src/navigator/index.tsx @@ -1,7 +1,6 @@ import React from 'react'; import {createStackNavigator} from '@react-navigation/stack'; import {NavigationContainer} from '@react-navigation/native'; -import AppWelcomeScreen from '../screens/Home'; import WelcomeScreen from '../screens/WelcomeScreen'; import Meeting from '../screens/Meeting'; @@ -20,11 +19,6 @@ const navigationOptions = { const AppStackNavigator = () => ( - { - return ( - - Welcome - - ); -}; - -export default Home; diff --git a/example/src/screens/Meeting.tsx b/example/src/screens/Meeting.tsx index 7b39cb27a..40ba8448d 100644 --- a/example/src/screens/Meeting.tsx +++ b/example/src/screens/Meeting.tsx @@ -10,6 +10,7 @@ import { BackHandler, Platform, TextInput, + PermissionsAndroid, } from 'react-native'; import {connect} from 'react-redux'; import { @@ -43,6 +44,8 @@ import {getDeviceType} from 'react-native-device-info'; import {Slider} from '@miblanchard/react-native-slider'; import type {StackNavigationProp} from '@react-navigation/stack'; import Toast from 'react-native-simple-toast'; +import RNFetchBlob from 'rn-fetch-blob'; +import {Picker} from '@react-native-picker/picker'; import {ChatWindow, AlertModal, CustomModal, CustomPicker} from '../components'; import { @@ -55,6 +58,7 @@ import { getThemeColour, getInitials, pairDataForScrollView, + writeFile, } from '../utils/functions'; import type {RootState} from '../redux'; import type {AppStackParamList} from '../navigator'; @@ -87,6 +91,7 @@ type DisplayTrackProps = { type: 'local' | 'remote' | 'screen'; instance: HMSSDK | undefined; permissions: HMSPermissions | undefined; + layout?: LayoutParams; }; type MeetingProps = { @@ -110,6 +115,8 @@ const DEFAULT_PEER: Peer = { type: 'local', }; +type LayoutParams = 'audio' | 'normal'; + type MeetingScreenProp = StackNavigationProp; const DisplayTrack = ({ @@ -119,6 +126,7 @@ const DisplayTrack = ({ type, instance, permissions, + layout, }: DisplayTrackProps) => { const { name, @@ -184,9 +192,9 @@ const DisplayTrack = ({ ] = [ {text: 'Cancel'}, { - text: 'Send', - onPress: () => { - instance?.changeRole(peerRefrence!, newRole!, force); + text: force ? 'Set' : 'Send', + onPress: async () => { + await instance?.changeRole(peerRefrence!, newRole!, force); }, }, ]; @@ -205,9 +213,15 @@ const DisplayTrack = ({ }, ]; + const selectLocalActionButtons: Array<{ + text: string; + type?: string; + onPress?: Function; + }> = [{text: 'Cancel', type: 'cancel'}]; + const selectActionTitle = 'Select action'; const selectActionMessage = ''; - const selectActionButtons: Array<{ + const selectRemoteActionButtons: Array<{ text: string; type?: string; onPress?: Function; @@ -241,7 +255,14 @@ const DisplayTrack = ({ }, ]; if (permissions?.changeRole) { - selectActionButtons.push( + selectLocalActionButtons.push({ + text: 'Change Role', + onPress: () => { + setForce(true); + setRoleModalVisible(true); + }, + }); + selectRemoteActionButtons.push( ...[ { text: 'Prompt to change role', @@ -261,20 +282,20 @@ const DisplayTrack = ({ ); } if (permissions?.removeOthers) { - selectActionButtons.push({ + selectRemoteActionButtons.push({ text: 'Remove Participant', - onPress: () => { - instance?.removePeer(id!, 'removed from room'); + onPress: async () => { + await instance?.removePeer(id!, 'removed from room'); }, }); } if (permissions?.unmute) { const unmute = false; if (isAudioMute) { - selectActionButtons.push({ + selectRemoteActionButtons.push({ text: 'Unmute audio', - onPress: () => { - instance?.changeTrackState( + onPress: async () => { + await instance?.changeTrackState( peerRefrence?.audioTrack as HMSTrack, unmute, ); @@ -282,10 +303,10 @@ const DisplayTrack = ({ }); } if (isVideoMute) { - selectActionButtons.push({ + selectRemoteActionButtons.push({ text: 'Unmute video', - onPress: () => { - instance?.changeTrackState( + onPress: async () => { + await instance?.changeTrackState( peerRefrence?.videoTrack as HMSTrack, unmute, ); @@ -296,10 +317,10 @@ const DisplayTrack = ({ if (permissions?.mute) { const mute = true; if (!isAudioMute) { - selectActionButtons.push({ + selectRemoteActionButtons.push({ text: 'Mute audio', - onPress: () => { - instance?.changeTrackState( + onPress: async () => { + await instance?.changeTrackState( peerRefrence?.audioTrack as HMSTrack, mute, ); @@ -307,10 +328,10 @@ const DisplayTrack = ({ }); } if (!isVideoMute) { - selectActionButtons.push({ + selectRemoteActionButtons.push({ text: 'Mute video', - onPress: () => { - instance?.changeTrackState( + onPress: async () => { + await instance?.changeTrackState( peerRefrence?.videoTrack as HMSTrack, mute, ); @@ -340,7 +361,7 @@ const DisplayTrack = ({ dimension.viewHeight(90) + (isTab ? dimension.viewHeight(20) : top + bottom) + 2)) / - 2 + (layout === 'audio' ? 3 : 2) : Dimensions.get('window').height - (Platform.OS === 'ios' ? 0 : 25) - (dimension.viewHeight(50) + @@ -348,118 +369,119 @@ const DisplayTrack = ({ (isTab ? dimension.viewHeight(20) : top + bottom) + 2); - if (HmsViewComponent) { - return ( - - + + + setVolume(value[0])} /> - - setVolume(value[0])} + + + + + {isVideoMute || layout === 'audio' ? ( + + + {getInitials(name!)} + + + ) : isDegraded ? ( + + Degraded + + ) : ( + + )} + {metadata?.isHandRaised === true && ( + + - - - + )} + {type === 'screen' || + (type === 'local' && selectLocalActionButtons.length > 1) || + (type === 'remote' && selectRemoteActionButtons.length > 1) ? ( + + - - {isVideoMute ? ( - - - {getInitials(name!)} - - - ) : isDegraded ? ( - - Degraded - - ) : ( - + ) : ( + <> + )} + + + + {name} + + + + + + + - )} - {metadata?.isHandRaised === true && ( - - - - )} - {type === 'screen' || - (type === 'remote' && selectActionButtons.length > 1) ? ( - - - - ) : ( - <> - )} - - - - {name} - - - - - - - - - ); - } else { - return null; - } + + ) : ( + <> + ); }; const Meeting = ({ @@ -483,6 +505,8 @@ const Meeting = ({ suggestedRole?: string; }>({}); const [action, setAction] = useState(0); + const [layout, setLayout] = useState('normal'); + const [newLayout, setNewLayout] = useState('normal'); const [newRole, setNewRole] = useState(trackId?.peerRefrence?.role); const [roleModalVisible, setRoleModalVisible] = useState(false); const [settingsModal, setSettingsModal] = useState(false); @@ -490,18 +514,21 @@ const Meeting = ({ const [recordingDetails, setRecordingDetails] = useState({ record: false, meetingURL: state.user.roomID - ? state.user.roomID + '/viewer?token=beam_recording' + ? state.user.roomID + '?token=beam_recording' : '', rtmpURLs: [], }); const [roleChangeModalVisible, setRoleChangeModalVisible] = useState(false); + const [layoutModal, setLayoutModal] = useState(false); const [changeTrackStateModalVisible, setChangeTrackStateModalVisible] = useState(false); const [leaveModalVisible, setLeaveModalVisible] = useState(false); const [localPeerPermissions, setLocalPeerPermissions] = useState(); - const roleChangeRequestTitle = recordingModal + const roleChangeRequestTitle = layoutModal + ? 'Layout Modal' + : recordingModal ? 'Recording Details' : roleChangeModalVisible ? 'Role Change Request' @@ -511,7 +538,17 @@ const Meeting = ({ const roleChangeRequestButtons: [ {text: string; onPress?: Function}, {text: string; onPress?: Function}, - ] = recordingModal + ] = layoutModal + ? [ + {text: 'Cancel'}, + { + text: 'Set', + onPress: async () => { + setLayout(newLayout); + }, + }, + ] + : recordingModal ? [ {text: 'Cancel'}, { @@ -569,7 +606,7 @@ const Meeting = ({ const pairedPeers: Array> = pairDataForScrollView( [...auxTracks, trackId, ...remoteTrackIds], - isPortrait() ? 4 : 2, + isPortrait() ? (layout === 'audio' ? 6 : 4) : 2, ); const decodeRemotePeer = ( @@ -709,26 +746,39 @@ const Meeting = ({ }; const onPeerListener = ({ + peer, room, type, remotePeers, localPeer, }: { + peer: HMSPeer; room?: HMSRoom; type?: HMSPeerUpdate; localPeer: HMSLocalPeer; remotePeers: HMSRemotePeer[]; }) => { updateVideoIds(remotePeers, localPeer); - console.log('data in onPeerListener: ', room, type, localPeer, remotePeers); + console.log( + 'data in onPeerListener: ', + peer, + room, + type, + localPeer, + remotePeers, + ); }; const onTrackListener = ({ + peer, + track, room, type, remotePeers, localPeer, }: { + peer: HMSPeer; + track: HMSTrack; room?: HMSRoom; type?: HMSTrackUpdate; localPeer: HMSLocalPeer; @@ -737,6 +787,8 @@ const Meeting = ({ updateVideoIds(remotePeers, localPeer); console.log( 'data in onTrackListener: ', + peer, + track, room, type, localPeer, @@ -767,10 +819,12 @@ const Meeting = ({ const reconnecting = (data: any) => { console.log(data); + Toast.showWithGravity('Reconnecting...', Toast.LONG, Toast.TOP); }; const reconnected = (data: any) => { console.log(data); + Toast.showWithGravity('Reconnected', Toast.LONG, Toast.TOP); }; const onRoleChangeRequest = (data: HMSRoleChangeRequest) => { @@ -933,6 +987,18 @@ const Meeting = ({ text: 'Cancel', type: 'cancel', }, + { + text: 'Report issue and share logs', + onPress: async () => { + await checkPermissionToWriteExternalStroage(); + }, + }, + { + text: 'Set Layout', + onPress: () => { + setLayoutModal(true); + }, + }, { text: 'Start RTMP or Recording', onPress: () => { @@ -1003,11 +1069,11 @@ const Meeting = ({ {text: 'Cancel'}, { text: 'Send', - onPress: () => { + onPress: async () => { const source = 'regular'; switch (action) { case 1: - instance?.changeTrackStateRoles( + await instance?.changeTrackStateRoles( HMSTrackType.VIDEO, true, source, @@ -1015,7 +1081,7 @@ const Meeting = ({ ); break; case 2: - instance?.changeTrackStateRoles( + await instance?.changeTrackStateRoles( HMSTrackType.VIDEO, false, source, @@ -1023,7 +1089,7 @@ const Meeting = ({ ); break; case 3: - instance?.changeTrackStateRoles( + await instance?.changeTrackStateRoles( HMSTrackType.AUDIO, true, source, @@ -1031,7 +1097,7 @@ const Meeting = ({ ); break; case 4: - instance?.changeTrackStateRoles( + await instance?.changeTrackStateRoles( HMSTrackType.AUDIO, false, source, @@ -1064,7 +1130,7 @@ const Meeting = ({ buttons.push({ text: 'End Room for all', onPress: async () => { - instance?.endRoom(false, 'Host ended the room'); + await instance?.endRoom(false, 'Host ended the room'); clearMessageRequest(); navigate('WelcomeScreen'); }, @@ -1119,6 +1185,53 @@ const Meeting = ({ } }); + const checkPermissionToWriteExternalStroage = async () => { + // Function to check the platform + // If Platform is Android then check for permissions. + if (Platform.OS === 'ios') { + await reportIssue(); + } else { + try { + const granted = await PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, + { + title: 'Storage Permission Required', + message: + 'Application needs access to your storage to download File', + buttonPositive: 'true', + }, + ); + if (granted === PermissionsAndroid.RESULTS.GRANTED) { + // Start downloading + await reportIssue(); + console.log('Storage Permission Granted.'); + } else { + // If permission denied then show alert + Toast.showWithGravity( + 'Storage Permission Not Granted', + Toast.LONG, + Toast.TOP, + ); + } + } catch (err) { + // To handle permission related exception + console.log('++++' + err); + } + } + }; + + const reportIssue = async () => { + try { + const fileUrl = RNFetchBlob.fs.dirs.DocumentDir + '/report-logs.json'; + const logger = HMSSDK.getLogger(); + const logs = logger?.getLogs(); + console.log(logs); + await writeFile({data: logs}, fileUrl); + } catch (err) { + console.log(err, 'error'); + } + }; + return ( + + + {[{name: 'normal'}, {name: 'audio'}].map((item, index) => ( + + ))} + + {trackId?.name} @@ -1318,6 +1446,7 @@ const Meeting = ({ instance={instance} type={view.type} permissions={localPeerPermissions} + layout={layout} /> )), )} @@ -1421,7 +1550,7 @@ const Meeting = ({ setNotification(false); }} messageToList={getMessageToList()} - send={( + send={async ( value: string, messageTo: {name: string; type: string; obj: any}, ) => { @@ -1432,11 +1561,11 @@ const Meeting = ({ message: value, }); if (messageTo?.type === 'everyone') { - instance?.sendBroadcastMessage(value); + await instance?.sendBroadcastMessage(value); } else if (messageTo?.type === 'group') { - instance?.sendGroupMessage(value, [messageTo?.obj]); + await instance?.sendGroupMessage(value, [messageTo?.obj]); } else if (messageTo.type === 'direct') { - instance?.sendDirectMessage(value, messageTo?.obj?.id); + await instance?.sendDirectMessage(value, messageTo?.obj?.id); } addMessageRequest({ data: hmsMessage, diff --git a/example/src/screens/WelcomeScreen.tsx b/example/src/screens/WelcomeScreen.tsx index 9ba04f2b0..f61e1730d 100644 --- a/example/src/screens/WelcomeScreen.tsx +++ b/example/src/screens/WelcomeScreen.tsx @@ -29,12 +29,15 @@ import HmsManager, { HMSVideoCodec, HMSTrackSettings, HMSException, + HMSCameraFacing, + HMSVideoResolution, } from '@100mslive/react-native-hms'; import {useNavigation} from '@react-navigation/native'; import type {StackNavigationProp} from '@react-navigation/stack'; import {PERMISSIONS, RESULTS, requestMultiple} from 'react-native-permissions'; import Feather from 'react-native-vector-icons/Feather'; import Toast from 'react-native-simple-toast'; +import {getModel} from 'react-native-device-info'; import * as services from '../services/index'; import {UserIdModal, PreviewModal} from '../components'; @@ -46,8 +49,6 @@ import { import {getThemeColour} from '../utils/functions'; import type {AppStackParamList} from '../navigator'; import type {RootState} from '../redux'; -import {HMSCameraFacing} from '../../../src/classes/HMSCameraFacing'; -import {HMSVideoResolution} from '../../../src/classes/HMSVideoResolution'; type WelcomeProps = { setAudioVideoStateRequest: Function; @@ -176,7 +177,7 @@ const App = ({ trackDescription: 'Simple Audio Track', }); let videoSettings = new HMSVideoTrackSettings({ - codec: HMSVideoCodec.vp8, + codec: HMSVideoCodec.VP8, maxBitrate: 512, maxFrameRate: 25, cameraFacing: HMSCameraFacing.FRONT, @@ -184,7 +185,29 @@ const App = ({ resolution: new HMSVideoResolution({height: 180, width: 320}), }); - return new HMSTrackSettings({video: videoSettings, audio: audioSettings}); + const listOfFaultyDevices = [ + 'Pixel', + 'Pixel XL', + 'Moto G5', + 'Moto G (5S) Plus', + 'Moto G4', + 'TA-1053', + 'Mi A1', + 'Mi A2', + 'E5823', // Sony z5 compact + 'Redmi Note 5', + 'FP2', // Fairphone FP2 + 'MI 5', + ]; + const deviceModal = getModel(); + + return new HMSTrackSettings({ + video: videoSettings, + audio: audioSettings, + useHardwareEchoCancellation: listOfFaultyDevices.includes(deviceModal) + ? true + : false, + }); }; const setupBuild = async () => { @@ -225,13 +248,9 @@ const App = ({ PERMISSIONS.ANDROID.CAMERA, PERMISSIONS.ANDROID.RECORD_AUDIO, ]) - .then(results => { - if ( - results['android.permission.CAMERA'] === RESULTS.GRANTED && - results['android.permission.RECORD_AUDIO'] === RESULTS.GRANTED - ) { - previewWithLink(token, userID, endpoint); - } + .then(() => { + previewWithLink(token, userID, endpoint); + setButtonState('Active'); }) .catch(error => { console.log(error); diff --git a/example/src/services/index.ts b/example/src/services/index.ts index f92e34993..8f00b4787 100644 --- a/example/src/services/index.ts +++ b/example/src/services/index.ts @@ -7,6 +7,7 @@ export const fetchToken = async ({ userID: string; role: string; }) => { + // TOKEN_ENDPOINT="https://prod-in.100ms.live/hmsapi//api/token" # Valid const endPoint = 'https://prod-in.100ms.live/hmsapi/random.app.100ms.live/api/token'; const body = { diff --git a/example/src/services/navigation.ts b/example/src/services/navigation.ts deleted file mode 100644 index b75aee811..000000000 --- a/example/src/services/navigation.ts +++ /dev/null @@ -1,31 +0,0 @@ -// import {NavigationActions, SwitchActions, StackActions} from 'react-navigation'; - -// const config: {navigator?: any} = {}; - -// // navigate within the stack navigator. -// export const navigate = (path: string) => { -// if (config.navigator) { -// config.navigator.dispatch(NavigationActions.navigate({routeName: path})); -// } -// }; - -// // replace within the stack navigator. -// export const replaceRoute = (path: string) => { -// if (config.navigator) { -// config.navigator.dispatch(StackActions.replace({routeName: path})); -// } -// }; - -// // sets the navigator reference. -// export const setNavigator = (nav: any) => { -// if (nav) { -// config.navigator = nav; -// } -// }; - -// // jump to a navigation stack. -// export const jumpToSwitchNavigatorStack = (screen: string) => { -// if (config.navigator) { -// config.navigator.dispatch(SwitchActions.jumpTo({routeName: screen})); -// } -// }; diff --git a/example/src/utils/functions.ts b/example/src/utils/functions.ts index e5e7728b9..b82484635 100644 --- a/example/src/utils/functions.ts +++ b/example/src/utils/functions.ts @@ -1,3 +1,7 @@ +import {Platform} from 'react-native'; +import RNFetchBlob from 'rn-fetch-blob'; +import Share from 'react-native-share'; + export const getThemeColour = () => '#4578e0'; export const getRandomColor = () => { @@ -84,3 +88,21 @@ export const pairDataForScrollView = (data: Array, batch: number) => { } return pairedData; }; + +export const writeFile = async (content: any, fileUrl: string) => { + await RNFetchBlob.fs + .writeFile(fileUrl, JSON.stringify(content), 'utf8') + .then(() => { + shareFile(fileUrl); + }) + .catch(e => console.error(e)); +}; + +export const shareFile = async (fileUrl: string) => { + await Share.open({ + url: Platform.OS === 'android' ? 'file://' + fileUrl : fileUrl, + type: 'application/json', + }) + .then(success => console.log(success)) + .catch(e => console.error(e)); +}; diff --git a/ios/HmsDecoder.swift b/ios/HmsDecoder.swift index f6a5c4891..571de5912 100644 --- a/ios/HmsDecoder.swift +++ b/ios/HmsDecoder.swift @@ -33,11 +33,7 @@ class HmsDecoder: NSObject { let videoTrack = getHmsVideoTrack(peer.videoTrack) let role = getHmsRole(peer.role) - var auxiliaryTracks = [[String: Any]]() - - for track in peer.auxiliaryTracks ?? [] { - auxiliaryTracks.append(getHmsTrack(track)) - } + let auxiliaryTracks = getAllTracks(peer.auxiliaryTracks ?? [] ) return ["peerID": peerID, "name": name, @@ -51,6 +47,15 @@ class HmsDecoder: NSObject { "role": role] } + static func getAllTracks (_ tracks: [HMSTrack]) -> [[String: Any]] { + var auxiliaryTracks = [[String: Any]]() + + for track in tracks { + auxiliaryTracks.append(getHmsTrack(track)) + } + return auxiliaryTracks + } + static func getHmsTrack (_ track: HMSTrack?) -> [String: Any] { guard let hmsTrack = track else { return [:] } @@ -59,9 +64,9 @@ class HmsDecoder: NSObject { let source = hmsTrack.source let trackDescription = hmsTrack.trackDescription let isMute = hmsTrack.isMute() - let type = HmsHelper.getHmsTrackType(hmsTrack.kind) + let type = HmsHelper.getHmsTrackType(hmsTrack.kind) ?? "" - return ["trackId": trackId, "source": source, "trackDescription": trackDescription, "isMute": isMute, "type": type] + return ["trackId": trackId, "source": source, "trackDescription": trackDescription, "isMute": isMute, "type": type, "kind": type] } static func getHmsAudioTrack (_ hmsAudioTrack: HMSAudioTrack?) -> [String: Any] { @@ -72,8 +77,9 @@ class HmsDecoder: NSObject { let source: String = hmsTrack.source let trackDescription: String = hmsTrack.trackDescription let isMute: Bool = hmsTrack.isMute() + let kind: String = HmsHelper.getHmsTrackType(hmsTrack.kind) ?? "" - return ["trackId": trackId, "source": source, "trackDescription": trackDescription, "isMute": isMute] + return ["trackId": trackId, "source": source, "trackDescription": trackDescription, "isMute": isMute, "type": kind, "kind": kind] } static func getHmsVideoTrack (_ hmsVideoTrack: HMSVideoTrack?) -> [String: Any] { @@ -85,8 +91,9 @@ class HmsDecoder: NSObject { let trackDescription = hmsTrack.trackDescription let isMute = hmsTrack.isMute() let isDegraded = hmsTrack.isDegraded() + let kind: String = HmsHelper.getHmsTrackType(hmsTrack.kind) ?? "" - return ["trackId": trackId, "source": source, "trackDescription": trackDescription, "isMute": isMute, "isDegraded": isDegraded] + return ["trackId": trackId, "source": source, "trackDescription": trackDescription, "isMute": isMute, "isDegraded": isDegraded, "type": kind, "kind": kind] } static func getHmsLocalPeer(_ hmsLocalPeer: HMSLocalPeer?) -> [String: Any] { @@ -113,12 +120,14 @@ class HmsDecoder: NSObject { var localAudioTrackData = [String: Any]() if let localAudio = localAudioTrack { - localAudioTrackData = ["trackId": localAudio.trackId, "source": localAudio.source, "trackDescription": localAudio.trackDescription, "settings": getHmsAudioTrackSettings(localAudio.settings), "isMute": localAudioTrack?.isMute() ?? false] + let type = HmsHelper.getHmsTrackType(localAudio.kind) ?? "" + localAudioTrackData = ["trackId": localAudio.trackId, "source": localAudio.source, "trackDescription": localAudio.trackDescription, "settings": getHmsAudioTrackSettings(localAudio.settings), "isMute": localAudioTrack?.isMute() ?? false, "type": type, "kind": type] } var localVideoTrackData = [String: Any]() if let localVideo = localVideoTrack { - localVideoTrackData = ["trackId": localVideo.trackId, "source": localVideo.source, "trackDescription": localVideo.trackDescription, "settings": getHmsVideoTrackSettings(localVideo.settings), "isMute":localAudioTrack?.isMute() ?? false] + let type = HmsHelper.getHmsTrackType(localVideo.kind) ?? "" + localVideoTrackData = ["trackId": localVideo.trackId, "source": localVideo.source, "trackDescription": localVideo.trackDescription, "settings": getHmsVideoTrackSettings(localVideo.settings), "isMute":localAudioTrack?.isMute() ?? false, "type": type, "kind": type] } return ["peerID": peerID, "name": name, "isLocal": isLocal, "customerUserID": customerUserID, "customerDescription": customerDescription, "metadata": metadata, "audioTrack": audioTrack, "videoTrack": videoTrack, "auxiliaryTracks": auxiliaryTracks, "localAudioTrackData": localAudioTrackData, "localVideoTrackData": localVideoTrackData, "role": role] @@ -162,11 +171,11 @@ class HmsDecoder: NSObject { static func getHmsVideoTrackCodec(_ codec : HMSCodec) -> String { switch(codec) { case HMSCodec.VP8: - return "vp8" + return "VP8" case HMSCodec.H264: - return "h264" + return "H264" default: - return "h264" + return "H264" } } @@ -222,12 +231,14 @@ class HmsDecoder: NSObject { var remoteAudioTrackData = [String: Any]() if let remoteAudio = remoteAudioTrack { - remoteAudioTrackData = ["trackId": remoteAudio.trackId, "source": remoteAudio.source, "trackDescription": remoteAudio.trackDescription, "playbackAllowed": remoteAudio.isPlaybackAllowed(), "isMute": remoteAudio.isMute()] + let type = HmsHelper.getHmsTrackType(remoteAudio.kind) ?? "" + remoteAudioTrackData = ["trackId": remoteAudio.trackId, "source": remoteAudio.source, "trackDescription": remoteAudio.trackDescription, "playbackAllowed": remoteAudio.isPlaybackAllowed(), "isMute": remoteAudio.isMute(), "type": type, "kind": type] } var remoteVideoTrackData = [String: Any]() if let remoteVideo = remoteVideoTrack { - remoteVideoTrackData = ["trackId": remoteVideo.trackId, "source": remoteVideo.source, "trackDescription": remoteVideo.trackDescription, "layer": remoteVideo.layer.rawValue, "playbackAllowed": remoteVideo.isPlaybackAllowed(), "isMute": remoteVideo.isMute()] + let type = HmsHelper.getHmsTrackType(remoteVideo.kind) ?? "" + remoteVideoTrackData = ["trackId": remoteVideo.trackId, "source": remoteVideo.source, "trackDescription": remoteVideo.trackDescription, "layer": remoteVideo.layer.rawValue, "playbackAllowed": remoteVideo.isPlaybackAllowed(), "isMute": remoteVideo.isMute(), "isDegraded": remoteVideo.isDegraded(), "type": type, "kind": type] } return ["peerID": peerID, "name": name, "isLocal": isLocal, "customerUserID": customerUserID, "customerDescription": customerDescription, "metadata": metadata, "audioTrack": audioTrack, "videoTrack": videoTrack, "auxiliaryTracks": auxiliaryTracks, "remoteAudioTrackData": remoteAudioTrackData, "remoteVideoTrackData": remoteVideoTrackData, "role": role] @@ -239,12 +250,14 @@ class HmsDecoder: NSObject { for track in tracks { if let localVideo = track as? HMSLocalVideoTrack { - let localVideoTrackData: [String : Any] = ["trackId": localVideo.trackId, "source": localVideo.source, "trackDescription": localVideo.trackDescription, "settings": getHmsVideoTrackSettings(localVideo.settings), "isMute": localVideo.isMute()] + let type = HmsHelper.getHmsTrackType(localVideo.kind) ?? "" + let localVideoTrackData: [String : Any] = ["trackId": localVideo.trackId, "source": localVideo.source, "trackDescription": localVideo.trackDescription, "settings": getHmsVideoTrackSettings(localVideo.settings), "isMute": localVideo.isMute(), "kind": type, "type": type] hmsTracks["videoTrack"] = localVideoTrackData } if let localAudio = track as? HMSLocalAudioTrack { - let localAudioTrackData: [String : Any] = ["trackId": localAudio.trackId, "source": localAudio.source, "trackDescription": localAudio.trackDescription, "settings": getHmsAudioTrackSettings(localAudio.settings), "isMute": localAudio.isMute()] + let type = HmsHelper.getHmsTrackType(localAudio.kind) ?? "" + let localAudioTrackData: [String : Any] = ["trackId": localAudio.trackId, "source": localAudio.source, "trackDescription": localAudio.trackDescription, "settings": getHmsAudioTrackSettings(localAudio.settings), "isMute": localAudio.isMute(), "kind": type, "type": type] hmsTracks["audioTrack"] = localAudioTrackData } } @@ -397,14 +410,14 @@ class HmsDecoder: NSObject { return [:] } - static func getHmsChangeTrackStateRequest(_ changeTrackStateRequest: HMSChangeTrackStateRequest) -> [String: Any] { + static func getHmsChangeTrackStateRequest(_ changeTrackStateRequest: HMSChangeTrackStateRequest, _ id: String) -> [String: Any] { var requestedBy: [String: Any]? if let peer = changeTrackStateRequest.requestedBy { requestedBy = getHmsPeer(peer) } let trackType = changeTrackStateRequest.track.kind == .video ? "video" : "audio" - var request = ["trackType": trackType] as [String: Any] + var request = ["trackType": trackType, "id": id] as [String: Any] if let requestedBy = requestedBy { request["requestedBy"] = requestedBy } diff --git a/ios/HmsHelper.swift b/ios/HmsHelper.swift index 5de83cd54..17656e8ab 100644 --- a/ios/HmsHelper.swift +++ b/ios/HmsHelper.swift @@ -3,7 +3,17 @@ import Foundation class HmsHelper: NSObject { - static func getPeerFromPeerId(_ peerID: String?, remotePeers: [HMSRemotePeer]?) -> HMSPeer? { + static func getPeerFromPeerId(_ peerID: String?, remotePeers: [HMSRemotePeer]?, localPeer: HMSLocalPeer?) -> HMSPeer? { + + guard let peerID = peerID, let peers = remotePeers else { return nil } + if(peerID == localPeer?.peerID) { + return localPeer + } + return peers.first { $0.peerID == peerID } + } + + + static func getRemotePeerFromPeerId(_ peerID: String?, remotePeers: [HMSRemotePeer]?) -> HMSPeer? { guard let peerID = peerID, let peers = remotePeers else { return nil } @@ -156,9 +166,9 @@ class HmsHelper: NSObject { static func getVideoCodec(_ codecString: String?) -> HMSCodec { switch codecString { - case "h264": + case "H264": return HMSCodec.H264 - case "vp8": + case "VP8": return HMSCodec.VP8 default: return HMSCodec.H264 diff --git a/ios/HmsManager.m b/ios/HmsManager.m index adb9baece..a108cd759 100644 --- a/ios/HmsManager.m +++ b/ios/HmsManager.m @@ -7,15 +7,15 @@ @interface RCT_EXTERN_MODULE(HmsManager, RCTEventEmitter) RCT_EXTERN_METHOD(preview: (NSDictionary) credentials) RCT_EXTERN_METHOD(setLocalMute: (NSDictionary) isMute) RCT_EXTERN_METHOD(setLocalVideoMute: (NSDictionary) isMute) -RCT_EXTERN_METHOD(sendBroadcastMessage: (NSDictionary) data) -RCT_EXTERN_METHOD(sendGroupMessage: (NSDictionary) data) -RCT_EXTERN_METHOD(sendDirectMessage: (NSDictionary) data) +RCT_EXTERN_METHOD(sendBroadcastMessage: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) +RCT_EXTERN_METHOD(sendGroupMessage: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) +RCT_EXTERN_METHOD(sendDirectMessage: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) RCT_EXTERN_METHOD(setPlaybackAllowed: (NSDictionary) data) -RCT_EXTERN_METHOD(removePeer: (NSDictionary) data) -RCT_EXTERN_METHOD(endRoom: (NSDictionary) data) -RCT_EXTERN_METHOD(changeRole: (NSDictionary) data) -RCT_EXTERN_METHOD(changeTrackState: (NSDictionary) data) -RCT_EXTERN_METHOD(changeTrackStateRoles: (NSDictionary) data) +RCT_EXTERN_METHOD(removePeer: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) +RCT_EXTERN_METHOD(endRoom: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) +RCT_EXTERN_METHOD(changeRole: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) +RCT_EXTERN_METHOD(changeTrackState: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) +RCT_EXTERN_METHOD(changeTrackStateRoles: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) RCT_EXTERN_METHOD(acceptRoleChange: (NSDictionary) data) RCT_EXTERN_METHOD(isMute: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) RCT_EXTERN_METHOD(getRoom: (NSDictionary) data :(RCTPromiseResolveBlock) resolve :(RCTPromiseRejectBlock) reject) diff --git a/ios/HmsManager.swift b/ios/HmsManager.swift index e26c35c03..13a3a0ae1 100644 --- a/ios/HmsManager.swift +++ b/ios/HmsManager.swift @@ -99,24 +99,24 @@ class HmsManager: RCTEventEmitter{ } @objc - func sendBroadcastMessage(_ data: NSDictionary) { + func sendBroadcastMessage(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.sendBroadcastMessage(data) + hms?.sendBroadcastMessage(data, resolve, reject) } @objc - func sendGroupMessage(_ data: NSDictionary) { + func sendGroupMessage(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.sendGroupMessage(data) + hms?.sendGroupMessage(data, resolve, reject) } @objc - func sendDirectMessage(_ data: NSDictionary) { + func sendDirectMessage(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.sendDirectMessage(data) + hms?.sendDirectMessage(data, resolve, reject) } @objc @@ -127,24 +127,24 @@ class HmsManager: RCTEventEmitter{ } @objc - func changeRole(_ data: NSDictionary) { + func changeRole(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.changeRole(data) + hms?.changeRole(data, resolve, reject) } @objc - func changeTrackState(_ data: NSDictionary) { + func changeTrackState(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.changeTrackState(data) + hms?.changeTrackState(data, resolve, reject) } @objc - func changeTrackStateRoles(_ data: NSDictionary) { + func changeTrackStateRoles(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.changeTrackStateRoles(data) + hms?.changeTrackStateRoles(data, resolve, reject) } @objc @@ -160,18 +160,18 @@ class HmsManager: RCTEventEmitter{ @objc - func removePeer(_ data: NSDictionary) { + func removePeer(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.removePeer(data) + hms?.removePeer(data, resolve, reject) } @objc - func endRoom(_ data: NSDictionary) { + func endRoom(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { let hms = HmsHelper.getHms(data, hmsCollection) - hms?.endRoom(data) + hms?.endRoom(data, resolve, reject) } @objc diff --git a/ios/HmsSDK.swift b/ios/HmsSDK.swift index 7204b29a1..f3e8841cf 100644 --- a/ios/HmsSDK.swift +++ b/ios/HmsSDK.swift @@ -146,7 +146,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { } } - func sendBroadcastMessage(_ data: NSDictionary) { + func sendBroadcastMessage(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let message = data.value(forKey: "message") as? String else { let error = HMSError(id: "108", code: HMSErrorCode.genericErrorUnknown, message: "REQUIRED_KEYS_NOT_FOUND") @@ -157,11 +157,20 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let type = data.value(forKey: "type") as? String ?? "chat" DispatchQueue.main.async { [weak self] in - self?.hms?.sendBroadcastMessage(type: type, message: message) + self?.hms?.sendBroadcastMessage(type: type, message: message, completion: { message, error in + if (error == nil) { + resolve?(["success": true, "data": ["sender": message?.sender?.name ?? "", "message": message?.message ?? "", "type": message?.type]]) + return + } else { + self?.delegate?.emitEvent("ON_ERROR", ["event": "ON_ERROR", "error": HmsDecoder.getError(error), "id": self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription, nil) + return + } + }) } } - func sendGroupMessage(_ data: NSDictionary) { + func sendGroupMessage(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let message = data.value(forKey: "message") as? String, let targetedRoles = data.value(forKey: "roles") as? [String] else { @@ -173,11 +182,20 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let type = data.value(forKey: "type") as? String ?? "chat" DispatchQueue.main.async { [weak self] in let encodedTargetedRoles = HmsHelper.getRolesFromRoleNames(targetedRoles, roles: self?.hms?.roles) - self?.hms?.sendGroupMessage(type: type, message: message, roles: encodedTargetedRoles) + self?.hms?.sendGroupMessage(type: type, message: message, roles: encodedTargetedRoles, completion: { message, error in + if (error == nil) { + resolve?(["success": true, "data": ["sender": message?.sender?.name ?? "", "message": message?.message ?? "", "type": message?.type]]) + return + } else { + self?.delegate?.emitEvent("ON_ERROR", ["event": "ON_ERROR", "error": HmsDecoder.getError(error), "id": self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription, nil) + return + } + }) } } - func sendDirectMessage(_ data: NSDictionary) { + func sendDirectMessage(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let message = data.value(forKey: "message") as? String, let peerId = data.value(forKey: "peerId") as? String else { @@ -188,7 +206,17 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let type = data.value(forKey: "type") as? String ?? "chat" DispatchQueue.main.async { [weak self] in - guard let peer = HmsHelper.getPeerFromPeerId(peerId, remotePeers: self?.hms?.remotePeers) else { return } + guard let peer = HmsHelper.getRemotePeerFromPeerId(peerId, remotePeers: self?.hms?.remotePeers) else { return } + self?.hms?.sendDirectMessage(type: type, message: message, peer: peer, completion: { message, error in + if (error == nil) { + resolve?(["success": true, "data": ["sender": message?.sender?.name ?? "", "message": message?.message ?? "", "type": message?.type]]) + return + } else { + self?.delegate?.emitEvent("ON_ERROR", ["event": "ON_ERROR", "error": HmsDecoder.getError(error), "id": self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription, nil) + return + } + }) self?.hms?.sendDirectMessage(type: type, message: message, peer: peer) } } @@ -205,7 +233,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { } } - func changeRole(_ data: NSDictionary) { + func changeRole(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let peerId = data.value(forKey: "peerId") as? String, let role = data.value(forKey: "role") as? String @@ -218,15 +246,22 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let force = data.value(forKey: "force") as? Bool ?? false DispatchQueue.main.async { [weak self] in - guard let peer = HmsHelper.getPeerFromPeerId(peerId, remotePeers: self?.hms?.remotePeers), + guard let peer = HmsHelper.getPeerFromPeerId(peerId, remotePeers: self?.hms?.remotePeers, localPeer:self?.hms?.localPeer), let role = HmsHelper.getRoleFromRoleName(role, roles: self?.hms?.roles) else { return } - - self?.hms?.changeRole(for: peer, to: role, force: force) + + self?.hms?.changeRole(for: peer, to: role, force: force, completion: { success, error in + if(success) { + resolve?(["success": true]) + } else{ + self?.delegate?.emitEvent("ON_ERROR", ["event": self?.ON_ERROR ?? "", "error": HmsDecoder.getError(error), "id":self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription,nil) + } + }) } } - func changeTrackState(_ data: NSDictionary) { + func changeTrackState(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let trackId = data.value(forKey: "trackId") as? String else { @@ -242,11 +277,18 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let track = HmsHelper.getTrackFromTrackId(trackId, remotePeers) else { return } - self?.hms?.changeTrackState(for: track, mute: mute) + self?.hms?.changeTrackState(for: track, mute: mute, completion: { success, error in + if(success) { + resolve?(["success": true]) + } else{ + self?.delegate?.emitEvent("ON_ERROR", ["event": self?.ON_ERROR ?? "", "error": HmsDecoder.getError(error), "id":self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription, nil) + } + }) } } - func changeTrackStateRoles(_ data: NSDictionary) { + func changeTrackStateRoles(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let source = data.value(forKey: "source") as? String, let targetedRoles = data.value(forKey: "roles") as? [String], @@ -266,7 +308,14 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { DispatchQueue.main.async { [weak self] in let encodedTargetedRoles = HmsHelper.getRolesFromRoleNames(targetedRoles, roles: self?.hms?.roles) - self?.hms?.changeTrackState(mute: mute, for: decodeType, source: source, roles: encodedTargetedRoles) + self?.hms?.changeTrackState(mute: mute, for: decodeType, source: source, roles: encodedTargetedRoles, completion: { success, error in + if(success) { + resolve?(["success": true]) + } else{ + self?.delegate?.emitEvent("ON_ERROR", ["event": self?.ON_ERROR ?? "", "error": HmsDecoder.getError(error), "id":self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription,nil) + } + }) } } @@ -301,7 +350,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { } } - func removePeer(_ data: NSDictionary) { + func removePeer(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let peerId = data.value(forKey: "peerId") as? String else { @@ -315,15 +364,22 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { DispatchQueue.main.async { [weak self] in guard let remotePeers = self?.hms?.remotePeers, - let peer = HmsHelper.getPeerFromPeerId(peerId, remotePeers: remotePeers) + let peer = HmsHelper.getRemotePeerFromPeerId(peerId, remotePeers: remotePeers) else { return } - self?.hms?.removePeer(peer, reason: reason ?? "Removed from room") + self?.hms?.removePeer(peer, reason: reason ?? "Removed from room", completion: { success, error in + if(success) { + resolve?(["success": true]) + } else{ + self?.delegate?.emitEvent("ON_ERROR", ["event": self?.ON_ERROR ?? "", "error": HmsDecoder.getError(error), "id":self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription,nil) + } + }) } } - func endRoom(_ data: NSDictionary) { + func endRoom(_ data: NSDictionary, _ resolve: RCTPromiseResolveBlock?, _ reject: RCTPromiseRejectBlock?) { guard let lock = data.value(forKey: "lock") as? Bool, let reason = data.value(forKey: "reason") as? String @@ -334,7 +390,14 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { } DispatchQueue.main.async { [weak self] in - self?.hms?.endRoom(lock: lock ?? false, reason: reason ?? "Room was ended") + self?.hms?.endRoom(lock: lock, reason: reason, completion: { success, error in + if(success) { + resolve?(["success": true]) + } else{ + self?.delegate?.emitEvent("ON_ERROR", ["event": self?.ON_ERROR ?? "", "error": HmsDecoder.getError(error), "id":self?.id ?? "12345"]) + reject?(error?.message, error?.localizedDescription,nil) + } + }) } } @@ -548,7 +611,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let decodedRoles = HmsDecoder.getAllRoles(hms?.roles) - self.delegate?.emitEvent(ON_JOIN, ["event": ON_JOIN, "id": self.id ?? "", "room": roomData, "localPeer": localPeerData, "remotePeers": remotePeerData, "roles": decodedRoles]) + self.delegate?.emitEvent(ON_JOIN, ["event": ON_JOIN, "id": self.id , "room": roomData, "localPeer": localPeerData, "remotePeers": remotePeerData, "roles": decodedRoles]) } func onPreview(room: HMSRoom, localTracks: [HMSTrack]) { @@ -556,7 +619,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let hmsRoom = HmsDecoder.getHmsRoom(room) let localPeerData = HmsDecoder.getHmsLocalPeer(hms?.localPeer) - self.delegate?.emitEvent(ON_PREVIEW, ["event": ON_PREVIEW, "id": self.id ?? "", "room": hmsRoom, "previewTracks": previewTracks, "localPeer": localPeerData]) + self.delegate?.emitEvent(ON_PREVIEW, ["event": ON_PREVIEW, "id": self.id , "room": hmsRoom, "previewTracks": previewTracks, "localPeer": localPeerData]) } func on(room: HMSRoom, update: HMSRoomUpdate) { @@ -567,7 +630,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let localPeerData = HmsDecoder.getHmsLocalPeer(hms?.localPeer) let remotePeerData = HmsDecoder.getHmsRemotePeers(hms?.remotePeers) - self.delegate?.emitEvent(ON_ROOM_UPDATE, ["event": ON_ROOM_UPDATE, "id": self.id ?? "", "type": type, "room": roomData, "localPeer": localPeerData, "remotePeers": remotePeerData]) + self.delegate?.emitEvent(ON_ROOM_UPDATE, ["event": ON_ROOM_UPDATE, "id": self.id , "type": type, "room": roomData, "localPeer": localPeerData, "remotePeers": remotePeerData]) } func on(peer: HMSPeer, update: HMSPeerUpdate) { @@ -577,8 +640,9 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let localPeerData = HmsDecoder.getHmsLocalPeer(hms?.localPeer) let remotePeerData = HmsDecoder.getHmsRemotePeers(hms?.remotePeers) + let hmsPeer = HmsDecoder.getHmsPeer(peer) - self.delegate?.emitEvent(ON_PEER_UPDATE, ["event": ON_PEER_UPDATE, "id": self.id ?? "", "type": type, "room": roomData, "localPeer": localPeerData, "remotePeers": remotePeerData]) + self.delegate?.emitEvent(ON_PEER_UPDATE, ["event": ON_PEER_UPDATE, "id": self.id, "type": type, "room": roomData, "localPeer": localPeerData, "remotePeers": remotePeerData, "peer": hmsPeer]) } func on(track: HMSTrack, update: HMSTrackUpdate, for peer: HMSPeer) { @@ -588,8 +652,10 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { let localPeerData = HmsDecoder.getHmsLocalPeer(hms?.localPeer) let remotePeerData = HmsDecoder.getHmsRemotePeers(hms?.remotePeers) + let hmsPeer = HmsDecoder.getHmsPeer(peer) + let hmsTrack = HmsDecoder.getHmsTrack(track) - self.delegate?.emitEvent(ON_TRACK_UPDATE, ["event": ON_TRACK_UPDATE, "id": self.id ?? "", "room": roomData, "type": type, "localPeer": localPeerData, "remotePeers": remotePeerData]) + self.delegate?.emitEvent(ON_TRACK_UPDATE, ["event": ON_TRACK_UPDATE, "id": self.id, "room": roomData, "type": type, "localPeer": localPeerData, "remotePeers": remotePeerData, "peer": hmsPeer, "track": hmsTrack]) } func on(error: HMSError) { @@ -597,7 +663,7 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { } func on(message: HMSMessage) { - self.delegate?.emitEvent(ON_MESSAGE, ["event": ON_MESSAGE, "id": self.id ?? "", "sender": message.sender?.name ?? "", "time": message.time, "message": message.message, "type": message.type]) + self.delegate?.emitEvent(ON_MESSAGE, ["event": ON_MESSAGE, "id": self.id , "sender": message.sender?.name ?? "", "time": message.time, "message": message.message, "type": message.type]) } func on(updated speakers: [HMSSpeaker]) { @@ -605,15 +671,15 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { for speaker in speakers { speakerPeerIds.append(["peer": HmsDecoder.getHmsPeer(speaker.peer), "level": speaker.level, "track": HmsDecoder.getHmsTrack(speaker.track)]) } - self.delegate?.emitEvent(ON_SPEAKER, ["event": ON_SPEAKER, "id": self.id ?? "", "count": speakers.count, "peers" :speakerPeerIds]) + self.delegate?.emitEvent(ON_SPEAKER, ["event": ON_SPEAKER, "id": self.id , "count": speakers.count, "peers" :speakerPeerIds]) } func onReconnecting() { - self.delegate?.emitEvent(RECONNECTING, ["event": RECONNECTING, "id": self.id ?? ""]) + self.delegate?.emitEvent(RECONNECTING, ["event": RECONNECTING, "id": self.id ]) } func onReconnected() { - self.delegate?.emitEvent(RECONNECTED, ["event": RECONNECTED, "id": self.id ?? ""]) + self.delegate?.emitEvent(RECONNECTED, ["event": RECONNECTED, "id": self.id ]) } func on(roleChangeRequest: HMSRoleChangeRequest) { @@ -623,7 +689,9 @@ class HmsSDK: HMSUpdateListener, HMSPreviewListener { } func on(changeTrackStateRequest: HMSChangeTrackStateRequest) { - // On track state change required + let decodedChangeTrackStateRequest = HmsDecoder.getHmsChangeTrackStateRequest(changeTrackStateRequest, id) + delegate?.emitEvent("ON_CHANGE_TRACK_STATE_REQUEST", decodedChangeTrackStateRequest) + recentChangeTrackStateRequest = changeTrackStateRequest } func on(removedFromRoom notification: HMSRemovedFromRoomNotification) { diff --git a/package-lock.json b/package-lock.json index a67add524..4cd3d4e30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@100mslive/react-native-hms", - "version": "0.8.1", + "version": "0.8.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@100mslive/react-native-hms", - "version": "0.8.1", + "version": "0.8.2", "license": "MIT", "devDependencies": { "@commitlint/config-conventional": "^11.0.0", diff --git a/package.json b/package.json index c4662aab1..3b75fa277 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@100mslive/react-native-hms", - "version": "0.8.1", + "version": "0.8.2", "description": "The React Native package for 100ms SDK", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/src/classes/HMSEncoder.ts b/src/classes/HMSEncoder.ts index 61529f8d8..24903fb13 100644 --- a/src/classes/HMSEncoder.ts +++ b/src/classes/HMSEncoder.ts @@ -48,7 +48,7 @@ export class HMSEncoder { role: HMSEncoder.encodeHmsRole(peer?.role), customerUserID: peer?.customerUserID, customerDescription: peer?.customerDescription, - metadata: peer.metadata, + metadata: peer?.metadata, audioTrack: HMSEncoder.encodeHmsAudioTrack(peer?.audioTrack, id), videoTrack: HMSEncoder.encodeHmsVideoTrack(peer?.videoTrack, id), auxiliaryTracks: HMSEncoder.encodeHmsAuxiliaryTracks( @@ -132,6 +132,7 @@ export class HMSEncoder { settings: HMSEncoder.encodeHmsAudioTrackSettings( peer?.localAudioTrackData?.settings ), + type: peer?.localAudioTrackData?.type, }, localVideoTrackData: { id: id, @@ -142,6 +143,7 @@ export class HMSEncoder { settings: HMSEncoder.encodeHmsVideoTrackSettings( peer?.localVideoTrackData?.settings ), + type: peer?.localVideoTrackData?.type, }, }; diff --git a/src/classes/HMSLocalAudioTrack.ts b/src/classes/HMSLocalAudioTrack.ts index 2ca5f699d..022601df1 100644 --- a/src/classes/HMSLocalAudioTrack.ts +++ b/src/classes/HMSLocalAudioTrack.ts @@ -1,5 +1,6 @@ import { NativeModules, Platform } from 'react-native'; import { HMSAudioTrack } from './HMSAudioTrack'; +import { HMSSDK } from './HMSSDK'; import type { HMSAudioTrackSettings } from './HMSAudioTrackSettings'; import type { HMSTrackType } from './HMSTrackType'; @@ -21,10 +22,25 @@ export class HMSLocalAudioTrack extends HMSAudioTrack { * @memberof HMSLocalAudioTrack */ setMute(isMute: boolean) { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function setMute', { + trackId: this.trackId, + id: this.id, + source: this.source, + type: this.type, + isMute, + }); HmsManager.setLocalMute({ isMute, id: this.id }); } getVolume = async () => { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function getVolume', { + trackId: this.trackId, + id: this.id, + source: this.source, + type: this.type, + }); if (Platform.OS === 'ios') { return 'This API not available for IOS'; } diff --git a/src/classes/HMSLocalPeer.ts b/src/classes/HMSLocalPeer.ts index cd6e7c0b6..7ccc969da 100644 --- a/src/classes/HMSLocalPeer.ts +++ b/src/classes/HMSLocalPeer.ts @@ -7,6 +7,7 @@ import type { HMSAudioTrackSettings } from './HMSAudioTrackSettings'; import { HMSLocalAudioTrack } from './HMSLocalAudioTrack'; import { HMSLocalVideoTrack } from './HMSLocalVideoTrack'; import type { HMSRole } from './HMSRole'; +import type { HMSTrackType } from './HMSTrackType'; export class HMSLocalPeer extends HMSPeer { private localAudio?: HMSLocalAudioTrack; @@ -37,6 +38,7 @@ export class HMSLocalPeer extends HMSPeer { trackDescription?: string; isMute?: boolean; settings?: HMSAudioTrackSettings; + type: HMSTrackType; }; localVideoTrackData?: { id: string; @@ -45,6 +47,7 @@ export class HMSLocalPeer extends HMSPeer { trackDescription?: string; isMute?: boolean; settings?: HMSVideoTrackSettings; + type: HMSTrackType; }; }) { super(params); diff --git a/src/classes/HMSLocalVideoTrack.ts b/src/classes/HMSLocalVideoTrack.ts index c53320ddf..0eaaed38e 100644 --- a/src/classes/HMSLocalVideoTrack.ts +++ b/src/classes/HMSLocalVideoTrack.ts @@ -1,5 +1,6 @@ import { NativeModules } from 'react-native'; import { HMSVideoTrack } from './HMSVideoTrack'; +import { HMSSDK } from './HMSSDK'; import type { HMSVideoTrackSettings } from './HMSVideoTrackSettings'; import type { HMSTrackType } from './HMSTrackType'; @@ -22,6 +23,13 @@ export class HMSLocalVideoTrack extends HMSVideoTrack { * @memberof HMSSDK */ switchCamera = () => { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function switchCamera', { + trackId: this.trackId, + source: this.source, + type: this.type, + id: this.id, + }); HmsManager.switchCamera({ id: this.id }); }; @@ -32,6 +40,13 @@ export class HMSLocalVideoTrack extends HMSVideoTrack { * @memberof HMSLocalVideoTrack */ setMute(isMute: boolean) { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function setMute', { + trackId: this.trackId, + source: this.source, + type: this.type, + id: this.id, + }); HmsManager.setLocalVideoMute({ isMute, id: this.id }); } diff --git a/src/classes/HMSLogger.ts b/src/classes/HMSLogger.ts index f036c7eca..c7d0ae04f 100644 --- a/src/classes/HMSLogger.ts +++ b/src/classes/HMSLogger.ts @@ -4,6 +4,12 @@ export class HMSLogger { private _verbose: boolean = false; private _warning: boolean = false; private _error: boolean = false; + private logs: { + type: 'verbose' | 'warn' | 'error'; + message: string; + data: any; + id: string; + }[] = []; constructor(params?: { verbose: boolean; warning: boolean; error: boolean }) { if (params) { @@ -14,21 +20,28 @@ export class HMSLogger { } verbose(message: string, data: any) { - if (this._verbose === true) { + if (this._verbose) { console.log(message, data); } + this.logs.push({ type: 'verbose', message, data, id: data?.id }); } warn(message: string, data: any) { if (this._warning) { console.warn(message, data); } + this.logs.push({ type: 'warn', message, data, id: data?.id }); } error(message: string, data: any) { if (this._error) { console.error(message, data); } + this.logs.push({ type: 'error', message, data, id: data?.id }); + } + + getLogs() { + return this.logs; } updateLogLevel(level: HMSLogLevel, value: boolean) { diff --git a/src/classes/HMSRemoteAudioTrack.ts b/src/classes/HMSRemoteAudioTrack.ts index a0f5064fe..c70b3bcbb 100644 --- a/src/classes/HMSRemoteAudioTrack.ts +++ b/src/classes/HMSRemoteAudioTrack.ts @@ -1,4 +1,5 @@ import { NativeModules } from 'react-native'; +import { HMSSDK } from './HMSSDK'; import type { HMSTrackType } from './HMSTrackType'; import { HMSAudioTrack } from './HMSAudioTrack'; @@ -17,6 +18,14 @@ export class HMSRemoteAudioTrack extends HMSAudioTrack { * @memberof HMSRemoteAudioTrack */ setPlaybackAllowed(playbackAllowed: boolean) { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function setPlaybackAllowed', { + trackId: this.trackId, + id: this.id, + source: this.source, + type: this.type, + playbackAllowed, + }); HmsManager.setPlaybackAllowed({ id: this.id, trackId: this.trackId, @@ -26,6 +35,13 @@ export class HMSRemoteAudioTrack extends HMSAudioTrack { isPlaybackAllowed = async () => { try { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function isPlaybackAllowed', { + trackId: this.trackId, + id: this.id, + source: this.source, + type: this.type, + }); const val = await HmsManager.isPlaybackAllowed({ id: this.id, trackId: this.trackId, diff --git a/src/classes/HMSRemoteVideoTrack.ts b/src/classes/HMSRemoteVideoTrack.ts index 6d514b82e..8d8d44039 100644 --- a/src/classes/HMSRemoteVideoTrack.ts +++ b/src/classes/HMSRemoteVideoTrack.ts @@ -1,4 +1,5 @@ import { NativeModules } from 'react-native'; +import { HMSSDK } from './HMSSDK'; import { HMSVideoTrack } from './HMSVideoTrack'; import type { HMSTrackType } from './HMSTrackType'; @@ -19,6 +20,14 @@ export class HMSRemoteVideoTrack extends HMSVideoTrack { * @memberof HMSRemoteVideoTrack */ setPlaybackAllowed(playbackAllowed: boolean) { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function setPlaybackAllowed', { + trackId: this.trackId, + id: this.id, + source: this.source, + type: this.type, + playbackAllowed, + }); HmsManager.setPlaybackAllowed({ id: this.id, trackId: this.trackId, @@ -28,6 +37,13 @@ export class HMSRemoteVideoTrack extends HMSVideoTrack { isPlaybackAllowed = async () => { try { + const logger = HMSSDK.getLogger(); + logger?.verbose('#Function isPlaybackAllowed', { + trackId: this.trackId, + id: this.id, + source: this.source, + type: this.type, + }); const val = await HmsManager.isPlaybackAllowed({ id: this.id, trackId: this.trackId, diff --git a/src/classes/HMSSDK.tsx b/src/classes/HMSSDK.tsx index 301058f22..bfd4591dc 100644 --- a/src/classes/HMSSDK.tsx +++ b/src/classes/HMSSDK.tsx @@ -38,12 +38,13 @@ const HmsEventEmitter = new NativeEventEmitter(HmsManager); let HmsSdk: HMSSDK | undefined; +let logger: HMSLogger | undefined; + export class HMSSDK { room?: HMSRoom; localPeer?: HMSLocalPeer; remotePeers?: HMSRemotePeer[]; knownRoles?: HMSRole[]; - logger?: HMSLogger; id: string; private muteStatus: boolean | undefined; @@ -81,6 +82,15 @@ export class HMSSDK { return HmsSdk; } + static getLogger() { + return logger; + } + + setLogger = (hmsLogger: HMSLogger) => { + logger = hmsLogger; + hmsLogger.verbose('#Function setLogger', { id: this.id }); + }; + destroy = () => { this.removeListeners(); }; @@ -224,12 +234,12 @@ export class HMSSDK { * @memberof HMSSDK */ join = async (config: HMSConfig) => { - this.logger?.verbose('JOIN', { config }); + logger?.verbose('#Function join', { config, id: this.id }); await HmsManager.join({ ...config, id: this.id }); }; preview = (config: HMSConfig) => { - this.logger?.verbose('PREVIEW', { config }); + logger?.verbose('#Function preview', { config, id: this.id }); HmsManager.preview({ ...config, id: this.id }); }; @@ -258,31 +268,45 @@ export class HMSSDK { * @memberof HMSSDK */ leave = async () => { - this.logger?.verbose('LEAVE', {}); + logger?.verbose('#Function leave', { id: this.id }); const data = { id: this.id, }; - await HmsManager.leave(data); + const op = await HmsManager.leave(data); this.muteStatus = undefined; this.localPeer = undefined; this.remotePeers = undefined; this.room = undefined; this.knownRoles = undefined; + return op; }; - sendBroadcastMessage = (message: string, type?: string) => { - this.logger?.verbose('SEND_BROADCAST_MESSAGE', { message }); - HmsManager.sendBroadcastMessage({ + sendBroadcastMessage = async (message: string, type?: string) => { + logger?.verbose('#Function sendBroadcastMessage', { + message, + type: type || null, + id: this.id, + }); + return await HmsManager.sendBroadcastMessage({ message, type: type || null, id: this.id, }); }; - sendGroupMessage = (message: string, roles: HMSRole[], type?: string) => { - this.logger?.verbose('SEND_GROUP_MESSAGE', { message, roles }); - HmsManager.sendGroupMessage({ + sendGroupMessage = async ( + message: string, + roles: HMSRole[], + type?: string + ) => { + logger?.verbose('#Function sendGroupMessage', { + message, + roles, + id: this.id, + type: type || null, + }); + return await HmsManager.sendGroupMessage({ message, roles: HMSHelper.getRoleNames(roles), id: this.id, @@ -290,9 +314,18 @@ export class HMSSDK { }); }; - sendDirectMessage = (message: string, peerId: string, type?: string) => { - this.logger?.verbose('SEND_DIRECT_MESSAGE', { message, peerId }); - HmsManager.sendDirectMessage({ + sendDirectMessage = async ( + message: string, + peerId: string, + type?: string + ) => { + logger?.verbose('#Function sendDirectMessage', { + message, + peerId, + id: this.id, + type: type || null, + }); + return await HmsManager.sendDirectMessage({ message, peerId, id: this.id, @@ -301,56 +334,64 @@ export class HMSSDK { }; changeMetadata = (metadata: string) => { - this.logger?.verbose('CHANGE_METADATA', { metadata }); + logger?.verbose('#Function changeMetadata', { metadata, id: this.id }); HmsManager.changeMetadata({ metadata, id: this.id }); }; startRTMPOrRecording = async (data: HMSRTMPConfig) => { - this.logger?.verbose('START_RTMP_OR_RECORDING', { data }); + logger?.verbose('#Function startRTMPOrRecording', { + ...data, + id: this.id, + }); const op = await HmsManager.startRTMPOrRecording({ ...data, id: this.id }); return op; }; stopRtmpAndRecording = async () => { - this.logger?.verbose('STOP_RTMP_OR_RECORDING', {}); + logger?.verbose('#Function stopRtmpAndRecording', {}); const op = await HmsManager.stopRtmpAndRecording({ id: this.id }); return op; }; - changeRole = (peer: HMSPeer, role: HMSRole, force: boolean = false) => { + changeRole = async (peer: HMSPeer, role: HMSRole, force: boolean = false) => { const data = { peerId: peer?.peerID, role: role?.name, force: force, id: this.id, }; - this.logger?.verbose('CHANGE_ROLE', data); - HmsManager.changeRole(data); + logger?.verbose('#Function changeRole', data); + return await HmsManager.changeRole(data); }; - changeTrackState = (track: HMSTrack, mute: boolean) => { - this.logger?.verbose('CHANGE_TRACK_STATE', { track, mute }); + changeTrackState = async (track: HMSTrack, mute: boolean) => { + logger?.verbose('#Function changeTrackState', { + track, + mute, + id: this.id, + }); const data = { trackId: track.trackId, mute, id: this.id, }; - HmsManager.changeTrackState(data); + return await HmsManager.changeTrackState(data); }; - changeTrackStateRoles = ( + changeTrackStateRoles = async ( type: HMSTrackType, mute: boolean, source: string, roles: Array ) => { - this.logger?.verbose('CHANGE_TRACK_STATE_ROLES', { + logger?.verbose('#Function changeTrackStateRoles', { source, mute, type, roles, + id: this.id, }); const data = { source, @@ -360,44 +401,47 @@ export class HMSSDK { id: this.id, }; - HmsManager.changeTrackStateRoles(data); + return await HmsManager.changeTrackStateRoles(data); }; - removePeer = (peerId: string, reason: string) => { - this.logger?.verbose('REMOVE_PEER', { peerId, reason }); + removePeer = async (peerId: string, reason: string) => { + logger?.verbose('#Function removePeer', { peerId, reason, id: this.id }); const data = { peerId, reason, id: this.id, }; - HmsManager.removePeer(data); + return await HmsManager.removePeer(data); }; - endRoom = (lock: boolean, reason: string) => { - this.logger?.verbose('END_ROOM', { lock, reason }); + endRoom = async (lock: boolean, reason: string) => { + logger?.verbose('#Function endRoom', { lock, reason, id: this.id }); const data = { lock, reason, id: this.id, }; - HmsManager.endRoom(data); + return await HmsManager.endRoom(data); }; acceptRoleChange = () => { - this.logger?.verbose('ACCEPT_ROLE_CHANGE', {}); + logger?.verbose('#Function acceptRoleChange', { id: this.id }); HmsManager.acceptRoleChange({ id: this.id }); }; muteAllPeersAudio = (mute: boolean) => { - this.logger?.verbose('ON_MUTE_ALL_PEERS', { mute }); + logger?.verbose('#Function muteAllPeersAudio', { mute, id: this.id }); this.muteStatus = mute; HmsManager.muteAllPeersAudio({ mute, id: this.id }); }; getRoom = async () => { - this.logger?.verbose('GET_ROOM_API_CALL', { roomID: this.id }); + logger?.verbose('#Function getRoom', { + roomID: this.room?.id, + id: this.id, + }); const hmsRoom = await HmsManager.getRoom({ id: this.id }); const encodedHmsRoom = HMSEncoder.encodeHmsRoom(hmsRoom, this.id); @@ -405,7 +449,11 @@ export class HMSSDK { }; setVolume = (track: HMSTrack, volume: number) => { - this.logger?.verbose('SET_VOLUME_CALL', { track, volume }); + logger?.verbose('#Function setVolume', { + track, + volume, + id: this.id, + }); HmsManager.setVolume({ id: this.id, trackId: track.trackId, @@ -423,7 +471,10 @@ export class HMSSDK { * @memberof HMSSDK */ addEventListener = (action: HMSUpdateListenerActions, callback: any) => { - this.logger?.verbose('ON_ATTACH_EVENT_LISTENER', { action }); + logger?.verbose('#Function addEventListener', { + action, + id: this.id, + }); switch (action) { case HMSUpdateListenerActions.ON_PREVIEW: this.onPreviewDelegate = callback; @@ -477,7 +528,7 @@ export class HMSSDK { * @memberof HMSSDK */ removeEventListener = (action: HMSUpdateListenerActions) => { - this.logger?.verbose('ON_REMOVE_LISTENER', { action }); + logger?.verbose('#Function removeEventListener', { action, id: this.id }); switch (action) { case HMSUpdateListenerActions.ON_PREVIEW: this.onPreviewDelegate = null; @@ -542,19 +593,14 @@ export class HMSSDK { this.onChangeTrackStateRequestDelegate = null; this.onRemovedFromRoomDelegate = null; - this.logger?.verbose('REMOVE_ALL_LISTENER', {}); - }; - - setLogger = (hmsLogger: HMSLogger) => { - this.logger = hmsLogger; - hmsLogger.verbose('UPDATE_LOGGER', { hmsLogger }); + logger?.verbose('#Function REMOVE_ALL_LISTENER', { id: this.id }); }; onPreviewListener = (data: any) => { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_PREVIEW', data); + logger?.verbose('#Listener ON_PREVIEW', data); const room: HMSRoom = HMSEncoder.encodeHmsRoom(data.room, this.id); const localPeer: HMSLocalPeer = HMSEncoder.encodeHmsLocalPeer( data.localPeer, @@ -566,7 +612,7 @@ export class HMSSDK { this.localPeer = localPeer; this.room = room; if (this.onPreviewDelegate) { - this.logger?.verbose('ON_PREVIEW_LISTENER_CALL', { + logger?.verbose('#Listener ON_PREVIEW_LISTENER_CALL', { ...data, room, localPeer, @@ -580,7 +626,7 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_JOIN', data); + logger?.verbose('#LISTENER ON_JOIN', data); // Preprocessing const room: HMSRoom = HMSEncoder.encodeHmsRoom(data.room, this.id); const localPeer: HMSLocalPeer = HMSEncoder.encodeHmsLocalPeer( @@ -597,7 +643,7 @@ export class HMSSDK { this.remotePeers = remotePeers; this.knownRoles = roles; if (this.onJoinDelegate) { - this.logger?.verbose('ON_JOIN_LISTENER_CALL', { + logger?.verbose('#Listener ON_JOIN_LISTENER_CALL', { ...data, room, localPeer, @@ -611,7 +657,7 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_ROOM', data); + logger?.verbose('#Listener ON_ROOM', data); const room: HMSRoom = HMSEncoder.encodeHmsRoom(data.room, this.id); const localPeer: HMSLocalPeer = HMSEncoder.encodeHmsLocalPeer( data.localPeer, @@ -625,7 +671,7 @@ export class HMSSDK { this.localPeer = localPeer; this.remotePeers = remotePeers; if (this.onRoomDelegate) { - this.logger?.verbose('ON_ROOM_LISTENER_CALL', { + logger?.verbose('#Listener ON_ROOM_LISTENER_CALL', { ...data, room, localPeer, @@ -639,7 +685,8 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_PEER', data); + logger?.verbose('#Listener ON_PEER', data); + const peer: HMSPeer = HMSEncoder.encodeHmsPeer(data.peer, this.id); const room: HMSRoom = HMSEncoder.encodeHmsRoom(data.room, this.id); const localPeer: HMSLocalPeer = HMSEncoder.encodeHmsLocalPeer( data.localPeer, @@ -654,8 +701,8 @@ export class HMSSDK { this.remotePeers = remotePeers; this.room = room; if (this.onPeerDelegate) { - this.logger?.verbose('ON_PEER_LISTENER_CALL', data); - this.onPeerDelegate({ ...data, localPeer, remotePeers, room }); + logger?.verbose('#Listener ON_PEER_LISTENER_CALL', data); + this.onPeerDelegate({ ...data, localPeer, remotePeers, room, peer }); } }; @@ -663,7 +710,9 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_TRACK', data); + logger?.verbose('#Listener ON_TRACK', data); + const track: HMSTrack = HMSEncoder.encodeHmsTrack(data.track, this.id); + const peer: HMSPeer = HMSEncoder.encodeHmsPeer(data.peer, this.id); const room: HMSRoom = HMSEncoder.encodeHmsRoom(data.room, this.id); const localPeer: HMSLocalPeer = HMSEncoder.encodeHmsLocalPeer( data.localPeer, @@ -680,8 +729,15 @@ export class HMSSDK { this.localPeer = localPeer; this.remotePeers = remotePeers; if (this.onTrackDelegate) { - this.logger?.verbose('ON_TRACK_LISTENER_CALL', data); - this.onTrackDelegate({ ...data, localPeer, remotePeers, room }); + logger?.verbose('#Listener ON_TRACK_LISTENER_CALL', data); + this.onTrackDelegate({ + ...data, + localPeer, + remotePeers, + room, + peer, + track, + }); } }; @@ -689,10 +745,10 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_MESSAGE', data); + logger?.verbose('#Listener ON_MESSAGE', data); const message = new HMSMessage(data); if (this.onMessageDelegate) { - this.logger?.verbose('ON_MESSAGE_LISTENER_CALL', message); + logger?.verbose('#Listener ON_MESSAGE_LISTENER_CALL', message); this.onMessageDelegate(message); } }; @@ -701,8 +757,9 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_SPEAKER', data); + logger?.verbose('#Listener ON_SPEAKER', data); if (this.onSpeakerDelegate) { + logger?.verbose('#Listener ON_SPEAKER_LISTENER_CALL', data); this.onSpeakerDelegate(data); } }; @@ -711,11 +768,11 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.warn('ON_ERROR', data); - this.logger?.verbose('ON_ERROR', data); + logger?.warn('#Listener ON_ERROR', data); + logger?.verbose('#Listener ON_ERROR', data); if (this.onErrorDelegate) { - this.logger?.verbose('ON_ERROR_LISTENER_CALL', data); - this.logger?.warn('ON_ERROR_LISTENER_CALL', data); + logger?.verbose('#Listener ON_ERROR_LISTENER_CALL', data); + logger?.warn('#Listener ON_ERROR_LISTENER_CALL', data); this.onErrorDelegate(data); } }; @@ -724,14 +781,14 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_ROLE_CHANGE_REQUEST', data); + logger?.verbose('#Listener ON_ROLE_CHANGE_REQUEST', data); if (this.onRoleChangeRequestDelegate) { const encodedRoleChangeRequest = HMSEncoder.encodeHmsRoleChangeRequest( data, this.id ); - this.logger?.verbose( - 'ON_ROLE_CHANGE_LISTENER_CALL', + logger?.verbose( + '#Listener ON_ROLE_CHANGE_LISTENER_CALL', encodedRoleChangeRequest ); this.onRoleChangeRequestDelegate(encodedRoleChangeRequest); @@ -739,12 +796,15 @@ export class HMSSDK { }; onChangeTrackStateRequestListener = (data: any) => { - this.logger?.verbose('ON_CHANGE_TRACK_STATE_REQUEST', data); + if (data.id !== this.id) { + return; + } + logger?.verbose('#Listener ON_CHANGE_TRACK_STATE_REQUEST', data); if (this.onChangeTrackStateRequestDelegate) { const encodedRoleChangeRequest = HMSEncoder.encodeHmsChangeTrackStateRequest(data, this.id); - this.logger?.verbose( - 'ON_CHANGE_TRACK_STATE_REQUEST_LISTENER_CALL', + logger?.verbose( + '#Listener ON_CHANGE_TRACK_STATE_REQUEST_LISTENER_CALL', encodedRoleChangeRequest ); this.onChangeTrackStateRequestDelegate(encodedRoleChangeRequest); @@ -755,7 +815,7 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_REMOVED_FROM_ROOM', data); + logger?.verbose('#Listener ON_REMOVED_FROM_ROOM', data); if (this.onRemovedFromRoomDelegate) { let requestedBy = null; if (data.requestedBy) { @@ -764,10 +824,11 @@ export class HMSSDK { const reason = data.reason; const roomEnded = data.roomEnded; - this.logger?.verbose('ON_REMOVED_FROM_ROOM_LISTENER_CALL', { + logger?.verbose('#Listener ON_REMOVED_FROM_ROOM_LISTENER_CALL', { requestedBy, reason, roomEnded, + id: this.id, }); this.onRemovedFromRoomDelegate({ requestedBy, reason, roomEnded }); } @@ -777,7 +838,7 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_RECONNECTING', data); + logger?.verbose('#Listener ON_RECONNECTING', data); if (this.onReconnectingDelegate) { this.onReconnectingDelegate(data); } @@ -787,7 +848,7 @@ export class HMSSDK { if (data.id !== this.id) { return; } - this.logger?.verbose('ON_RECONNECTED', data); + logger?.verbose('#Listener ON_RECONNECTED', data); if (this.onReconnectedDelegate) { this.onReconnectedDelegate(data); } diff --git a/src/classes/HMSTrackSettings.ts b/src/classes/HMSTrackSettings.ts index ebefc5ea3..004240775 100644 --- a/src/classes/HMSTrackSettings.ts +++ b/src/classes/HMSTrackSettings.ts @@ -4,14 +4,17 @@ import type { HMSVideoTrackSettings } from './HMSVideoTrackSettings'; export class HMSTrackSettings { video?: HMSVideoTrackSettings; audio?: HMSAudioTrackSettings; + useHardwareEchoCancellation?: boolean; constructor(params?: { video?: HMSVideoTrackSettings; audio?: HMSAudioTrackSettings; + useHardwareEchoCancellation?: boolean; }) { if (params) { this.video = params.video; this.audio = params.audio; + this.useHardwareEchoCancellation = params.useHardwareEchoCancellation; } } } diff --git a/src/classes/HMSVideoCodec.ts b/src/classes/HMSVideoCodec.ts index a32600b9c..97c384ae6 100644 --- a/src/classes/HMSVideoCodec.ts +++ b/src/classes/HMSVideoCodec.ts @@ -1,6 +1,6 @@ export enum HMSVideoCodec { - h264 = 'h264', - vp8 = 'vp8', - vp9 = 'vp9', - h265 = 'h265', + H264 = 'H264', + VP8 = 'VP8', + VP9 = 'VP9', + H265 = 'H265', } diff --git a/src/index.ts b/src/index.ts index 575c3d208..0ad4c4474 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,6 +46,7 @@ export * from './classes/HMSRtmpStreamingState'; export * from './classes/HMSServerRecordingState'; export * from './classes/HMSBrowserRecordingState'; export * from './classes/HMSRTMPConfig'; +export * from './classes/HMSVideoResolution'; import { HMSSDK as HmsManager } from './classes/HMSSDK'; export default HmsManager;