pedroSG94 / RootEncoder

RootEncoder for Android (rtmp-rtsp-stream-client-java) is a stream encoder to push video/audio to media servers using protocols RTMP, RTSP, SRT and UDP with all code written in Java/Kotlin
Apache License 2.0
2.54k stars 772 forks source link

Crash and flashback problem occurs when using the reConnect method api #1209

Closed sheng930920 closed 7 months ago

sheng930920 commented 1 year ago

When the rtmp connection fails, use the reConnect method in the api method of onConnectionFailedRtmp to crash

Below is the code to use

class RtmpPublisher private constructor() : ConnectCheckerRtmp, VideoFeeder.VideoDataListener {

    private var mStreamUrl: String? = null
    private var mPPS: ByteArray? = null
    private var mSPS: ByteArray? = null
    private var mVideoFeed: VideoFeeder.VideoFeed? = null
    private var isStartStream = false

    private val mVideoInfo = MediaCodec.BufferInfo()
    private val mRtmpClient by lazy {
        RtmpClient(this).apply {
            setOnlyVideo(true)
            setReTries(Integer.MAX_VALUE)
            setFps(30)
            resizeCache(10 * 1024)
            setProfileIop(ProfileIop.BASELINE)
            setLogs(true)
        }
    }

    fun startRtmp(streamUrl: String) {
        if (isStartStream) {
            return
        }
        isStartStream = true
        mStreamUrl = streamUrl
        val product = NestApplication.productInstance
        if (product != null && product.isConnected) {
            VideoFeeder.getInstance().transcodingDataRate = 2.0f
            mVideoFeed = VideoFeeder.getInstance().provideTranscodedVideoFeed()
            mVideoFeed?.setPriority(VideoFeedPriority.HIGH) {
            }
            mVideoFeed?.addVideoDataListener(this@RtmpPublisher)
        }
    }

    fun stopRtmp() {
        isStartStream = false
        mStreamUrl = null
        mVideoFeed?.removeVideoDataListener(this@RtmpPublisher)
        if (mRtmpClient.isStreaming) {
            mRtmpClient.disconnect()
        }
    }

    override fun onReceive(videoBuffer: ByteArray?, size: Int) {
        mVideoInfo.size = size
        mVideoInfo.offset = 0
        mVideoInfo.presentationTimeUs = System.nanoTime() / 1000
        mVideoInfo.flags = MediaCodec.BUFFER_FLAG_PARTIAL_FRAME
        if (videoBuffer != null) {
            if (H264Utils.isSPS(videoBuffer) || H264Utils.isPPS(videoBuffer)) {
                val sps = H264Utils.getFrame(videoBuffer, 7)
                val pps = H264Utils.getFrame(videoBuffer, 8)
                if (!mSPS.contentEquals(sps) || !mPPS.contentEquals(pps)) {
                    mSPS = sps
                    mPPS = pps
                    if (!mRtmpClient.isStreaming) {
                        mRtmpClient.setVideoInfo(
                            ByteBuffer.wrap(mSPS!!),
                            ByteBuffer.wrap(mPPS!!),
                            null
                        )
                        mRtmpClient.connect(mStreamUrl, true)
                    }
                }
            }
            if (mRtmpClient.isStreaming) {
                val h264Buffer = ByteBuffer.wrap(videoBuffer)
                mRtmpClient.sendVideo(h264Buffer, mVideoInfo)
            }
        }
    }

    override fun onAuthErrorRtmp() {
    }

    override fun onAuthSuccessRtmp() {
    }

    override fun onConnectionFailedRtmp(reason: String) {
        mRtmpClient.reConnect(200L)
    }

    override fun onConnectionStartedRtmp(rtmpUrl: String) {
    }

    override fun onConnectionSuccessRtmp() {
    }

    override fun onDisconnectRtmp() {
    }

    override fun onNewBitrateRtmp(bitrate: Long) {
    }

    companion object {

        @Volatile
        private var instance: RtmpPublisher? = null

        fun getInstance(): RtmpPublisher {
            if (instance == null) {
                synchronized(RtmpPublisher::class.java) {
                    if (instance == null) {
                        instance = RtmpPublisher()
                    }
                }
            }
            return instance!!
        }
    }

}

Below is the crash log


=====   Device Info =====
manufacture:DJI
product:rm500
model:rm500
version:V00.00.11.88 release-keys
android version:7.1.2
build num:
build name:
sdk version:25
=====   App Info    =====
versionCode:1
versionName:1.4.0
=====   Crash   =====
java.lang.Error: java.net.SocketException: Socket is closed
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1139)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)
Caused by: java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:898)
    at com.pedro.rtmp.utils.socket.TcpSocket.close(TcpSocket.kt:63)
    at com.pedro.rtmp.rtmp.RtmpClient.closeConnection(RtmpClient.kt:434)
    at com.pedro.rtmp.rtmp.RtmpClient.disconnect(RtmpClient.kt:477)
    at com.pedro.rtmp.rtmp.RtmpClient.reConnect(RtmpClient.kt:441)
    at com.pedro.rtmp.rtmp.RtmpClient.reConnect$default(RtmpClient.kt:439)
    at com.shd.nest.dji.rtmp.RtmpPublisher.onConnectionFailedRtmp(RtmpPublisher.kt:95)
    at com.pedro.rtmp.rtmp.RtmpSender.start$lambda-2(RtmpSender.kt:133)
    at com.pedro.rtmp.rtmp.RtmpSender.lambda$5sw3xMk-TljoSOH0h26wXmD9F0M(RtmpSender.kt)
    at com.pedro.rtmp.rtmp.-$$Lambda$RtmpSender$5sw3xMk-TljoSOH0h26wXmD9F0M.run(lambda)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    ... 2 more
java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:898)
    at com.pedro.rtmp.utils.socket.TcpSocket.close(TcpSocket.kt:63)
    at com.pedro.rtmp.rtmp.RtmpClient.closeConnection(RtmpClient.kt:434)
    at com.pedro.rtmp.rtmp.RtmpClient.disconnect(RtmpClient.kt:477)
    at com.pedro.rtmp.rtmp.RtmpClient.reConnect(RtmpClient.kt:441)
    at com.pedro.rtmp.rtmp.RtmpClient.reConnect$default(RtmpClient.kt:439)
    at com.shd.nest.dji.rtmp.RtmpPublisher.onConnectionFailedRtmp(RtmpPublisher.kt:95)
    at com.pedro.rtmp.rtmp.RtmpSender.start$lambda-2(RtmpSender.kt:133)
    at com.pedro.rtmp.rtmp.RtmpSender.lambda$5sw3xMk-TljoSOH0h26wXmD9F0M(RtmpSender.kt)
    at com.pedro.rtmp.rtmp.-$$Lambda$RtmpSender$5sw3xMk-TljoSOH0h26wXmD9F0M.run(lambda)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)

=======Thread info======Crash name:java.lang.Error: java.net.SocketException: Socket is closed
 Cause is:java.net.SocketException: Socket is closed
 Thread name is:pool-9-thread-1 778
 Thread count is:136
 Fd count is:380

Name:   com.shd.nest
State:  S (sleeping)
Tgid:   5880
Ngid:   0
Pid:    5880
PPid:   302
TracerPid:  0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 512
Groups: 1007 1015 1023 1024 2001 3001 3002 3003 9997 41000 
VmPeak:  3465960 kB
VmSize:  3405396 kB
VmLck:        48 kB
VmPin:         0 kB
VmHWM:    620712 kB
VmRSS:    596212 kB
VmData:   429780 kB
VmStk:      8192 kB
VmExe:        16 kB
VmLib:    252540 kB
VmPTE:      2452 kB
VmPMD:        28 kB
VmSwap:        0 kB
Threads:    208
SigQ:   3/15346
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000001204
SigIgn: 0000000000000000
SigCgt: 20000002000086f8
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000000000000000
CapAmb: 0000000000000000
Seccomp:    0
Cpus_allowed:   3f
Cpus_allowed_list:  0-5
Mems_allowed:   1
Mems_allowed_list:  0
voluntary_ctxt_switches:    1338510
nonvoluntary_ctxt_switches: 1191624

```java
pedroSG94 commented 1 year ago

This is already fixed here: https://github.com/pedroSG94/rtmp-rtsp-stream-client-java/commit/b4ca9bd7569855dd0e9c261fc83c41fb7a10a951 I will release a new version today with the fix included