Skip to content

Commit

Permalink
Merge pull request #621 from 100mslive/develop
Browse files Browse the repository at this point in the history
Release 0.9.5: Develop to main
  • Loading branch information
ygit authored May 11, 2022
2 parents 30e6876 + 36bba43 commit 4d8adb7
Show file tree
Hide file tree
Showing 42 changed files with 2,250 additions and 1,456 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,9 @@ const styles = StyleSheet.create({
});

// trackId can be acquired from the method explained above
// sink is passed false video would be removed. It is a ios only prop, for android it is handled by the package itself.
// scaleType can be selected from HMSVideoViewMode as required
// mirror can be passed as true to flip videos horizontally
<HmsView sink={true} style={styles.hmsView} trackId={trackId} mirror={true} scaleType={HMSVideoViewMode.ASPECT_FIT} />
<HmsView style={styles.hmsView} trackId={trackId} mirror={true} scaleType={HMSVideoViewMode.ASPECT_FIT} />

...
```
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ 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:lib:2.3.5'
implementation 'com.github.100mslive.android-sdk:lib:2.3.7'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
Expand Down
153 changes: 80 additions & 73 deletions android/src/main/java/com/reactnativehmssdk/HmsHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package com.reactnativehmssdk

import android.content.Context
import android.graphics.Bitmap
import android.media.MediaScannerConnection
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.util.Base64
import android.util.Log
import android.view.PixelCopy
import androidx.annotation.RequiresApi
import com.facebook.react.bridge.*
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.uimanager.events.RCTEventEmitter
import java.io.ByteArrayOutputStream
import java.util.*
import live.hms.video.error.HMSException
import live.hms.video.media.codec.HMSAudioCodec
import live.hms.video.media.codec.HMSVideoCodec
Expand All @@ -25,9 +28,6 @@ import live.hms.video.sdk.models.*
import live.hms.video.sdk.models.role.HMSRole
import live.hms.video.utils.HmsUtilities
import org.webrtc.SurfaceViewRenderer
import java.io.File
import java.io.FileOutputStream
import java.util.*

object HmsHelper {

Expand Down Expand Up @@ -136,7 +136,9 @@ object HmsHelper {
var useHardwareEchoCancellation = false
val requiredKeysUseHardwareEchoCancellation =
this.areAllRequiredKeysAvailable(
data, arrayOf(Pair("useHardwareEchoCancellation", "Boolean")))
data,
arrayOf(Pair("useHardwareEchoCancellation", "Boolean"))
)
if (requiredKeysUseHardwareEchoCancellation) {
useHardwareEchoCancellation = data.getBoolean("useHardwareEchoCancellation")
}
Expand Down Expand Up @@ -291,11 +293,17 @@ object HmsHelper {
var singleFilePerLayer = false
var videoOnDemand = false
if (areAllRequiredKeysAvailable(
hmsHlsRecordingConfig, arrayOf(Pair("singleFilePerLayer", "Boolean")))) {
hmsHlsRecordingConfig,
arrayOf(Pair("singleFilePerLayer", "Boolean"))
)
) {
singleFilePerLayer = hmsHlsRecordingConfig.getBoolean("singleFilePerLayer")
}
if (areAllRequiredKeysAvailable(
hmsHlsRecordingConfig, arrayOf(Pair("videoOnDemand", "Boolean")))) {
hmsHlsRecordingConfig,
arrayOf(Pair("videoOnDemand", "Boolean"))
)
) {
videoOnDemand = hmsHlsRecordingConfig.getBoolean("videoOnDemand")
}
return HMSHlsRecordingConfig(singleFilePerLayer, videoOnDemand)
Expand Down Expand Up @@ -329,7 +337,9 @@ object HmsHelper {
arrayOf(
Pair("endpoint", "String"),
Pair("metadata", "String"),
Pair("captureNetworkQualityInPreview", "Boolean"))) -> {
Pair("captureNetworkQualityInPreview", "Boolean")
)
) -> {
config =
HMSConfig(
credentials.getString("username") as String,
Expand All @@ -341,7 +351,9 @@ object HmsHelper {
)
}
areAllRequiredKeysAvailable(
credentials, arrayOf(Pair("endpoint", "String"), Pair("metadata", "String"))) -> {
credentials,
arrayOf(Pair("endpoint", "String"), Pair("metadata", "String"))
) -> {
config =
HMSConfig(
credentials.getString("username") as String,
Expand All @@ -352,8 +364,8 @@ object HmsHelper {
}
areAllRequiredKeysAvailable(
credentials,
arrayOf(
Pair("endpoint", "String"), Pair("captureNetworkQualityInPreview", "Boolean"))) -> {
arrayOf(Pair("endpoint", "String"), Pair("captureNetworkQualityInPreview", "Boolean"))
) -> {
config =
HMSConfig(
credentials.getString("username") as String,
Expand All @@ -365,8 +377,8 @@ object HmsHelper {
}
areAllRequiredKeysAvailable(
credentials,
arrayOf(
Pair("metadata", "String"), Pair("captureNetworkQualityInPreview", "Boolean"))) -> {
arrayOf(Pair("metadata", "String"), Pair("captureNetworkQualityInPreview", "Boolean"))
) -> {
config =
HMSConfig(
credentials.getString("username") as String,
Expand All @@ -393,83 +405,78 @@ object HmsHelper {
)
}
areAllRequiredKeysAvailable(
credentials, arrayOf(Pair("captureNetworkQualityInPreview", "Boolean"))) -> {
credentials,
arrayOf(Pair("captureNetworkQualityInPreview", "Boolean"))
) -> {
config =
HMSConfig(
credentials.getString("username") as String,
credentials.getString("authToken") as String,
captureNetworkQualityInPreview =
credentials.getBoolean("captureNetworkQualityInPreview"))
credentials.getBoolean("captureNetworkQualityInPreview")
)
}
}
return config
}

@RequiresApi(Build.VERSION_CODES.N)
fun captureSurfaceView(surfaceView: SurfaceViewRenderer, context: Context, id: String?) {
fun captureSurfaceView(
surfaceView: SurfaceViewRenderer,
sdkId: String,
args: ReadableArray?,
context: Context,
id: Int
) {
val output = Arguments.createMap()
if (args != null) {
output.putInt("requestId", args.getInt(0))
} else {
output.putInt("requestId", -1)
}
val reactContext = context as ReactContext
try {
val bitmap: Bitmap =
Bitmap.createBitmap(surfaceView.width, surfaceView.height, Bitmap.Config.ARGB_8888)
Bitmap.createBitmap(surfaceView.width, surfaceView.height, Bitmap.Config.ARGB_8888)
PixelCopy.request(
surfaceView,
bitmap,
{ copyResult ->
if (copyResult === PixelCopy.SUCCESS) {
Log.d("captureSurfaceView", "bitmap: $bitmap")
saveImage(bitmap, context, id)
} else {
HmsModule.hmsCollection[id]?.emitHMSError(
HMSException(
103,
copyResult.toString(),
copyResult.toString(),
copyResult.toString(),
copyResult.toString()
surfaceView,
bitmap,
{ copyResult ->
if (copyResult === PixelCopy.SUCCESS) {
Log.d("captureSurfaceView", "bitmap: $bitmap")
val byteArrayOutputStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
val byteArray = byteArrayOutputStream.toByteArray()
val encoded: String = Base64.encodeToString(byteArray, Base64.DEFAULT)
Log.d("captureSurfaceView", "Base64: $encoded")
output.putString("result", encoded)
reactContext
.getJSModule(RCTEventEmitter::class.java)
.receiveEvent(id, "captureFrame", output)
} else {
Log.e("captureSurfaceView", "copyResult: $copyResult")
HmsModule.hmsCollection[sdkId]?.emitHMSError(
HMSException(
103,
copyResult.toString(),
copyResult.toString(),
copyResult.toString(),
copyResult.toString()
)
)
)
Log.e("captureSurfaceView", "copyResult: $copyResult")
}
},
Handler()
output.putString("error", copyResult.toString())
reactContext
.getJSModule(RCTEventEmitter::class.java)
.receiveEvent(id, "captureFrame", output)
}
},
Handler()
)
} catch (e: Exception) {
Log.e("captureSurfaceView", "error: $e")
}
}

private fun saveImage(finalBitmap: Bitmap, context: Context, id: String?) {
val folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
if (!folder.exists()) {
folder.mkdir()
}
val generator = Random()
var n = 10000
n = generator.nextInt(n)
val fileName = "Image-$n.jpg"
val file = File(folder.absolutePath, fileName)
if (file.exists()) file.delete()
try {
val out = FileOutputStream(file)
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)
out.flush()
out.close()
} catch (e: Exception) {
HmsModule.hmsCollection[id]?.emitHMSError(
HMSException(
103,
e.message.toString(),
e.message.toString(),
e.message.toString(),
e.message.toString()
)
)
Log.e("saveImage", "error: $e")
}
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(context, arrayOf(file.toString()), null) { path, uri ->
Log.i("ExternalStorage", "Scanned $path:")
Log.i("ExternalStorage", "-> uri=$uri")
HmsModule.hmsCollection[sdkId]?.emitHMSError(e as HMSException)
output.putString("error", e.message)
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "captureFrame", output)
}
}
}
2 changes: 1 addition & 1 deletion android/src/main/java/com/reactnativehmssdk/HmsSDK.kt
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ class HmsSDK(
data.putMap("sender", HmsDecoder.getHmsPeer(message.sender))
data.putString("message", message.message)
data.putString("type", message.type)
data.putString("time", message.serverReceiveTime.toString())
data.putString("time", message.serverReceiveTime.time.toString())
data.putString("id", id)
data.putMap("recipient", HmsDecoder.getHmsMessageRecipient(message.recipient))

Expand Down
18 changes: 9 additions & 9 deletions android/src/main/java/com/reactnativehmssdk/HmsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.RCTEventEmitter
import live.hms.video.media.tracks.HMSVideoTrack
Expand All @@ -23,20 +24,19 @@ class HmsView(context: ReactContext) : FrameLayout(context) {
private var scaleTypeApplied: Boolean = false
private var sdkId: String = "12345"
private var currentScaleType: RendererCommon.ScalingType =
RendererCommon.ScalingType.SCALE_ASPECT_FILL
RendererCommon.ScalingType.SCALE_ASPECT_FILL

init {
val inflater =
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val inflater = getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val view = inflater.inflate(R.layout.hms_view, this)

surfaceView = view.findViewById(R.id.surfaceView)
surfaceView.setEnableHardwareScaler(true)
}

@RequiresApi(Build.VERSION_CODES.N)
fun captureHmsView() {
HmsHelper.captureSurfaceView(surfaceView, context, sdkId)
fun captureHmsView(args: ReadableArray?) {
HmsHelper.captureSurfaceView(surfaceView, sdkId, args, context, id)
}

private fun onReceiveNativeEvent() {
Expand Down Expand Up @@ -97,10 +97,10 @@ class HmsView(context: ReactContext) : FrameLayout(context) {
}

fun setData(
id: String?,
trackId: String?,
hmsCollection: MutableMap<String, HmsSDK>,
mirror: Boolean?
id: String?,
trackId: String?,
hmsCollection: MutableMap<String, HmsSDK>,
mirror: Boolean?
) {
if (id != null) {
sdkId = id
Expand Down
37 changes: 29 additions & 8 deletions android/src/main/java/com/reactnativehmssdk/HmssdkViewManager.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.reactnativehmssdk

import android.os.Build
import androidx.annotation.NonNull
import androidx.annotation.Nullable
import androidx.annotation.RequiresApi
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.SimpleViewManager
Expand Down Expand Up @@ -30,6 +33,32 @@ class HmssdkViewManager : SimpleViewManager<HmsView>() {
.build()
}

override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any>? {
return MapBuilder.of(
"captureFrame",
MapBuilder.of("registrationName", "onDataReturned"),
)
}

@RequiresApi(Build.VERSION_CODES.N)
override fun receiveCommand(@NonNull root: HmsView, commandId: String?, args: ReadableArray?) {
when (commandId) {
"capture" -> root.captureHmsView(args)
}
}

@RequiresApi(Build.VERSION_CODES.N)
override fun receiveCommand(@NonNull root: HmsView, commandId: Int, args: ReadableArray?) {
when (commandId) {
1 -> root.captureHmsView(args)
}
}

@Nullable
override fun getCommandsMap(): Map<String, Int>? {
return MapBuilder.of("capture", 1)
}

@ReactProp(name = "data")
fun setData(view: HmsView, data: ReadableMap) {
val trackId = data.getString("trackId")
Expand All @@ -50,14 +79,6 @@ class HmssdkViewManager : SimpleViewManager<HmsView>() {
fun setZOrderMediaOverlay(view: HmsView, data: Boolean?) {
view.updateZOrderMediaOverlay(data)
}

@RequiresApi(Build.VERSION_CODES.N)
@ReactProp(name = "screenshot")
fun setCaptureHmsView(view: HmsView, screenshot: Boolean?) {
if(screenshot == true){
view.captureHmsView()
}
}

private fun getHms(): MutableMap<String, HmsSDK>? {
return reactContext?.getNativeModule(HmsModule::class.java)?.getHmsInstance()
Expand Down
Loading

0 comments on commit 4d8adb7

Please sign in to comment.