diff --git a/webrtc_player/android/.gitattributes b/webrtc_player/android/.gitattributes deleted file mode 100644 index 0c9b41ab..00000000 --- a/webrtc_player/android/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -zlm/libs/arm64-v8a/libZLToolKit.a filter=lfs diff=lfs merge=lfs -text -zlm/libs/armeabi-v7a/libZLToolKit.a filter=lfs diff=lfs merge=lfs -text diff --git a/webrtc_player/android/.gitignore b/webrtc_player/android/.gitignore index d4c3a57e..aa724b77 100644 --- a/webrtc_player/android/.gitignore +++ b/webrtc_player/android/.gitignore @@ -13,4 +13,3 @@ .externalNativeBuild .cxx local.properties -/.idea/ diff --git a/webrtc_player/android/.idea/.gitignore b/webrtc_player/android/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/webrtc_player/android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/webrtc_player/android/.idea/.name b/webrtc_player/android/.idea/.name new file mode 100644 index 00000000..377c1793 --- /dev/null +++ b/webrtc_player/android/.idea/.name @@ -0,0 +1 @@ +RTCPlayer \ No newline at end of file diff --git a/webrtc_player/android/.idea/compiler.xml b/webrtc_player/android/.idea/compiler.xml new file mode 100644 index 00000000..b589d56e --- /dev/null +++ b/webrtc_player/android/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/webrtc_player/android/.idea/deploymentTargetDropDown.xml b/webrtc_player/android/.idea/deploymentTargetDropDown.xml new file mode 100644 index 00000000..0c0c3383 --- /dev/null +++ b/webrtc_player/android/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/webrtc_player/android/.idea/gradle.xml b/webrtc_player/android/.idea/gradle.xml new file mode 100644 index 00000000..32522c1e --- /dev/null +++ b/webrtc_player/android/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/webrtc_player/android/.idea/kotlinc.xml b/webrtc_player/android/.idea/kotlinc.xml new file mode 100644 index 00000000..8d81632f --- /dev/null +++ b/webrtc_player/android/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/webrtc_player/android/.idea/migrations.xml b/webrtc_player/android/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/webrtc_player/android/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/webrtc_player/android/.idea/misc.xml b/webrtc_player/android/.idea/misc.xml new file mode 100644 index 00000000..0ad17cbd --- /dev/null +++ b/webrtc_player/android/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/webrtc_player/android/.idea/vcs.xml b/webrtc_player/android/.idea/vcs.xml new file mode 100644 index 00000000..b2bdec2d --- /dev/null +++ b/webrtc_player/android/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/webrtc_player/android/README.md b/webrtc_player/android/README.md new file mode 100644 index 00000000..bd2e7ab3 --- /dev/null +++ b/webrtc_player/android/README.md @@ -0,0 +1,104 @@ +# RTCPlayer 播放器 + +一个基于Android客户端的的RTC播放器 + +## 项目特点 + + - 低延迟 + - [X]支持[ZLMediakit](https://github.com/ZLMediaKit/ZLMediaKit)流媒体 + - [ ]支持[SRS](https://github.com/ossrs/srs) + - [ ]支持[Janus](https://github.com/meetecho/janus-gateway) + +
+     +     + +
+ +## 延迟情况 + +- **网页端推流,Android端播放** + +
+     +     + +
+ +三次延迟分别为:490ms、526ms、560ms + +- **Android端推屏幕流,网页端播放** + +
+     +     + +
+ +三次延迟分别为:440ms、430ms、387ms + +## 接口说明 + +### Player + +- bind(surface: RTCSurfaceView) + + 绑定视图 + +- play(app: String, streamId: String) + + 播放 +- setVolume(volume:Float) + + 设置音量,范围: 0.0~1.0f +- stop() + + 停止播放 +- pause() + + 暂停播放 +- resume() + + 恢复播放 +- capture(listener: (bitmap: Bitmap) -> Unit) + + 截图 +- record(duration: Long, result: (path: String) -> Unit) + + 录制 +- setOnErrorListener(listener: (code: Int, msg: String) -> Unit) + + 设置播放器错误监听回调 +- setOnStatusListener(listener: (status: Status) -> Unit) + + 设置播放器状态回调 + +### Pusher + +- bind(surface: RTCSurfaceView, localPreview: Boolean) + + 绑定视图 + +- push(app: String, streamId: String, mode: PushMode = PushMode.CAMERA, inputFile: String = "") + + 推流,支持Camera、Screen、File + +- stop() + + 停止推流 + +- setOnErrorListener(listener: (code: Int, msg: String) -> Unit) + + 设置播放器错误监听回调 + +## 联系作者 +如果您需要深度二次开发,并支持其他流媒体服务,可以找我哦! +[李之阳](https://github.com/leo94666) + +## 特别感谢 + +感谢[ZLMediakit](https://github.com/ZLMediaKit/ZLMediaKit)开源项目 + +同时感谢JetBrains对开源项目的支持,本项目使用Android Studio开发与调试: + +[![Android Studio](https://th.bing.com/th?id=ODLS.d2ea10a5-5792-4f82-bd13-1595fd9d969c&w=32&h=32&qlt=90&pcl=fffffa&o=6&pid=1.2)](https://developer.android.com/studio?hl=zh-cn) \ No newline at end of file diff --git a/webrtc_player/android/app-debug.apk b/webrtc_player/android/app-debug.apk deleted file mode 100644 index 969d48b7..00000000 Binary files a/webrtc_player/android/app-debug.apk and /dev/null differ diff --git a/webrtc_player/android/app/.gitignore b/webrtc_player/android/app/.gitignore index c591fdeb..42afabfd 100644 --- a/webrtc_player/android/app/.gitignore +++ b/webrtc_player/android/app/.gitignore @@ -1,2 +1 @@ -/build -.cxx \ No newline at end of file +/build \ No newline at end of file diff --git a/webrtc_player/android/app/build.gradle b/webrtc_player/android/app/build.gradle deleted file mode 100644 index 6bacd76e..00000000 --- a/webrtc_player/android/app/build.gradle +++ /dev/null @@ -1,56 +0,0 @@ -plugins { - id 'com.android.application' - id 'org.jetbrains.kotlin.android' - id 'kotlin-android-extensions' - id 'kotlin-kapt' - -} -apply plugin: 'kotlin-android' - -android { - compileSdk 32 - - defaultConfig { - applicationId "com.zlmediakit.webrtc" - minSdk 24 - targetSdk 32 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -dependencies { - - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.5.1' - implementation 'com.google.android.material:material:1.6.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - implementation 'com.google.code.gson:gson:2.8.9' - - implementation("com.squareup.okhttp3:okhttp:4.10.0") - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - - implementation project(':zlm') - implementation 'com.guolindev.permissionx:permissionx:1.7.1' - - -} \ No newline at end of file diff --git a/webrtc_player/android/app/build.gradle.kts b/webrtc_player/android/app/build.gradle.kts new file mode 100644 index 00000000..9ca6cebf --- /dev/null +++ b/webrtc_player/android/app/build.gradle.kts @@ -0,0 +1,58 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + +} + +android { + namespace = "com.top.player" + compileSdk = 34 + + defaultConfig { + applicationId = "com.top.player" + minSdk = 24 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + viewBinding { + enable = true + } +} + +dependencies { + + implementation("androidx.appcompat:appcompat:1.5.1") + implementation("com.google.android.material:material:1.6.1") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.3") + androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") + + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22") + implementation("com.guolindev.permissionx:permissionx:1.7.1") + + //implementation(project(":RTCPlayer")) + implementation("com.rtc.core:RTCPlayer:1.0.0.beta") + +} \ No newline at end of file diff --git a/webrtc_player/android/app/src/androidTest/java/com/top/player/ExampleInstrumentedTest.java b/webrtc_player/android/app/src/androidTest/java/com/top/player/ExampleInstrumentedTest.java new file mode 100644 index 00000000..2c5af40e --- /dev/null +++ b/webrtc_player/android/app/src/androidTest/java/com/top/player/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.top.player; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.top.player", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/webrtc_player/android/app/src/androidTest/java/com/zlmediakit/webrtc/ExampleInstrumentedTest.kt b/webrtc_player/android/app/src/androidTest/java/com/zlmediakit/webrtc/ExampleInstrumentedTest.kt deleted file mode 100644 index 645a1102..00000000 --- a/webrtc_player/android/app/src/androidTest/java/com/zlmediakit/webrtc/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.zlmediakit.webrtc - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.zlmediakit.webrtc", appContext.packageName) - } -} \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/AndroidManifest.xml b/webrtc_player/android/app/src/main/AndroidManifest.xml index 28a013ba..1e944e3c 100644 --- a/webrtc_player/android/app/src/main/AndroidManifest.xml +++ b/webrtc_player/android/app/src/main/AndroidManifest.xml @@ -1,24 +1,27 @@ + xmlns:tools="http://schemas.android.com/tools"> - - + + + android:required="true" /> + + + + + + + + + + + + + + - - - - - - - - - - + tools:overrideLibrary="com.rtc.core" + android:name=".App"> @@ -43,12 +45,13 @@ - - - + + + \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/App.kt b/webrtc_player/android/app/src/main/java/com/top/player/App.kt similarity index 80% rename from webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/App.kt rename to webrtc_player/android/app/src/main/java/com/top/player/App.kt index 5d1796f6..1c457ffd 100644 --- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/App.kt +++ b/webrtc_player/android/app/src/main/java/com/top/player/App.kt @@ -1,4 +1,4 @@ -package com.zlmediakit.webrtc +package com.top.player import android.app.Application diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt b/webrtc_player/android/app/src/main/java/com/top/player/MainActivity.kt similarity index 87% rename from webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt rename to webrtc_player/android/app/src/main/java/com/top/player/MainActivity.kt index d22a5b8e..8cb2a7e5 100644 --- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/MainActivity.kt +++ b/webrtc_player/android/app/src/main/java/com/top/player/MainActivity.kt @@ -1,4 +1,4 @@ -package com.zlmediakit.webrtc +package com.top.player import android.content.Intent import android.os.Bundle @@ -11,7 +11,6 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - } fun toPlayActivity(view: View) { @@ -23,7 +22,4 @@ class MainActivity : AppCompatActivity() { } - fun toDataChannelActivity(view: View) { - - } } \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/java/com/top/player/PlayerDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/top/player/PlayerDemoActivity.kt new file mode 100644 index 00000000..50f810cb --- /dev/null +++ b/webrtc_player/android/app/src/main/java/com/top/player/PlayerDemoActivity.kt @@ -0,0 +1,112 @@ +package com.top.player + +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import com.rtc.core.ZLMRTCPlayer +import com.rtc.core.play.Status +import com.rtc.core.play.ZLMRTCPlayerImpl +import com.top.player.databinding.ActivityPlayerBinding + + +class PlayerDemoActivity : AppCompatActivity() { + + + private val player: ZLMRTCPlayer by lazy { + ZLMRTCPlayerImpl(this) + } + + + private val binding by lazy { + ActivityPlayerBinding.inflate(layoutInflater) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(binding.root) + + //ffmpeg -re -stream_loop -1 -i "D:\li\hot\data\data\baseline.mp4" -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp -bf 0 rtsp://zlmediakit.com/live/li + //ffmpeg -re -stream_loop -1 -i "D:\li\hot\data\data\test.mp4" -vcodec h264 -acodec aac -f flv -bf 0 rtmp://zlmediakit.com/live/li + + setTitle("Player Demo") + player.bind(binding.surfaceViewRender) + + player.setOnErrorListener { code, msg -> + Toast.makeText(this, "code:$code,msg:${msg}", Toast.LENGTH_SHORT).show() + + } + + player.setOnStatusListener { + when (it) { + Status.PREPARING -> { + binding.tvStatus.text = "准备播放" + } + + Status.PLAYING -> { + binding.tvStatus.text = "播放中.." + } + + Status.PAUSE -> { + binding.tvStatus.text = "暂停中.." + } + + Status.RESUME -> { + binding.tvStatus.text = "播放中.." + } + + Status.STOP -> { + binding.tvStatus.text = "" + } + + Status.ERROR -> { + binding.tvStatus.text = "播放异常" + } + + else -> {} + } + } + + } + + + override fun onDestroy() { + super.onDestroy() + player.stop() + } + + fun onPlayClick(view: View) { + + player.play(binding.tvApp.text.toString(), binding.tvStreamId.text.toString()) + } + + fun onPauseClick(view: View) { + player.pause() + //Toast.makeText(this, "ok", Toast.LENGTH_SHORT).show() + } + + fun onStopClick(view: View) { + player.stop() + } + + fun onResumeClick(view: View) { + player.resume() + } + + fun onCapture(view: View) { + player.capture { + Toast.makeText(this, "capture ok", Toast.LENGTH_SHORT).show() + } + } + + fun onRecord(view: View) { + player.record(10 * 1000) { + Toast.makeText(this, "" + it, Toast.LENGTH_SHORT).show() + } + } + + fun onVolume(view: View) { + player.setVolume(0.0f) + } +} \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PusherDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/top/player/PusherDemoActivity.kt similarity index 60% rename from webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PusherDemoActivity.kt rename to webrtc_player/android/app/src/main/java/com/top/player/PusherDemoActivity.kt index 9139dda4..168dafe5 100644 --- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PusherDemoActivity.kt +++ b/webrtc_player/android/app/src/main/java/com/top/player/PusherDemoActivity.kt @@ -1,21 +1,19 @@ -package com.zlmediakit.webrtc +package com.top.player import android.Manifest import android.content.Intent -import android.content.pm.PackageManager import android.os.Bundle import android.view.View +import android.widget.Toast 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 +import com.rtc.core.RTCSurfaceView +import com.rtc.core.ZLMRTCPusher +import com.rtc.core.push.PushMode +import com.rtc.core.push.ZLMRTCPusherImpl +import com.top.player.databinding.ActivityPlayerBinding +import com.top.player.databinding.ActivityPusherBinding + class PusherDemoActivity : AppCompatActivity() { @@ -25,15 +23,25 @@ class PusherDemoActivity : AppCompatActivity() { } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) + private val binding by lazy { + ActivityPusherBinding.inflate(layoutInflater) } + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pusher) - pusher.bind(surface_view_renderer, true) + val rtcSurfaceView = findViewById(R.id.surface_view_render) + + pusher.bind(rtcSurfaceView, true) + setTitle("Pusher Demo") + + + pusher.setOnErrorListener { code, msg -> + Toast.makeText(this, "code:${code},msg:${msg}", Toast.LENGTH_SHORT).show() + } } @@ -42,7 +50,7 @@ class PusherDemoActivity : AppCompatActivity() { .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()) + pusher.push(binding.tvApp.text.toString(), binding.tvStreamId.text.toString()) } } } @@ -53,8 +61,8 @@ class PusherDemoActivity : AppCompatActivity() { .request { allGranted, grantedList, deniedList -> if (allGranted) { pusher.push( - tv_app.text.toString(), - tv_stream_id.text.toString(), + binding.tvApp.text.toString(), + binding.tvStreamId.text.toString(), PushMode.SCREEN ) } @@ -67,8 +75,8 @@ class PusherDemoActivity : AppCompatActivity() { .request { allGranted, grantedList, deniedList -> if (allGranted) { pusher.push( - tv_app.text.toString(), - tv_stream_id.text.toString(), + binding.tvApp.text.toString(), + binding.tvStreamId.text.toString(), PushMode.FILE, "" ) @@ -81,5 +89,9 @@ class PusherDemoActivity : AppCompatActivity() { pusher.stop() } + fun onStopPush(view: View) { + pusher.stop() + } + } \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayDemoActivity.kt deleted file mode 100644 index fb950b32..00000000 --- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayDemoActivity.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.zlmediakit.webrtc - -import android.annotation.SuppressLint -import android.graphics.drawable.BitmapDrawable -import android.os.Bundle -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import com.zlm.rtc.ZLMRTCPlayer -import kotlinx.android.synthetic.main.activity_main.* -import kotlinx.android.synthetic.main.activity_main.view.* -import kotlinx.android.synthetic.main.activity_play.* - - -class PlayDemoActivity : AppCompatActivity() { - - private var isSpeaker = true - - @SuppressLint("SetTextI18n") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_play) - - lifecycle.addObserver(web_rtc_sv) - - - - - - //http://124.223.98.45/index/api/webrtc?app=live&stream=test&type=play - url.setText("https://zlmediakit.com/index/api/webrtc?app=live&stream=test&type=play") - - //http://192.168.1.17/index/api/webrtc?app=live&stream=test&type=play - btn_play.setOnClickListener { - web_rtc_sv?.setVideoPath(url.text.toString()) - web_rtc_sv.start() - } - - web_rtc_sv.setOnErrorListener { errorCode, errorMsg -> - runOnUiThread { - Toast.makeText(this, "errorCode:$errorCode,errorMsg:$errorMsg", Toast.LENGTH_SHORT) - .show() - } - } - - - btn_pause.setOnClickListener { - web_rtc_sv?.pause() - } - - btn_resume.setOnClickListener { - web_rtc_sv?.resume() - } - - btn_screenshot.setOnClickListener { - web_rtc_sv?.screenshot { - runOnUiThread { - iv_screen.setImageDrawable(BitmapDrawable(it)) - } - } - } - - btn_mute.setOnClickListener { - web_rtc_sv.mute(true) - } - - - selectAudio() - btn_speaker.setOnClickListener { - selectAudio() - } - - } - - fun selectAudio(){ - if (isSpeaker){ - btn_speaker.setText("扬声器") - web_rtc_sv.setSpeakerphoneOn(isSpeaker) - }else{ - btn_speaker.setText("话筒") - web_rtc_sv.setSpeakerphoneOn(isSpeaker) - } - isSpeaker=!isSpeaker - } -} \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayerDemoActivity.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayerDemoActivity.kt deleted file mode 100644 index 0f016858..00000000 --- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/PlayerDemoActivity.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.zlmediakit.webrtc - -import android.os.Bundle -import android.view.View -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import com.zlm.rtc.ZLMRTCPlayer -import com.zlm.rtc.play.ZLMRTCPlayerImpl -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 PlayerDemoActivity : AppCompatActivity() { - - - private val player: ZLMRTCPlayer by lazy { - ZLMRTCPlayerImpl(this) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContentView(R.layout.activity_player) - - //ffmpeg -re -stream_loop -1 -i "D:\li\hot\data\data\baseline.mp4" -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp -bf 0 rtsp://zlmediakit.com/live/li - //ffmpeg -re -stream_loop -1 -i "D:\li\hot\data\data\test.mp4" -vcodec h264 -acodec aac -f flv -bf 0 rtmp://zlmediakit.com/live/li - - player.bind(surface_view_renderer) - - } - - - override fun onDestroy() { - super.onDestroy() - player.stop() - } - - fun onPlayClick(view: View) { - - player.play(tv_app.text.toString(), tv_stream_id.text.toString()) - } - - fun onPauseClick(view: View) { - player.pause() - } - - fun onStopClick(view: View) { - player.stop() - } - - fun onResumeClick(view: View) { - player.resume() - } - - fun onCapture(view: View) { - player.capture { - Toast.makeText(this, "capture ok", Toast.LENGTH_SHORT).show() - } - } - - fun onRecord(view: View) { - player.record(10 * 1000) { - Toast.makeText(this, "" + it, Toast.LENGTH_SHORT).show() - } - } - - fun onVolume(view: View) { - player.setVolume() - } -} \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/WebRTCSurfaceView.kt b/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/WebRTCSurfaceView.kt deleted file mode 100644 index 3e94171c..00000000 --- a/webrtc_player/android/app/src/main/java/com/zlmediakit/webrtc/WebRTCSurfaceView.kt +++ /dev/null @@ -1,439 +0,0 @@ -package com.zlmediakit.webrtc - -import android.content.Context -import android.graphics.Bitmap -import android.media.AudioManager -import android.util.AttributeSet -import android.util.Log -import android.view.LayoutInflater -import android.widget.RelativeLayout -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import com.google.gson.Gson -import okhttp3.* -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import org.webrtc.* -import org.webrtc.RendererCommon.ScalingType -import org.webrtc.audio.AudioDeviceModule -import org.webrtc.audio.JavaAudioDeviceModule -import java.io.IOException -import java.util.* - -public class WebRTCSurfaceView(context: Context, attrs: AttributeSet?) : - RelativeLayout(context, attrs), DefaultLifecycleObserver, RendererCommon.RendererEvents { - - - private data class sdp(var sdp: String, var username: String, var password: String) - - private data class SdpResponse(var code: Int, var id: String, var sdp: String, var type: String) - - private enum class ErrorCode(val errorCode: Int) { - SUCCESS(0x00), - GET_REMOTE_SDP_ERROR(0x01); - } - - - companion object { - private val TAG = "WebRTCSurfaceView" - - } - - private var mContext: Context = context - - private val eglBase: EglBase = EglBase.create() - private var mEGLBaseContext: EglBase.Context = eglBase.eglBaseContext - - private lateinit var videoUrl: String; - - private var mPeerConnectionFactory: PeerConnectionFactory? = null - - private var mLocalMediaStream: MediaStream? = null - private var mLocalAudioTrack: AudioTrack? = null - private var mAudioSource: AudioSource? = null - - private var mLocalSessionDescription: SessionDescription? = null - private var mRemoteSessionDescription: SessionDescription? = null - - private var mLocalPeer: Peer? = null - - private var mSurfaceViewRenderer: SurfaceViewRenderer - - private lateinit var OnErrorListener: (errorCode: Int, errorMsg: String) -> Unit? - - fun setOnErrorListener(listener: (errorCode: Int, errorMsg: String) -> Unit) { - this.OnErrorListener = listener - } - - private lateinit var OnPreparedListener: () -> Unit? - - fun setOnPreparedListener(listener: () -> Unit) { - this.OnPreparedListener = listener - } - - private val audioManager: AudioManager - - - init { - - val view = LayoutInflater.from(mContext).inflate(R.layout.layout_videoview, this) - - mPeerConnectionFactory = createConnectionFactory() - - mSurfaceViewRenderer = view.findViewById(R.id.surface_view_renderer) - - mSurfaceViewRenderer.init(mEGLBaseContext, this) - mSurfaceViewRenderer.setScalingType(ScalingType.SCALE_ASPECT_FILL) - mSurfaceViewRenderer.setEnableHardwareScaler(true) - - - //创建媒体流 - mLocalMediaStream = mPeerConnectionFactory?.createLocalMediaStream("ARDAMS") - //采集音频 - mAudioSource = mPeerConnectionFactory?.createAudioSource(createAudioConstraints()) - mLocalAudioTrack = mPeerConnectionFactory?.createAudioTrack("ARDAMSa0", mAudioSource) - - //添加Tracks - mLocalMediaStream?.addTrack(mLocalAudioTrack) - - audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager - audioManager.isSpeakerphoneOn = false - - - } - - - private fun set(width: Int, height: Int) { - layoutParams.width = width - layoutParams.height = height - } - - private fun createConnectionFactory(): PeerConnectionFactory? { - - val options = PeerConnectionFactory.InitializationOptions.builder(mContext) - .setEnableInternalTracer(false) - .createInitializationOptions() - - PeerConnectionFactory.initialize(options) - - val videoEncoderFactory = DefaultVideoEncoderFactory( - mEGLBaseContext, - true, - true - ) - - val videoDecoderFactory = DefaultVideoDecoderFactory(mEGLBaseContext) - - - val audioDevice = createJavaAudioDevice() - val peerConnectionFactory = PeerConnectionFactory.builder() - .setAudioDeviceModule(audioDevice) - .setVideoEncoderFactory(videoEncoderFactory) - .setVideoDecoderFactory(videoDecoderFactory) - .createPeerConnectionFactory() - audioDevice.release() - - return peerConnectionFactory - - } - - private fun createAudioConstraints(): MediaConstraints { - val audioConstraints = MediaConstraints() - audioConstraints.mandatory.add( - MediaConstraints.KeyValuePair( - "googEchoCancellation", - "true" - ) - ) - audioConstraints.mandatory.add( - MediaConstraints.KeyValuePair( - "googAutoGainControl", - "false" - ) - ) - audioConstraints.mandatory.add( - MediaConstraints.KeyValuePair( - "googHighpassFilter", - "true" - ) - ) - audioConstraints.mandatory.add( - MediaConstraints.KeyValuePair( - "googNoiseSuppression", - "true" - ) - ) - return audioConstraints - } - - private fun offerOrAnswerConstraint(): MediaConstraints { - val mediaConstraints = MediaConstraints() - val keyValuePairs = java.util.ArrayList() - keyValuePairs.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")) - keyValuePairs.add(MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true")) - mediaConstraints.mandatory.addAll(keyValuePairs) - return mediaConstraints - } - - private fun createJavaAudioDevice(): AudioDeviceModule { - val audioTrackErrorCallback: JavaAudioDeviceModule.AudioTrackErrorCallback = object : - JavaAudioDeviceModule.AudioTrackErrorCallback { - override fun onWebRtcAudioTrackInitError(errorMessage: String) { - Log.i(TAG, "onWebRtcAudioTrackInitError ============> $errorMessage") - - } - - override fun onWebRtcAudioTrackStartError( - errorCode: JavaAudioDeviceModule.AudioTrackStartErrorCode, errorMessage: String - ) { - Log.i(TAG, "onWebRtcAudioTrackStartError ============> $errorCode:$errorMessage") - - } - - override fun onWebRtcAudioTrackError(errorMessage: String) { - Log.i(TAG, "onWebRtcAudioTrackError ============> $errorMessage") - - } - } - - - // Set audio track state callbacks. - val audioTrackStateCallback: JavaAudioDeviceModule.AudioTrackStateCallback = object : - JavaAudioDeviceModule.AudioTrackStateCallback { - override fun onWebRtcAudioTrackStart() { - Log.i(TAG, "onWebRtcAudioTrackStart ============>") - - } - - override fun onWebRtcAudioTrackStop() { - Log.i(TAG, "onWebRtcAudioTrackStop ============>") - - } - } - - return JavaAudioDeviceModule.builder(mContext) - .setUseHardwareAcousticEchoCanceler(true) - .setUseHardwareNoiseSuppressor(true) - .setAudioTrackErrorCallback(audioTrackErrorCallback) - .setAudioTrackStateCallback(audioTrackStateCallback) - .setUseStereoOutput(true) //立体声 - .createAudioDeviceModule() - } - - fun setVideoPath(url: String) { - videoUrl = url - } - - fun start() { - - mLocalPeer = Peer { - val okHttpClient = OkHttpClient.Builder().build() - - - val body = RequestBody.create("text/plain; charset=utf-8".toMediaType(), it!!) - - - val request: Request = Request.Builder() - .url(videoUrl) - .post(body) - .build() - - val call: Call = okHttpClient.newCall(request) - - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - Log.i(TAG, "onFailure") - OnErrorListener?.invoke( - ErrorCode.GET_REMOTE_SDP_ERROR.errorCode, - e.message.toString() - ) - } - - override fun onResponse(call: Call, response: Response) { - val body = response.body?.string() - val sdpResponse = Gson().fromJson(body, SdpResponse::class.java) - - try { - mRemoteSessionDescription = SessionDescription( - SessionDescription.Type.fromCanonicalForm("answer"), - sdpResponse.sdp - ) - Log.i( - TAG, - "RemoteSdpObserver onCreateSuccess:[SessionDescription[type=${mRemoteSessionDescription?.type?.name},description=${mRemoteSessionDescription?.description}]]" - ) - mLocalPeer?.setRemoteDescription(mRemoteSessionDescription!!) - } catch (e: Exception) { - Log.i(TAG, e.toString()) - OnErrorListener.invoke( - ErrorCode.GET_REMOTE_SDP_ERROR.errorCode, - e.localizedMessage - ) - } - } - }) - } - } - - fun pause() { - mSurfaceViewRenderer.pauseVideo() - //mSurfaceViewRenderer.disableFpsReduction() - } - - fun resume() { - mSurfaceViewRenderer.setFpsReduction(15f) - } - - fun screenshot(listener: (bitmap: Bitmap) -> Unit) { - mSurfaceViewRenderer.addFrameListener({ - listener.invoke(it) - }, 1f) - } - - fun setSpeakerphoneOn(on: Boolean) { - audioManager.isSpeakerphoneOn = on - } - - fun mute(on:Boolean) { - audioManager.isMicrophoneMute=on - } - - override fun onDestroy(owner: LifecycleOwner) { - super.onDestroy(owner) - mSurfaceViewRenderer.release() - mLocalPeer?.mPeerConnection?.dispose() - mAudioSource?.dispose() - mPeerConnectionFactory?.dispose() - } - - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec) - - } - - inner class Peer(var sdp: (String?) -> Unit = {}) : PeerConnection.Observer, SdpObserver { - - var mPeerConnection: PeerConnection? = null - - init { - mPeerConnection = createPeerConnection() - mPeerConnection?.createOffer(this, offerOrAnswerConstraint()) - } - - //初始化 RTCPeerConnection 连接管道 - private fun createPeerConnection(): PeerConnection? { - if (mPeerConnectionFactory == null) { - mPeerConnectionFactory = createConnectionFactory() - } - // 管道连接抽象类实现方法 - val ICEServers = LinkedList() - val rtcConfig = PeerConnection.RTCConfiguration(ICEServers) - //修改模式 PlanB无法使用仅接收音视频的配置 - //rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.PLAN_B - return mPeerConnectionFactory?.createPeerConnection(rtcConfig, this) - } - - fun setRemoteDescription(sdp: SessionDescription) { - mPeerConnection?.setRemoteDescription(this, sdp) - } - - override fun onCreateSuccess(sessionDescription: SessionDescription?) { - mPeerConnection?.setLocalDescription(this, sessionDescription) - mPeerConnection?.addStream(mLocalMediaStream) - sdp.invoke(sessionDescription?.description) - } - - override fun onSetSuccess() { - - } - - override fun onCreateFailure(p0: String?) { - - } - - override fun onSetFailure(p0: String?) { - - } - - override fun onSignalingChange(signalingState: PeerConnection.SignalingState?) { - Log.i(TAG, "onSignalingChange ============> " + signalingState.toString()) - } - - override fun onIceConnectionChange(iceConnectionState: PeerConnection.IceConnectionState?) { - Log.i(TAG, "onIceConnectionChange ============> " + iceConnectionState.toString()) - - } - - override fun onIceConnectionReceivingChange(p0: Boolean) { - Log.i(TAG, "onIceConnectionReceivingChange ============> $p0") - - } - - override fun onIceGatheringChange(iceGatheringState: PeerConnection.IceGatheringState?) { - Log.i(TAG, "onIceGatheringChange ============> ${iceGatheringState.toString()}") - } - - override fun onIceCandidate(iceCandidate: IceCandidate?) { - Log.i(TAG, "onIceCandidate ============> ${iceCandidate.toString()}") - - - } - - override fun onIceCandidatesRemoved(p0: Array?) { - Log.i(TAG, "onIceCandidatesRemoved ============> ${p0.toString()}") - } - - override fun onAddStream(mediaStream: MediaStream?) { - Log.i(TAG, "onAddStream ============> ${mediaStream?.toString()}") - - if (mediaStream?.videoTracks?.isEmpty() != true) { - val remoteVideoTrack = mediaStream?.videoTracks?.get(0) - remoteVideoTrack?.setEnabled(true) - remoteVideoTrack?.addSink(mSurfaceViewRenderer) - } - - if (mediaStream?.audioTracks?.isEmpty() != true) { - val remoteAudioTrack = mediaStream?.audioTracks?.get(0) - remoteAudioTrack?.setEnabled(true) - remoteAudioTrack?.setVolume(1.0) - } - - - } - - override fun onRemoveStream(mediaStream: MediaStream?) { - Log.i(TAG, "onRemoveStream ============> ${mediaStream.toString()}") - - } - - override fun onDataChannel(dataChannel: DataChannel?) { - Log.i(TAG, "onDataChannel ============> ${dataChannel.toString()}") - - } - - override fun onRenegotiationNeeded() { - Log.i(TAG, "onRenegotiationNeeded ============>") - - } - - override fun onAddTrack(rtpReceiver: RtpReceiver?, p1: Array?) { - Log.i(TAG, "onAddTrack ============>" + rtpReceiver?.track()) - Log.i(TAG, "onAddTrack ============>" + p1?.size) - - } - } - - override fun onFirstFrameRendered() { - Log.i(TAG, "onFirstFrameRendered ============>") - - } - - override fun onFrameResolutionChanged(frameWidth: Int, frameHeight: Int, rotation: Int) { - Log.i(TAG, "onFrameResolutionChanged ============> $frameWidth:$frameHeight:$rotation") - //set(frameWidth,frameHeight) - } - - - - -} \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/webrtc_player/android/app/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from webrtc_player/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to webrtc_player/android/app/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/webrtc_player/android/app/src/main/res/layout/activity_main.xml b/webrtc_player/android/app/src/main/res/layout/activity_main.xml index 6cb0ffaa..afb6529b 100644 --- a/webrtc_player/android/app/src/main/res/layout/activity_main.xml +++ b/webrtc_player/android/app/src/main/res/layout/activity_main.xml @@ -8,6 +8,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="toPlayActivity" + android:text="播放" /> - \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/layout/activity_play.xml b/webrtc_player/android/app/src/main/res/layout/activity_play.xml deleted file mode 100644 index c84e17e0..00000000 --- a/webrtc_player/android/app/src/main/res/layout/activity_play.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/layout/activity_player.xml b/webrtc_player/android/app/src/main/res/layout/activity_player.xml index 6f9b47b4..eebedc84 100644 --- a/webrtc_player/android/app/src/main/res/layout/activity_player.xml +++ b/webrtc_player/android/app/src/main/res/layout/activity_player.xml @@ -5,16 +5,28 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + + + android:layout_below="@id/surface_view_render"> diff --git a/webrtc_player/android/app/src/main/res/layout/activity_pusher.xml b/webrtc_player/android/app/src/main/res/layout/activity_pusher.xml index 81bbe808..484ee730 100644 --- a/webrtc_player/android/app/src/main/res/layout/activity_pusher.xml +++ b/webrtc_player/android/app/src/main/res/layout/activity_pusher.xml @@ -1,11 +1,11 @@ - - @@ -13,8 +13,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintTop_toBottomOf="@id/surface_view_renderer" - > + android:layout_below="@id/surface_view_render" + app:layout_constraintTop_toBottomOf="@id/surface_view_render"> + android:layout_below="@id/surface_view_render"> @@ -82,5 +82,14 @@ android:textAllCaps="false" android:onClick="onPushFile"/> + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/layout/layout_videoview.xml b/webrtc_player/android/app/src/main/res/layout/layout_videoview.xml deleted file mode 100644 index 43c56e5e..00000000 --- a/webrtc_player/android/app/src/main/res/layout/layout_videoview.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cfe..6f3b755b 100644 --- a/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe..6f3b755b 100644 --- a/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/webrtc_player/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/values-night/themes.xml b/webrtc_player/android/app/src/main/res/values-night/themes.xml index 6a2a7eac..79caf632 100644 --- a/webrtc_player/android/app/src/main/res/values-night/themes.xml +++ b/webrtc_player/android/app/src/main/res/values-night/themes.xml @@ -1,16 +1,7 @@ - \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/values/colors.xml b/webrtc_player/android/app/src/main/res/values/colors.xml index f8c6127d..c8524cd9 100644 --- a/webrtc_player/android/app/src/main/res/values/colors.xml +++ b/webrtc_player/android/app/src/main/res/values/colors.xml @@ -1,10 +1,5 @@ - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 #FF000000 #FFFFFFFF \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/values/strings.xml b/webrtc_player/android/app/src/main/res/values/strings.xml index 7a3df89f..5fb2987c 100644 --- a/webrtc_player/android/app/src/main/res/values/strings.xml +++ b/webrtc_player/android/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - ZLMediakit WebRTC + RTCPlayer \ No newline at end of file diff --git a/webrtc_player/android/app/src/main/res/values/themes.xml b/webrtc_player/android/app/src/main/res/values/themes.xml index 119a9df9..df2c41fa 100644 --- a/webrtc_player/android/app/src/main/res/values/themes.xml +++ b/webrtc_player/android/app/src/main/res/values/themes.xml @@ -1,16 +1,9 @@ - + +