ThibaultBee / StreamPack

SRT/RTMP/RTMPS live streaming libraries for Android
https://thibaultbee.github.io/StreamPack/index.html
Apache License 2.0
174 stars 67 forks source link

[Bug]: "demo-camera" app crashes at startup #99

Open benunderwood opened 4 months ago

benunderwood commented 4 months ago

Version

2.6.0

Environment that reproduces the issue

Custom device running Android 9 (api 28).

RTMP/SRT/... Server

N/A

Audio configuration

N/A

Video configuration

N/A

Is it reproducible in the demos application?

Yes

Reproduction steps

Running the "demo-camera" app results in an immediate crash.

Expected result

App doesn't crash.

Actual result

The app crashes with "java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "CRYPTO_ctr128_encrypt".

Additional context

This only happens on the custom device mentioned.

Relevant logs output

This is the full log output from launching the app to crashing:

---------------------------- PROCESS STARTED (28421) for package io.github.thibaultbee.streampack.sample ----------------------------
12:49:13.028  D  Checking for metadata for AppLocalesMetadataHolderService : Service not found
12:49:13.106  W  Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
12:49:13.107  W  Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
12:49:13.107  W  Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
12:49:13.107  W  Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
12:49:13.560  D  Skia GL Pipeline
12:49:13.561  I  [static] sSurfaceFactory = com.mediatek.view.impl.SurfaceFactoryImpl@b20831b
12:49:13.571  I  Connecting to camera service
12:49:13.957  W  Setting the fragment as the LifecycleOwner might cause memory leaks because views lives shorter than the Fragment. Consider using Fragment's view lifecycle
12:49:14.157  E  createStreamer failed
                 java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "CRYPTO_ctr128_encrypt" referenced by "/data/app/io.github.thibaultbee.streampack.sample-9iUe-XHgKnOiNUTo2rC7dA==/base.apk!/lib/armeabi-v7a/libsrt.so"...
                    at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
                    at java.lang.System.loadLibrary(System.java:1669)
                    at io.github.thibaultbee.srtdroid.Srt.<clinit>(Srt.kt:23)
                    at io.github.thibaultbee.srtdroid.models.Socket.<clinit>(Socket.kt:41)
                    at io.github.thibaultbee.streampack.ext.srt.internal.endpoints.SrtProducer.<init>(SrtProducer.kt:43)
                    at io.github.thibaultbee.streampack.ext.srt.internal.endpoints.SrtProducer.<init>(SrtProducer.kt:38)
                    at io.github.thibaultbee.streampack.ext.srt.streamers.CameraSrtLiveStreamer.<init>(CameraSrtLiveStreamer.kt:58)
                    at io.github.thibaultbee.streampack.ext.srt.streamers.CameraSrtLiveStreamer.<init>(CameraSrtLiveStreamer.kt:46)
                    at io.github.thibaultbee.streampack.app.utils.StreamerFactory.createStreamer(StreamerFactory.kt:90)
                    at io.github.thibaultbee.streampack.app.utils.StreamerFactory.build(StreamerFactory.kt:131)
                    at io.github.thibaultbee.streampack.app.utils.StreamerManager.rebuildStreamer(StreamerManager.kt:89)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewViewModel$createStreamer$1.invokeSuspend(PreviewViewModel.kt:86)
                    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                    at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367)
                    at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
                    at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
                    at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
                    at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
                    at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
                    at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
                    at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
                    at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewViewModel.createStreamer(PreviewViewModel.kt:84)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.createStreamer(PreviewFragment.kt:178)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.requestCameraAndMicrophonePermissions(PreviewFragment.kt:147)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.onStart(PreviewFragment.kt:137)
                    at androidx.fragment.app.Fragment.performStart(Fragment.java:3021)
                    at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:589)
                    at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:300)
                    at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
                    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
                    at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
                    at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:3079)
                    at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:262)
                    at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:510)
                    at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:251)
                    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
                    at android.app.Activity.performStart(Activity.java:7195)
                    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2968)
                    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
                    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
                    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
12:49:14.158  E     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836)
                    at android.os.Handler.dispatchMessage(Handler.java:106)
                    at android.os.Looper.loop(Looper.java:193)
                    at android.app.ActivityThread.main(ActivityThread.java:6702)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:931)
12:49:14.161  D  Shutting down VM
12:49:14.164  E  FATAL EXCEPTION: main
                 Process: io.github.thibaultbee.streampack.sample, PID: 28421
                 java.lang.NullPointerException
                    at io.github.thibaultbee.streampack.app.utils.StreamerManager$streamerLifeCycleObserver$2.invoke(StreamerManager.kt:66)
                    at io.github.thibaultbee.streampack.app.utils.StreamerManager$streamerLifeCycleObserver$2.invoke(StreamerManager.kt:65)
                    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
                    at io.github.thibaultbee.streampack.app.utils.StreamerManager.getStreamerLifeCycleObserver(StreamerManager.kt:65)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewViewModel.getStreamerLifeCycleObserver(PreviewViewModel.kt:42)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.createStreamer(PreviewFragment.kt:195)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.requestCameraAndMicrophonePermissions(PreviewFragment.kt:147)
                    at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.onStart(PreviewFragment.kt:137)
                    at androidx.fragment.app.Fragment.performStart(Fragment.java:3021)
                    at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:589)
                    at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:300)
                    at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
                    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
                    at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
                    at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:3079)
                    at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:262)
                    at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:510)
                    at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:251)
                    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
                    at android.app.Activity.performStart(Activity.java:7195)
                    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2968)
                    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
                    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
                    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
                    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836)
                    at android.os.Handler.dispatchMessage(Handler.java:106)
                    at android.os.Looper.loop(Looper.java:193)
                    at android.app.ActivityThread.main(ActivityThread.java:6702)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:931)
12:49:14.181  I  Sending signal. PID: 28421 SIG: 9
---------------------------- PROCESS ENDED (28421) for package io.github.thibaultbee.streampack.sample ----------------------------
ThibaultBee commented 4 months ago

hmm. That's going to be tricky. Could you remove RTMP protocol dependency there: https://github.com/ThibaultBee/StreamPack/blob/908f7f0e92f7a0d9777dfd0698ff045e337265d1/demos/camera/build.gradle#L54? You will have to remove RTMP classes as well. It is just for a test. Do you need both RTMP and SRT? RTMP and SRT are both shipped with a version of libssl/libcrypto and I suspect that gradle picked one that is missing API.

benunderwood commented 4 months ago

Thanks for the reply.

I'm just doing some exploration at the moment so I'm not sure if I'll be using RTMP or SRT, I think either is suitable.

I've tried removing the RTMP dependency, and I find it still has the same error.

If I put back the RTMP dependency and remove the SRT dependency I get another error, which looks similar, but is from librtmp this time:

16:14:12.787 E createStreamer failed java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "DH_get0_pub_key" referenced by "/data/app/io.github.thibaultbee.streampack.sample-qXWgmifSgqUjLEmSW0FTSQ==/base.apk!/lib/armeabi-v7a/librtmp.so"... at java.lang.Runtime.loadLibrary0(Runtime.java:1016) at java.lang.System.loadLibrary(System.java:1669) at video.api.rtmpdroid.RtmpNativeLoader.(RtmpNativeLoader.kt:9) at video.api.rtmpdroid.Rtmp.(Rtmp.kt:19) at io.github.thibaultbee.streampack.ext.rtmp.internal.endpoints.RtmpProducer.(RtmpProducer.kt:33) at io.github.thibaultbee.streampack.ext.rtmp.internal.endpoints.RtmpProducer.(RtmpProducer.kt:28) at io.github.thibaultbee.streampack.ext.rtmp.streamers.CameraRtmpLiveStreamer.(CameraRtmpLiveStreamer.kt:43) at io.github.thibaultbee.streampack.ext.rtmp.streamers.CameraRtmpLiveStreamer.(CameraRtmpLiveStreamer.kt:34) at io.github.thibaultbee.streampack.app.utils.StreamerFactory.createStreamer(StreamerFactory.kt:99) at io.github.thibaultbee.streampack.app.utils.StreamerFactory.build(StreamerFactory.kt:132) at io.github.thibaultbee.streampack.app.utils.StreamerManager.rebuildStreamer(StreamerManager.kt:89) at io.github.thibaultbee.streampack.app.ui.main.PreviewViewModel$createStreamer$1.invokeSuspend(PreviewViewModel.kt:86) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25) at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110) at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56) at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47) at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1) at io.github.thibaultbee.streampack.app.ui.main.PreviewViewModel.createStreamer(PreviewViewModel.kt:84) at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.createStreamer(PreviewFragment.kt:178) at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.requestCameraAndMicrophonePermissions(PreviewFragment.kt:147) at io.github.thibaultbee.streampack.app.ui.main.PreviewFragment.onStart(PreviewFragment.kt:137) at androidx.fragment.app.Fragment.performStart(Fragment.java:3021) at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:589) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:300) at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647) at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128) at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:3079) at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:262) at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:510) at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:251) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391) at android.app.Activity.performStart(Activity.java:7195) at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2968) at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180) at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142) 16:14:12.787 E at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6702) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:931)

ThibaultBee commented 4 months ago

I don't have a clue why this is happening 🤔 Might be because you are using a custom phone and something is missing in the implementation.

I made a test where I enforce loadLibrary of ssl and crypto: https://github.com/ThibaultBee/StreamPack/tree/test/openssl Could you test it? Hopefully it will be called before loading rtmpdroid and srtdroid.

ThibaultBee commented 4 months ago

For RTMP, you could try something like that the dependencies:

  implementation("video.api:rtmpdroid:1.2.1-packed")
  implementation project(':extension-rtmp') {
    exclude group: 'video.api', module: 'rtmpdroid'
    // exclude the transitive dependency to use packed version to avoid conflict with libssl.so and libcrypto.so
  }
ThibaultBee commented 4 months ago

Also found this relevant info: https://developer.android.com/training/articles/perf-jni.html#native-libraries

benunderwood commented 4 months ago

I've tried the test/openssl branch you created, and that fixes the problem for me, thank you!

I suspect you are correct that it is something missing on the device, and it's not a general issue. It's currently beyond my understanding, but if I work out what is happening I'll let you know.

ThibaultBee commented 4 months ago

Ok, I will add this is in native dependencies (srtdroid and rtmpdroid):

    System.loadLibrary("crypto")
    System.loadLibrary("ssl")

Already in rtmpdroid: https://github.com/apivideo/api.video-rtmpdroid/commit/d7eb771f960ab4131409b0cd1bcdb93741ef6f85

But it will take a while.