11package com.tencent.iot.explorer.link.demo.video.preview
22
33import android.Manifest
4+ import android.app.Service
5+ import android.content.pm.ActivityInfo
46import android.graphics.SurfaceTexture
57import android.media.AudioFormat
8+ import android.media.AudioManager
69import android.os.Handler
710import android.os.Message
811import android.text.TextUtils
@@ -13,6 +16,7 @@ import android.view.TextureView
1316import android.view.View
1417import android.view.WindowManager
1518import android.widget.Toast
19+ import androidx.constraintlayout.widget.ConstraintLayout
1620import com.alibaba.fastjson.JSONArray
1721import com.tencent.iot.explorer.link.demo.BuildConfig
1822import com.tencent.iot.explorer.link.demo.R
@@ -23,28 +27,35 @@ import com.tencent.iot.explorer.link.demo.common.util.ImageSelect
2327import com.tencent.iot.explorer.link.demo.video.Command
2428import com.tencent.iot.explorer.link.demo.video.DevInfo
2529import com.tencent.iot.explorer.link.demo.video.playback.VideoPlaybackActivity
30+ import com.tencent.iot.explorer.link.demo.video.utils.ListOptionsDialog
2631import com.tencent.iot.explorer.link.demo.video.utils.TipToastDialog
2732import com.tencent.iot.explorer.link.demo.video.utils.ToastDialog
2833import com.tencent.iot.video.link.util.audio.AudioRecordUtil
2934import com.tencent.xnet.XP2P
3035import com.tencent.xnet.XP2PAppConfig
3136import com.tencent.xnet.XP2PCallback
3237import com.tencent.xnet.annotations.XP2PProtocolType
38+ import kotlinx.android.synthetic.main.activity_video_preview.btn_layout
39+ import kotlinx.android.synthetic.main.activity_video_preview.iv_audio
3340import kotlinx.android.synthetic.main.activity_video_preview.iv_down
3441import kotlinx.android.synthetic.main.activity_video_preview.iv_left
42+ import kotlinx.android.synthetic.main.activity_video_preview.iv_orientation
3543import kotlinx.android.synthetic.main.activity_video_preview.iv_right
3644import kotlinx.android.synthetic.main.activity_video_preview.iv_up
45+ import kotlinx.android.synthetic.main.activity_video_preview.layout_content
3746import kotlinx.android.synthetic.main.activity_video_preview.layout_video_preview
3847import kotlinx.android.synthetic.main.activity_video_preview.radio_photo
3948import kotlinx.android.synthetic.main.activity_video_preview.radio_playback
4049import kotlinx.android.synthetic.main.activity_video_preview.radio_record
4150import kotlinx.android.synthetic.main.activity_video_preview.radio_talk
4251import kotlinx.android.synthetic.main.activity_video_preview.tv_video_quality
4352import kotlinx.android.synthetic.main.activity_video_preview.v_preview
53+ import kotlinx.android.synthetic.main.activity_video_preview.v_title
4454import kotlinx.android.synthetic.main.dash_board_layout.tv_a_cache
4555import kotlinx.android.synthetic.main.dash_board_layout.tv_tcp_speed
4656import kotlinx.android.synthetic.main.dash_board_layout.tv_v_cache
4757import kotlinx.android.synthetic.main.dash_board_layout.tv_video_w_h
58+ import kotlinx.android.synthetic.main.title_layout.iv_back
4859import kotlinx.coroutines.CoroutineScope
4960import kotlinx.coroutines.Dispatchers
5061import kotlinx.coroutines.MainScope
@@ -62,9 +73,10 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
6273 IMediaPlayer .OnInfoListener {
6374 private val player = IjkMediaPlayer ()
6475 lateinit var surface: Surface
65- private var productId = " "
66- private var deviceName = " "
67- private var xp2pInfo = " "
76+ private var productId: String = " "
77+ private var deviceName: String = " "
78+ private var xp2pInfo: String = " "
79+ private val channel: Int = 0
6880 var urlPrefix = " "
6981 var screenWidth = 0
7082 var screenHeight = 0
@@ -80,6 +92,8 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
8092
8193 @Volatile
8294 var speakAble = false
95+ var audioAble = true
96+ var orientationV = true
8397
8498 private val xP2PAppConfig = XP2PAppConfig ().also { appConfig ->
8599 appConfig.appKey =
@@ -141,7 +155,7 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
141155 private fun checkDeviceState () {
142156 Log .d(" VideoTestActivity" , " ====检测设备状态===" )
143157 launch(Dispatchers .IO ) {
144- val command = " action=user_define&channel=0 &cmd=device_state"
158+ val command = " action=user_define&channel=${channel} &cmd=device_state"
145159 val retContent = XP2P .postCommandRequestSync(
146160 " ${productId} /${deviceName} " ,
147161 command.toByteArray(), command.toByteArray().size.toLong(), 1 * 1000 * 1000
@@ -153,9 +167,9 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
153167// restartService()
154168// }
155169// } else {
156- launch(Dispatchers .Main ) {
157- delegateHttpFlv()
158- }
170+ launch(Dispatchers .Main ) {
171+ delegateHttpFlv()
172+ }
159173// }
160174 }
161175 }
@@ -175,6 +189,16 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
175189 }
176190
177191 override fun setListener () {
192+ iv_back.setOnClickListener { finish() }
193+ iv_orientation.setOnClickListener {
194+ orientationV = ! orientationV
195+ switchOrientation(orientationV)
196+ }
197+ tv_video_quality.setOnClickListener(switchVideoQualityListener)
198+ iv_audio.setOnClickListener {
199+ audioAble = ! audioAble
200+ chgAudioStatus(audioAble)
201+ }
178202 radio_talk.setOnCheckedChangeListener { buttonView, isChecked ->
179203 if (isChecked && checkPermissions(permissions)) {
180204 if (! speakAble(true )) radio_talk.isChecked = false
@@ -223,14 +247,122 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
223247 iv_left.setOnClickListener(controlListener)
224248 }
225249
250+ private fun chgAudioStatus (audioAble : Boolean ) {
251+ if (! audioAble) {
252+ iv_audio.setImageResource(R .mipmap.no_audio)
253+ player.setVolume(0F , 0F )
254+ } else {
255+ iv_audio.setImageResource(R .mipmap.audio)
256+ val audioManager = getSystemService(Service .AUDIO_SERVICE ) as AudioManager
257+ val volume = audioManager.getStreamVolume(AudioManager .STREAM_MUSIC )
258+ player.setVolume(volume.toFloat(), volume.toFloat())
259+ }
260+ }
261+
262+ private var switchVideoQualityListener = View .OnClickListener {
263+ if (orientationV) {
264+ showVVideoQualityDialog()
265+ } else {
266+ showHVideoQualityDialog()
267+ }
268+ }
269+
270+ private fun showVVideoQualityDialog () {
271+ val options = arrayListOf (
272+ getString(R .string.video_quality_high_str) + " " + getString(R .string.video_quality_high),
273+ getString(R .string.video_quality_medium_str) + " " + getString(R .string.video_quality_medium),
274+ getString(R .string.video_quality_low_str) + " " + getString(R .string.video_quality_low)
275+ )
276+ val dlg = ListOptionsDialog (this , options)
277+ dlg.show()
278+ dlg.setOnDismisListener { chgTextState(it) }
279+ }
280+
281+ private fun showHVideoQualityDialog () {
282+ var pos = - 1
283+ when (tv_video_quality.text.toString()) {
284+ getString(R .string.video_quality_high_str) -> pos = 2
285+ getString(R .string.video_quality_medium_str) -> pos = 1
286+ getString(R .string.video_quality_low_str) -> pos = 0
287+ }
288+ val dlg = VideoQualityDialog (this , pos)
289+ dlg.show()
290+ btn_layout.visibility = View .GONE
291+ dlg.setOnDismisListener(object : VideoQualityDialog .OnDismisListener {
292+ override fun onItemClicked (pos : Int ) {
293+ chgTextState(pos)
294+ }
295+
296+ override fun onDismiss () {
297+ btn_layout.visibility = View .VISIBLE
298+ }
299+ })
300+ }
301+
302+ private fun switchOrientation (orientation : Boolean ) {
303+ var marginWidth = 0
304+ val layoutParams = layout_video_preview.layoutParams as ConstraintLayout .LayoutParams
305+ var fitSize = 0
306+ var visibility = View .VISIBLE
307+ var moreSpace = 10
308+ if (orientation) {
309+ setRequestedOrientation(ActivityInfo .SCREEN_ORIENTATION_PORTRAIT )
310+ } else {
311+ setRequestedOrientation(ActivityInfo .SCREEN_ORIENTATION_LANDSCAPE )
312+ visibility = View .GONE
313+ fitSize = ConstraintLayout .LayoutParams .MATCH_PARENT
314+ marginWidth = 73
315+ moreSpace = 32
316+ }
317+
318+ v_title.visibility = visibility
319+ layout_content.visibility = visibility
320+
321+ layoutParams.height = fitSize
322+ layoutParams.width = fitSize
323+ layout_video_preview.layoutParams = layoutParams
324+
325+ val videoLayoutParams = v_preview.layoutParams as ConstraintLayout .LayoutParams
326+ videoLayoutParams.marginStart = dp2px(marginWidth)
327+ videoLayoutParams.marginEnd = dp2px(marginWidth)
328+ v_preview.layoutParams = videoLayoutParams
329+
330+ val btnLayoutParams = btn_layout.layoutParams as ConstraintLayout .LayoutParams
331+ btnLayoutParams.bottomMargin = dp2px(moreSpace)
332+ btn_layout.layoutParams = btnLayoutParams
333+ }
334+
335+ private fun chgTextState (value : Int ) {
336+ val url = when (value) {
337+ 0 -> {
338+ tv_video_quality.setText(R .string.video_quality_high_str)
339+ Command .getVideoSuperQualityUrlSuffix(channel)
340+ }
341+
342+ 1 -> {
343+ tv_video_quality.setText(R .string.video_quality_medium_str)
344+ Command .getVideoHightQualityUrlSuffix(channel)
345+ }
346+
347+ 2 -> {
348+ tv_video_quality.setText(R .string.video_quality_low_str)
349+ Command .getVideoStandardQualityUrlSuffix(channel)
350+ }
351+
352+ else -> " "
353+ }
354+ setPlayerUrl(url)
355+ chgAudioStatus(audioAble)
356+ }
357+
226358 open var controlListener = object : View .OnClickListener {
227359 override fun onClick (v : View ? ) {
228360 var command = " "
229361 when (v) {
230- iv_up -> command = Command .getPtzUpCommand(0 )
231- iv_down -> command = Command .getPtzDownCommand(0 )
232- iv_right -> command = Command .getPtzRightCommand(0 )
233- iv_left -> command = Command .getPtzLeftCommand(0 )
362+ iv_up -> command = Command .getPtzUpCommand(channel )
363+ iv_down -> command = Command .getPtzDownCommand(channel )
364+ iv_right -> command = Command .getPtzRightCommand(channel )
365+ iv_left -> command = Command .getPtzLeftCommand(channel )
234366 }
235367
236368 Thread (Runnable {
@@ -251,7 +383,7 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
251383
252384 open fun speakAble (able : Boolean ): Boolean {
253385 if (able) {
254- val command = Command .getNvrIpcStatus(0 , 0 )
386+ val command = Command .getNvrIpcStatus(channel , 0 )
255387 val repStatus = XP2P .postCommandRequestSync(
256388 " ${productId} /${deviceName} " ,
257389 command.toByteArray(), command.toByteArray().size.toLong(), 2 * 1000 * 1000
@@ -269,7 +401,7 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
269401 if (it.size == 1 && it.get(0 ).status == 0 ) {
270402 XP2P .runSendService(
271403 " ${productId} /${deviceName} " ,
272- Command .getTwoWayRadio(0 ),
404+ Command .getTwoWayRadio(channel ),
273405 true
274406 )
275407 audioRecordUtil?.start()
@@ -292,19 +424,19 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
292424 when (tv_video_quality.text.toString()) {
293425 getString(R .string.video_quality_high_str) -> setPlayerUrl(
294426 Command .getVideoSuperQualityUrlSuffix(
295- 0
427+ channel
296428 )
297429 )
298430
299431 getString(R .string.video_quality_medium_str) -> setPlayerUrl(
300432 Command .getVideoHightQualityUrlSuffix(
301- 0
433+ channel
302434 )
303435 )
304436
305437 getString(R .string.video_quality_low_str) -> setPlayerUrl(
306438 Command .getVideoStandardQualityUrlSuffix(
307- 0
439+ channel
308440 )
309441 )
310442 }
@@ -322,16 +454,16 @@ open class VideoTestActivity : VideoBaseActivity(), XP2PCallback, CoroutineScope
322454 val url = urlPrefix + suffix
323455 it.setOption(IjkMediaPlayer .OPT_CATEGORY_FORMAT , " probesize" , 50 * 1024 )
324456 it.setOption(IjkMediaPlayer .OPT_CATEGORY_PLAYER , " packet-buffering" , 0 )
457+ it.setOption(IjkMediaPlayer .OPT_CATEGORY_CODEC , " threads" , 2 )
458+ // it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 30*1024)
325459 it.setOption(IjkMediaPlayer .OPT_CATEGORY_PLAYER , " start-on-prepared" , 1 )
326- it.setOption(IjkMediaPlayer .OPT_CATEGORY_CODEC , " threads" , 1 )
327460 it.setOption(IjkMediaPlayer .OPT_CATEGORY_PLAYER , " sync-av-start" , 0 )
328461 it.setOption(IjkMediaPlayer .OPT_CATEGORY_PLAYER , " mediacodec" , 1 )
329462 it.setOption(IjkMediaPlayer .OPT_CATEGORY_PLAYER , " mediacodec-auto-rotate" , 1 )
330463 it.setOption(
331464 IjkMediaPlayer .OPT_CATEGORY_PLAYER , " mediacodec-handle-resolution-change" , 1
332465 )
333- // it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 50*1024)
334- it.setFrameSpeed(1.5f )
466+ it.setFrameSpeed(1.8f )
335467 while (! ::surface.isInitialized) {
336468 delay(50 )
337469 L .e(" delay for waiting surface." )
0 commit comments