桌面推流ok
This commit is contained in:
parent
b5df0c6374
commit
ff8769f4ac
|
|
@ -50,5 +50,7 @@ dependencies {
|
|||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
implementation project(':zlm')
|
||||
implementation 'com.guolindev.permissionx:permissionx:1.7.1'
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,14 +1,23 @@
|
|||
package com.zlmediakit.webrtc
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.permissionx.guolindev.PermissionX
|
||||
import com.permissionx.guolindev.callback.RequestCallback
|
||||
import com.zlm.rtc.ZLMRTCPusher
|
||||
import com.zlm.rtc.push.PushMode
|
||||
import com.zlm.rtc.push.ZLMRTCPusherImpl
|
||||
import kotlinx.android.synthetic.main.activity_player.surface_view_renderer
|
||||
import kotlinx.android.synthetic.main.activity_player.tv_app
|
||||
import kotlinx.android.synthetic.main.activity_player.tv_stream_id
|
||||
|
||||
class PusherDemoActivity: AppCompatActivity() {
|
||||
class PusherDemoActivity : AppCompatActivity() {
|
||||
|
||||
|
||||
private val pusher: ZLMRTCPusher by lazy {
|
||||
|
|
@ -16,23 +25,50 @@ class PusherDemoActivity: AppCompatActivity() {
|
|||
}
|
||||
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContentView(R.layout.activity_pusher)
|
||||
|
||||
pusher.bind(surface_view_renderer, true)
|
||||
|
||||
}
|
||||
|
||||
fun onPushCamera(view: View) {
|
||||
|
||||
|
||||
|
||||
pusher.push(tv_app.text.toString(), tv_stream_id.text.toString())
|
||||
PermissionX.init(this)
|
||||
.permissions(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
|
||||
.request { allGranted, grantedList, deniedList ->
|
||||
if (allGranted) {
|
||||
pusher.push(tv_app.text.toString(), tv_stream_id.text.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onPushScreen(view: View) {
|
||||
PermissionX.init(this)
|
||||
.permissions(Manifest.permission.RECORD_AUDIO)
|
||||
.request { allGranted, grantedList, deniedList ->
|
||||
if (allGranted) {
|
||||
pusher.push(
|
||||
tv_app.text.toString(),
|
||||
tv_stream_id.text.toString(),
|
||||
PushMode.SCREEN
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onPushFile(view: View) {
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
pusher.stop()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/surface_view_renderer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="240dp" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
v=0
|
||||
o=- 6282534540641525368 2 IN IP4 127.0.0.1
|
||||
s=-
|
||||
t=0 0
|
||||
a=group:BUNDLE 0 1 2
|
||||
a=extmap-allow-mixed
|
||||
a=msid-semantic: WMS
|
||||
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:H2Ms
|
||||
a=ice-pwd:14ODtTVh5+lT7W0+g9EAlE4j
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 47:81:90:07:43:95:D7:F2:DA:60:DA:79:E5:88:26:65:29:4A:26:28:7A:B7:AB:D3:DB:CE:C9:09:39:EB:31:91
|
||||
a=setup:actpass
|
||||
a=mid:0
|
||||
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=sendrecv
|
||||
a=msid:- ef1bcbd2-7e69-40d3-9532-0f4a698022a7
|
||||
a=rtcp-mux
|
||||
a=rtpmap:111 opus/48000/2
|
||||
a=rtcp-fb:111 transport-cc
|
||||
a=fmtp:111 minptime=10;useinbandfec=1
|
||||
a=rtpmap:63 red/48000/2
|
||||
a=fmtp:63 111/111
|
||||
a=rtpmap:9 G722/8000
|
||||
a=rtpmap:102 ILBC/8000
|
||||
a=rtpmap:0 PCMU/8000
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:13 CN/8000
|
||||
a=rtpmap:110 telephone-event/48000
|
||||
a=rtpmap:126 telephone-event/8000
|
||||
a=ssrc:2860285610 cname:2EW1hNfQMKxwbRrt
|
||||
a=ssrc:2860285610 msid:- ef1bcbd2-7e69-40d3-9532-0f4a698022a7
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 96 97 39 40 98 99 127 103 104 105 106 107 108
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:H2Ms
|
||||
a=ice-pwd:14ODtTVh5+lT7W0+g9EAlE4j
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 47:81:90:07:43:95:D7:F2:DA:60:DA:79:E5:88:26:65:29:4A:26:28:7A:B7:AB:D3:DB:CE:C9:09:39:EB:31:91
|
||||
a=setup:actpass
|
||||
a=mid:1
|
||||
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:13 urn:3gpp:video-orientation
|
||||
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
|
||||
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
|
||||
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
|
||||
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
|
||||
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
|
||||
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
|
||||
a=sendonly
|
||||
a=msid:- 8b57ef63-835d-4acf-bce9-18e26cebf9b1
|
||||
a=rtcp-mux
|
||||
a=rtcp-rsize
|
||||
a=rtpmap:96 VP8/90000
|
||||
a=rtcp-fb:96 goog-remb
|
||||
a=rtcp-fb:96 transport-cc
|
||||
a=rtcp-fb:96 ccm fir
|
||||
a=rtcp-fb:96 nack
|
||||
a=rtcp-fb:96 nack pli
|
||||
a=rtpmap:97 rtx/90000
|
||||
a=fmtp:97 apt=96
|
||||
a=rtpmap:39 AV1/90000
|
||||
a=rtcp-fb:39 goog-remb
|
||||
a=rtcp-fb:39 transport-cc
|
||||
a=rtcp-fb:39 ccm fir
|
||||
a=rtcp-fb:39 nack
|
||||
a=rtcp-fb:39 nack pli
|
||||
a=rtpmap:40 rtx/90000
|
||||
a=fmtp:40 apt=39
|
||||
a=rtpmap:98 VP9/90000
|
||||
a=rtcp-fb:98 goog-remb
|
||||
a=rtcp-fb:98 transport-cc
|
||||
a=rtcp-fb:98 ccm fir
|
||||
a=rtcp-fb:98 nack
|
||||
a=rtcp-fb:98 nack pli
|
||||
a=fmtp:98 profile-id=0
|
||||
a=rtpmap:99 rtx/90000
|
||||
a=fmtp:99 apt=98
|
||||
a=rtpmap:127 H264/90000
|
||||
a=rtcp-fb:127 goog-remb
|
||||
a=rtcp-fb:127 transport-cc
|
||||
a=rtcp-fb:127 ccm fir
|
||||
a=rtcp-fb:127 nack
|
||||
a=rtcp-fb:127 nack pli
|
||||
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
|
||||
a=rtpmap:103 rtx/90000
|
||||
a=fmtp:103 apt=127
|
||||
a=rtpmap:104 H265/90000
|
||||
a=rtcp-fb:104 goog-remb
|
||||
a=rtcp-fb:104 transport-cc
|
||||
a=rtcp-fb:104 ccm fir
|
||||
a=rtcp-fb:104 nack
|
||||
a=rtcp-fb:104 nack pli
|
||||
a=rtpmap:105 rtx/90000
|
||||
a=fmtp:105 apt=104
|
||||
a=rtpmap:106 red/90000
|
||||
a=rtpmap:107 rtx/90000
|
||||
a=fmtp:107 apt=106
|
||||
a=rtpmap:108 ulpfec/90000
|
||||
a=ssrc-group:FID 100166069 2038394461
|
||||
a=ssrc:100166069 cname:2EW1hNfQMKxwbRrt
|
||||
a=ssrc:100166069 msid:- 8b57ef63-835d-4acf-bce9-18e26cebf9b1
|
||||
a=ssrc:2038394461 cname:2EW1hNfQMKxwbRrt
|
||||
a=ssrc:2038394461 msid:- 8b57ef63-835d-4acf-bce9-18e26cebf9b1
|
||||
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:H2Ms
|
||||
a=ice-pwd:14ODtTVh5+lT7W0+g9EAlE4j
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 47:81:90:07:43:95:D7:F2:DA:60:DA:79:E5:88:26:65:29:4A:26:28:7A:B7:AB:D3:DB:CE:C9:09:39:EB:31:91
|
||||
a=setup:actpass
|
||||
a=mid:2
|
||||
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=sendonly
|
||||
a=msid:- 49d08cb1-a325-4a5f-805a-72a215eb67af
|
||||
a=rtcp-mux
|
||||
a=rtpmap:111 opus/48000/2
|
||||
a=rtcp-fb:111 transport-cc
|
||||
a=fmtp:111 minptime=10;useinbandfec=1
|
||||
a=rtpmap:63 red/48000/2
|
||||
a=fmtp:63 111/111
|
||||
a=rtpmap:9 G722/8000
|
||||
a=rtpmap:102 ILBC/8000
|
||||
a=rtpmap:0 PCMU/8000
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:13 CN/8000
|
||||
a=rtpmap:110 telephone-event/48000
|
||||
a=rtpmap:126 telephone-event/8000
|
||||
a=ssrc:2666757999 cname:2EW1hNfQMKxwbRrt
|
||||
a=ssrc:2666757999 msid:- 49d08cb1-a325-4a5f-805a-72a215eb67af
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
v=0
|
||||
o=- 6005790964057401669 2 IN IP4 127.0.0.1
|
||||
s=-
|
||||
t=0 0
|
||||
a=group:BUNDLE 0 1
|
||||
a=extmap-allow-mixed
|
||||
a=msid-semantic: WMS ARDAMS
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 96 97 39 40 98 99 127 103 104 105 106 107 108
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:UITA
|
||||
a=ice-pwd:obg6A6ZHKhr5CGzmmgRfTk/y
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 5E:23:E2:B2:0F:ED:FC:A2:20:06:24:0F:6A:4B:99:33:91:39:A7:40:A5:20:88:77:D6:99:04:FB:C7:CD:7F:33
|
||||
a=setup:actpass
|
||||
a=mid:0
|
||||
a=extmap:1 urn:ietf:params:rtp-hdrext:toffset
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:3 urn:3gpp:video-orientation
|
||||
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
|
||||
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
|
||||
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
|
||||
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
|
||||
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
|
||||
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
|
||||
a=sendrecv
|
||||
a=msid:ARDAMS ARDAMSv0
|
||||
a=rtcp-mux
|
||||
a=rtcp-rsize
|
||||
a=rtpmap:96 VP8/90000
|
||||
a=rtcp-fb:96 goog-remb
|
||||
a=rtcp-fb:96 transport-cc
|
||||
a=rtcp-fb:96 ccm fir
|
||||
a=rtcp-fb:96 nack
|
||||
a=rtcp-fb:96 nack pli
|
||||
a=rtpmap:97 rtx/90000
|
||||
a=fmtp:97 apt=96
|
||||
a=rtpmap:39 AV1/90000
|
||||
a=rtcp-fb:39 goog-remb
|
||||
a=rtcp-fb:39 transport-cc
|
||||
a=rtcp-fb:39 ccm fir
|
||||
a=rtcp-fb:39 nack
|
||||
a=rtcp-fb:39 nack pli
|
||||
a=rtpmap:40 rtx/90000
|
||||
a=fmtp:40 apt=39
|
||||
a=rtpmap:98 VP9/90000
|
||||
a=rtcp-fb:98 goog-remb
|
||||
a=rtcp-fb:98 transport-cc
|
||||
a=rtcp-fb:98 ccm fir
|
||||
a=rtcp-fb:98 nack
|
||||
a=rtcp-fb:98 nack pli
|
||||
a=fmtp:98 profile-id=0
|
||||
a=rtpmap:99 rtx/90000
|
||||
a=fmtp:99 apt=98
|
||||
a=rtpmap:127 H264/90000
|
||||
a=rtcp-fb:127 goog-remb
|
||||
a=rtcp-fb:127 transport-cc
|
||||
a=rtcp-fb:127 ccm fir
|
||||
a=rtcp-fb:127 nack
|
||||
a=rtcp-fb:127 nack pli
|
||||
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
|
||||
a=rtpmap:103 rtx/90000
|
||||
a=fmtp:103 apt=127
|
||||
a=rtpmap:104 H265/90000
|
||||
a=rtcp-fb:104 goog-remb
|
||||
a=rtcp-fb:104 transport-cc
|
||||
a=rtcp-fb:104 ccm fir
|
||||
a=rtcp-fb:104 nack
|
||||
a=rtcp-fb:104 nack pli
|
||||
a=rtpmap:105 rtx/90000
|
||||
a=fmtp:105 apt=104
|
||||
a=rtpmap:106 red/90000
|
||||
a=rtpmap:107 rtx/90000
|
||||
a=fmtp:107 apt=106
|
||||
a=rtpmap:108 ulpfec/90000
|
||||
a=ssrc-group:FID 1882091013 3163545249
|
||||
a=ssrc:1882091013 cname:L6diPFsW7sR8uU/a
|
||||
a=ssrc:1882091013 msid:ARDAMS ARDAMSv0
|
||||
a=ssrc:3163545249 cname:L6diPFsW7sR8uU/a
|
||||
a=ssrc:3163545249 msid:ARDAMS ARDAMSv0
|
||||
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:UITA
|
||||
a=ice-pwd:obg6A6ZHKhr5CGzmmgRfTk/y
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 5E:23:E2:B2:0F:ED:FC:A2:20:06:24:0F:6A:4B:99:33:91:39:A7:40:A5:20:88:77:D6:99:04:FB:C7:CD:7F:33
|
||||
a=setup:actpass
|
||||
a=mid:1
|
||||
a=extmap:14 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=sendrecv
|
||||
a=msid:ARDAMS ARDAMSa0
|
||||
a=rtcp-mux
|
||||
a=rtpmap:111 opus/48000/2
|
||||
a=rtcp-fb:111 transport-cc
|
||||
a=fmtp:111 minptime=10;useinbandfec=1
|
||||
a=rtpmap:63 red/48000/2
|
||||
a=fmtp:63 111/111
|
||||
a=rtpmap:9 G722/8000
|
||||
a=rtpmap:102 ILBC/8000
|
||||
a=rtpmap:0 PCMU/8000
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:13 CN/8000
|
||||
a=rtpmap:110 telephone-event/48000
|
||||
a=rtpmap:126 telephone-event/8000
|
||||
a=ssrc:1776947399 cname:L6diPFsW7sR8uU/a
|
||||
a=ssrc:1776947399 msid:ARDAMS ARDAMSa0
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
v=0
|
||||
o=- 2629706501878304631 2 IN IP4 127.0.0.1
|
||||
s=-
|
||||
t=0 0
|
||||
a=group:BUNDLE 0 1
|
||||
a=extmap-allow-mixed
|
||||
a=msid-semantic: WMS ARDAMS
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 96 97 39 40 98 99 127 103 104 105 106 107 108 43
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:+zOA
|
||||
a=ice-pwd:q88Il7adjqdu6SeSqAdsv8lv
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 8D:0B:86:0B:8C:DF:22:99:85:DD:60:41:AA:FE:F1:98:FE:FB:29:32:5C:11:6E:47:54:82:21:6C:A0:4F:60:B2
|
||||
a=setup:actpass
|
||||
a=mid:0
|
||||
a=extmap:1 urn:ietf:params:rtp-hdrext:toffset
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:3 urn:3gpp:video-orientation
|
||||
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
|
||||
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
|
||||
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
|
||||
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
|
||||
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
|
||||
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
|
||||
a=sendrecv
|
||||
a=msid:ARDAMS ARDAMSv0
|
||||
a=rtcp-mux
|
||||
a=rtcp-rsize
|
||||
a=rtpmap:96 VP8/90000
|
||||
a=rtcp-fb:96 goog-remb
|
||||
a=rtcp-fb:96 transport-cc
|
||||
a=rtcp-fb:96 ccm fir
|
||||
a=rtcp-fb:96 nack
|
||||
a=rtcp-fb:96 nack pli
|
||||
a=rtpmap:97 rtx/90000
|
||||
a=fmtp:97 apt=96
|
||||
a=rtpmap:39 AV1/90000
|
||||
a=rtcp-fb:39 goog-remb
|
||||
a=rtcp-fb:39 transport-cc
|
||||
a=rtcp-fb:39 ccm fir
|
||||
a=rtcp-fb:39 nack
|
||||
a=rtcp-fb:39 nack pli
|
||||
a=rtpmap:40 rtx/90000
|
||||
a=fmtp:40 apt=39
|
||||
a=rtpmap:98 VP9/90000
|
||||
a=rtcp-fb:98 goog-remb
|
||||
a=rtcp-fb:98 transport-cc
|
||||
a=rtcp-fb:98 ccm fir
|
||||
a=rtcp-fb:98 nack
|
||||
a=rtcp-fb:98 nack pli
|
||||
a=fmtp:98 profile-id=0
|
||||
a=rtpmap:99 rtx/90000
|
||||
a=fmtp:99 apt=98
|
||||
a=rtpmap:127 H264/90000
|
||||
a=rtcp-fb:127 goog-remb
|
||||
a=rtcp-fb:127 transport-cc
|
||||
a=rtcp-fb:127 ccm fir
|
||||
a=rtcp-fb:127 nack
|
||||
a=rtcp-fb:127 nack pli
|
||||
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
|
||||
a=rtpmap:103 rtx/90000
|
||||
a=fmtp:103 apt=127
|
||||
a=rtpmap:104 H265/90000
|
||||
a=rtcp-fb:104 goog-remb
|
||||
a=rtcp-fb:104 transport-cc
|
||||
a=rtcp-fb:104 ccm fir
|
||||
a=rtcp-fb:104 nack
|
||||
a=rtcp-fb:104 nack pli
|
||||
a=rtpmap:105 rtx/90000
|
||||
a=fmtp:105 apt=104
|
||||
a=rtpmap:106 red/90000
|
||||
a=rtpmap:107 rtx/90000
|
||||
a=fmtp:107 apt=106
|
||||
a=rtpmap:108 ulpfec/90000
|
||||
a=rtpmap:43 flexfec-03/90000
|
||||
a=rtcp-fb:43 goog-remb
|
||||
a=rtcp-fb:43 transport-cc
|
||||
a=fmtp:43 repair-window=10000000
|
||||
a=ssrc-group:FID 129065984 1082217256
|
||||
a=ssrc-group:FEC-FR 129065984 4071693473
|
||||
a=ssrc:129065984 cname:T1fpJkmBNuVUtXM8
|
||||
a=ssrc:129065984 msid:ARDAMS ARDAMSv0
|
||||
a=ssrc:1082217256 cname:T1fpJkmBNuVUtXM8
|
||||
a=ssrc:1082217256 msid:ARDAMS ARDAMSv0
|
||||
a=ssrc:4071693473 cname:T1fpJkmBNuVUtXM8
|
||||
a=ssrc:4071693473 msid:ARDAMS ARDAMSv0
|
||||
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126
|
||||
c=IN IP4 0.0.0.0
|
||||
a=rtcp:9 IN IP4 0.0.0.0
|
||||
a=ice-ufrag:+zOA
|
||||
a=ice-pwd:q88Il7adjqdu6SeSqAdsv8lv
|
||||
a=ice-options:trickle renomination
|
||||
a=fingerprint:sha-256 8D:0B:86:0B:8C:DF:22:99:85:DD:60:41:AA:FE:F1:98:FE:FB:29:32:5C:11:6E:47:54:82:21:6C:A0:4F:60:B2
|
||||
a=setup:actpass
|
||||
a=mid:1
|
||||
a=extmap:14 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
||||
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
||||
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
||||
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
|
||||
a=sendrecv
|
||||
a=msid:ARDAMS ARDAMSa0
|
||||
a=rtcp-mux
|
||||
a=rtpmap:111 opus/48000/2
|
||||
a=rtcp-fb:111 transport-cc
|
||||
a=fmtp:111 minptime=10;useinbandfec=1
|
||||
a=rtpmap:63 red/48000/2
|
||||
a=fmtp:63 111/111
|
||||
a=rtpmap:9 G722/8000
|
||||
a=rtpmap:102 ILBC/8000
|
||||
a=rtpmap:0 PCMU/8000
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:13 CN/8000
|
||||
a=rtpmap:110 telephone-event/48000
|
||||
a=rtpmap:126 telephone-event/8000
|
||||
a=ssrc:2019904101 cname:T1fpJkmBNuVUtXM8
|
||||
a=ssrc:2019904101 msid:ARDAMS ARDAMSa0
|
||||
|
|
@ -12,5 +12,12 @@
|
|||
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
<application>
|
||||
<service android:name="com.zlm.rtc.push.ScreenShareService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:foregroundServiceType="mediaProjection"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -1,9 +1,14 @@
|
|||
package com.zlm.rtc
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.zlm.rtc.push.PushMode
|
||||
import org.webrtc.SurfaceViewRenderer
|
||||
|
||||
abstract class ZLMRTCPusher {
|
||||
abstract fun push(app: String, streamId: String)
|
||||
|
||||
public abstract fun bind(surface: SurfaceViewRenderer, localPreview: Boolean)
|
||||
|
||||
abstract fun push(app: String, streamId: String, mode: PushMode = PushMode.CAMERA)
|
||||
|
||||
abstract fun stop()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.zlm.rtc.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
public class ActivityLauncher {
|
||||
private static final String TAG = "ActivityLauncher";
|
||||
private Context mContext;
|
||||
private RouterFragment mRouterFragment;
|
||||
|
||||
public static ActivityLauncher init(FragmentActivity activity) {
|
||||
return new ActivityLauncher(activity);
|
||||
}
|
||||
|
||||
private ActivityLauncher(FragmentActivity activity) {
|
||||
mContext = activity;
|
||||
mRouterFragment = getRouterFragment(activity);
|
||||
}
|
||||
|
||||
private RouterFragment getRouterFragment(FragmentActivity activity) {
|
||||
RouterFragment routerFragment = findRouterFragment(activity);
|
||||
if (routerFragment == null) {
|
||||
routerFragment = RouterFragment.newInstance();
|
||||
FragmentManager fragmentManager = activity.getSupportFragmentManager();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(routerFragment, TAG)
|
||||
.commitAllowingStateLoss();
|
||||
fragmentManager.executePendingTransactions();
|
||||
}
|
||||
return routerFragment;
|
||||
}
|
||||
|
||||
private RouterFragment findRouterFragment(FragmentActivity activity) {
|
||||
return (RouterFragment) activity.getSupportFragmentManager().findFragmentByTag(TAG);
|
||||
}
|
||||
|
||||
public void startActivityForResult(Class<?> clazz, Callback callback) {
|
||||
Intent intent = new Intent(mContext, clazz);
|
||||
startActivityForResult(intent, callback);
|
||||
}
|
||||
|
||||
public void startActivityForResult(Intent intent, Callback callback) {
|
||||
mRouterFragment.startActivityForResult(intent, callback);
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onActivityResult(int resultCode, Intent data);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.zlm.rtc.base;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RouterFragment extends Fragment {
|
||||
|
||||
private SparseArray<ActivityLauncher.Callback> mCallbacks = new SparseArray<>();
|
||||
private Random mCodeGenerator = new Random();
|
||||
|
||||
public RouterFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
public static RouterFragment newInstance() {
|
||||
return new RouterFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
public void startActivityForResult(Intent intent, ActivityLauncher.Callback callback) {
|
||||
int requestCode = makeRequestCode();
|
||||
mCallbacks.put(requestCode, callback);
|
||||
startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成唯一的requestCode,最多尝试10次
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private int makeRequestCode() {
|
||||
int requestCode;
|
||||
int tryCount = 0;
|
||||
do {
|
||||
requestCode = mCodeGenerator.nextInt(0x0000FFFF);
|
||||
tryCount++;
|
||||
} while (mCallbacks.indexOfKey(requestCode) >= 0 && tryCount < 10);
|
||||
return requestCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
ActivityLauncher.Callback callback = mCallbacks.get(requestCode);
|
||||
mCallbacks.remove(requestCode);
|
||||
if (callback != null) {
|
||||
callback.onActivityResult(resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -636,7 +636,7 @@ public class PeerConnectionClient {
|
|||
// Create SDP constraints.
|
||||
sdpMediaConstraints = new MediaConstraints();
|
||||
sdpMediaConstraints.mandatory.add(
|
||||
new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
|
||||
new MediaConstraints.KeyValuePair("OfferToReceiveAudio", Boolean.toString(true)));
|
||||
sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
|
||||
"OfferToReceiveVideo", Boolean.toString(true)));//这里
|
||||
}
|
||||
|
|
@ -692,8 +692,10 @@ public class PeerConnectionClient {
|
|||
|
||||
if (saveVideoFileRecorder == null) {
|
||||
saveVideoFileRecorder = new VideoFileRecorder();
|
||||
|
||||
}
|
||||
// peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO,new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_RECV));
|
||||
// peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO,new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_RECV));
|
||||
|
||||
Log.d(TAG, "Peer connection created.");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.zlm.rtc.push
|
||||
|
||||
enum class PushMode {
|
||||
CAMERA, SCREEN, FILE
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.zlm.rtc.push
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.media.projection.MediaProjectionManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.zlm.rtc.R
|
||||
|
||||
class ScreenShareService :Service(){
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
val resultCode = intent?.getIntExtra("resultCode", -1)
|
||||
val resultData = intent?.getParcelableExtra<Intent>("data")
|
||||
createNotificationChannel()
|
||||
|
||||
resultCode?.let {code->
|
||||
resultData?.let { data->
|
||||
val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
|
||||
val mediaProjection = mediaProjectionManager.getMediaProjection(code, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(
|
||||
"ScreenShared", "屏幕录制",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
val manager = getSystemService(
|
||||
NotificationManager::class.java
|
||||
)
|
||||
manager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
val notification = NotificationCompat.Builder(this, "ScreenShared")
|
||||
.setContentTitle("屏幕分享")
|
||||
.setContentText("分享中...")
|
||||
.setSmallIcon(R.drawable.icon_screen_share)
|
||||
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.icon_screen_share))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
startForeground(1024, notification)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
package com.zlm.rtc.push
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.media.AudioManager
|
||||
import android.content.Intent
|
||||
import android.media.projection.MediaProjection
|
||||
import android.media.projection.MediaProjectionManager
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.zlm.rtc.NativeLib
|
||||
import com.zlm.rtc.ZLMRTCPusher
|
||||
import com.zlm.rtc.base.ActivityLauncher
|
||||
import com.zlm.rtc.client.HttpClient
|
||||
import com.zlm.rtc.client.PeerConnectionClient
|
||||
import org.json.JSONObject
|
||||
|
|
@ -15,6 +20,7 @@ import org.webrtc.CameraEnumerator
|
|||
import org.webrtc.EglBase
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.PeerConnectionFactory
|
||||
import org.webrtc.ScreenCapturerAndroid
|
||||
import org.webrtc.SessionDescription
|
||||
import org.webrtc.StatsReport
|
||||
import org.webrtc.SurfaceViewRenderer
|
||||
|
|
@ -22,7 +28,7 @@ import org.webrtc.VideoCapturer
|
|||
import java.math.BigInteger
|
||||
import kotlin.random.Random
|
||||
|
||||
class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
||||
class ZLMRTCPusherImpl(val context: FragmentActivity) : ZLMRTCPusher(),
|
||||
PeerConnectionClient.PeerConnectionEvents {
|
||||
|
||||
|
||||
|
|
@ -39,6 +45,10 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
private var app: String = ""
|
||||
private var streamId: String = ""
|
||||
|
||||
|
||||
private val CAPTURE_PERMISSION_REQUEST_CODE = 1
|
||||
|
||||
|
||||
private fun initPeerConnectionClient(): PeerConnectionClient {
|
||||
eglBase = EglBase.create()
|
||||
return PeerConnectionClient(
|
||||
|
|
@ -47,19 +57,19 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
1280,
|
||||
720,
|
||||
defaultFps,
|
||||
1024 * 1000 * 2,
|
||||
"H264",
|
||||
true,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"VP8",
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
"OPUS",
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
|
@ -74,6 +84,18 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
} else {
|
||||
createCameraCapture(Camera1Enumerator(true))
|
||||
}
|
||||
|
||||
return videoCapturer
|
||||
}
|
||||
|
||||
|
||||
private fun createScreenCapture(context: Context?): VideoCapturer? {
|
||||
val videoCapturer: VideoCapturer? = if (Camera2Enumerator.isSupported(context)) {
|
||||
createCameraCapture(Camera2Enumerator(context))
|
||||
} else {
|
||||
createCameraCapture(Camera1Enumerator(true))
|
||||
}
|
||||
|
||||
return videoCapturer
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +135,12 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
|
||||
|
||||
|
||||
override fun push(app: String, streamId: String) {
|
||||
override fun bind(surface: SurfaceViewRenderer, localPreview: Boolean) {
|
||||
this.surfaceViewRenderer = surface
|
||||
}
|
||||
|
||||
|
||||
override fun push(app: String, streamId: String, mode: PushMode) {
|
||||
this.app = app
|
||||
this.streamId = streamId
|
||||
if (peerConnectionClient == null) peerConnectionClient = initPeerConnectionClient()
|
||||
|
|
@ -121,10 +148,41 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
peerConnectionClient?.setAudioEnabled(true)
|
||||
peerConnectionClient?.setVideoEnabled(true)
|
||||
peerConnectionClient?.createPeerConnectionFactory(PeerConnectionFactory.Options())
|
||||
peerConnectionClient?.createPeerConnection(createVideoCapture(context), localHandleId)
|
||||
peerConnectionClient?.createOffer(localHandleId)
|
||||
}
|
||||
|
||||
if (mode == PushMode.CAMERA) {
|
||||
peerConnectionClient?.createPeerConnection(createVideoCapture(context), localHandleId)
|
||||
peerConnectionClient?.createOffer(localHandleId)
|
||||
|
||||
} else if (mode == PushMode.SCREEN) {
|
||||
|
||||
val mediaProjectionManager = context.getSystemService(
|
||||
Context.MEDIA_PROJECTION_SERVICE
|
||||
) as MediaProjectionManager
|
||||
|
||||
ActivityLauncher.init(context).startActivityForResult(
|
||||
mediaProjectionManager.createScreenCaptureIntent()
|
||||
) { resultCode, data ->
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
|
||||
ContextCompat.startForegroundService(context, Intent(context, ScreenShareService::class.java))
|
||||
|
||||
val screenCapturerAndroid =
|
||||
ScreenCapturerAndroid(data, object : MediaProjection.Callback() {
|
||||
|
||||
})
|
||||
|
||||
peerConnectionClient?.createPeerConnection(screenCapturerAndroid, localHandleId)
|
||||
peerConnectionClient?.createOffer(localHandleId)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
surfaceViewRenderer?.clearImage()
|
||||
|
|
@ -144,6 +202,7 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
mutableMapOf()
|
||||
)
|
||||
val result = JSONObject(doPost)
|
||||
logger(result.toString())
|
||||
val code = result.getInt("code")
|
||||
if (code == 0) {
|
||||
logger("handleId: $doPost")
|
||||
|
|
@ -155,11 +214,12 @@ class ZLMRTCPusherImpl(val context:Context) :ZLMRTCPusher(),
|
|||
} else {
|
||||
val msg = result.getString("msg")
|
||||
logger("handleId: $msg")
|
||||
peerConnectionClient?.setAudioEnabled(false)
|
||||
peerConnectionClient?.setVideoEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onIceCandidate(handleId: BigInteger?, candidate: IceCandidate?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onIceCandidatesRemoved(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:viewportHeight="1024"
|
||||
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#333333" android:pathData="M740.4,709.3H298.7a98.2,98.2 0,0 1,-98.1 -98.1V360.2A98.2,98.2 0,0 1,298.7 262.1h426.7a98.2,98.2 0,0 1,98.1 98.1v266a12.8,12.8 0,0 1,-25.6 0V360.2a72.6,72.6 0,0 0,-72.5 -72.5H298.7a72.6,72.6 0,0 0,-72.5 72.5v251a72.6,72.6 0,0 0,72.5 72.5h441.7a12.8,12.8 0,0 1,0 25.6zM612.2,761.9H401.1a12.8,12.8 0,1 1,0 -25.6h211.1a12.8,12.8 0,0 1,0 25.6z"/>
|
||||
<path android:fillColor="#0098F0" android:pathData="M649.2,483.3L531.6,390v54.8c-147,0.7 -156.8,136.5 -156.8,136.5 49,-68.3 156.8,-58.9 156.8,-58.9v54.3z"/>
|
||||
</vector>
|
||||
Loading…
Reference in New Issue