-
-
Notifications
You must be signed in to change notification settings - Fork 938
Expand file tree
/
Copy pathScreenActivity.kt
More file actions
237 lines (218 loc) · 7.69 KB
/
Copy pathScreenActivity.kt
File metadata and controls
237 lines (218 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/*
* Copyright (C) 2024 pedroSG94.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.pedro.streamer.screen
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import android.widget.EditText
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import com.pedro.common.ConnectChecker
import com.pedro.encoder.input.sources.audio.InternalAudioSource
import com.pedro.encoder.input.sources.audio.MicrophoneSource
import com.pedro.encoder.input.sources.audio.MixAudioSource
import com.pedro.library.base.recording.RecordController
import com.pedro.streamer.R
import com.pedro.streamer.utils.fitAppPadding
import com.pedro.streamer.utils.toast
import com.pedro.streamer.utils.updateMenuColor
/**
* Example code to stream the device screen.
* Necessary API 21+
*
* More documentation see:
* [com.pedro.library.base.DisplayBase]
* Support RTMP, RTSP and SRT with commons features
* [com.pedro.library.generic.GenericDisplay]
* Support RTSP with all RTSP features
* [com.pedro.library.rtsp.RtspDisplay]
* Support RTMP with all RTMP features
* [com.pedro.library.rtmp.RtmpDisplay]
* Support SRT with all SRT features
* [com.pedro.library.srt.SrtDisplay]
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
class ScreenActivity : AppCompatActivity(), ConnectChecker {
enum class Action {
STREAM, RECORD, NONE, CHANGE
}
private lateinit var button: ImageView
private lateinit var bRecord: ImageView
private lateinit var etUrl: EditText
private var currentAudioSource: MenuItem? = null
private var action = Action.NONE
private val activityResultContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val data = result.data
if (data != null && result.resultCode == RESULT_OK) {
val screenService = ScreenService.INSTANCE
if (screenService != null) {
if (action == Action.CHANGE) {
screenService.screenS(result.resultCode, data)
}else if (screenService.prepareStream(result.resultCode, data)) {
when (action) {
Action.STREAM -> startStream()
Action.RECORD -> toggleRecord()
else -> {}
}
} else {
toast("Prepare stream failed")
}
}
} else {
toast("No permissions available")
button.setImageResource(R.drawable.stream_icon)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContentView(R.layout.activity_display)
fitAppPadding()
button = findViewById(R.id.b_start_stop)
etUrl = findViewById(R.id.et_rtp_url)
bRecord = findViewById(R.id.b_record)
val screenService = ScreenService.INSTANCE
//No streaming/recording start service
if (screenService == null) {
startService(Intent(this, ScreenService::class.java))
}
if (screenService != null && screenService.isStreaming()) {
button.setImageResource(R.drawable.stream_stop_icon)
} else {
button.setImageResource(R.drawable.stream_icon)
}
if (screenService != null && screenService.isRecording()) {
bRecord.setImageResource(R.drawable.stop_icon)
} else {
bRecord.setImageResource(R.drawable.record_icon)
}
button.setOnClickListener {
val service = ScreenService.INSTANCE
if (service != null) {
service.setCallback(this)
if (!service.isStreaming() && !service.isRecording()) {
action = Action.STREAM
activityResultContract.launch(service.sendIntent())
} else if (!service.isStreaming()) {
startStream()
} else {
stopStream()
}
}
}
bRecord.setOnClickListener {
val service = ScreenService.INSTANCE
if (service != null) {
service.setCallback(this)
if (!service.isStreaming() && !service.isRecording()) {
action = Action.RECORD
activityResultContract.launch(service.sendIntent())
} else toggleRecord()
}
}
}
private fun startStream() {
button.setImageResource(R.drawable.stream_stop_icon)
val endpoint = etUrl.text.toString()
ScreenService.INSTANCE?.startStream(endpoint)
}
private fun stopStream() {
button.setImageResource(R.drawable.stream_icon)
ScreenService.INSTANCE?.stopStream()
}
private fun toggleRecord() {
ScreenService.INSTANCE?.toggleRecord { state ->
when (state) {
RecordController.Status.STARTED -> {
bRecord.setImageResource(R.drawable.pause_icon)
}
RecordController.Status.STOPPED -> {
bRecord.setImageResource(R.drawable.record_icon)
}
RecordController.Status.RECORDING -> {
bRecord.setImageResource(R.drawable.stop_icon)
}
else -> {}
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.screen_menu, menu)
val defaultAudioSource = when (ScreenService.INSTANCE?.getCurrentAudioSource()) {
is MicrophoneSource -> menu.findItem(R.id.audio_source_microphone)
is InternalAudioSource -> menu.findItem(R.id.audio_source_internal)
is MixAudioSource -> menu.findItem(R.id.audio_source_mix)
else -> menu.findItem(R.id.audio_source_microphone)
}
currentAudioSource = defaultAudioSource.updateMenuColor(this, currentAudioSource)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
try {
when (item.itemId) {
R.id.audio_source_microphone, R.id.audio_source_internal, R.id.audio_source_mix -> {
val service = ScreenService.INSTANCE
if (service != null) {
if (item.itemId == R.id.audio_source_internal) {
action = Action.CHANGE
activityResultContract.launch(service.sendIntent())
} else {
service.toggleAudioSource(item.itemId)
}
currentAudioSource = item.updateMenuColor(this, currentAudioSource)
}
}
}
} catch (e: IllegalArgumentException) {
toast("Change source error: ${e.message}")
}
return super.onOptionsItemSelected(item)
}
override fun onDestroy() {
super.onDestroy()
val screenService = ScreenService.INSTANCE
if (screenService != null && !screenService.isStreaming() && !screenService.isRecording()) {
screenService.setCallback(null)
activityResultContract.unregister()
//stop service only if no streaming or recording
if (isFinishing) stopService(Intent(this, ScreenService::class.java))
}
}
override fun onConnectionStarted(url: String) {}
override fun onConnectionSuccess() {
toast("Connected")
}
override fun onConnectionFailed(reason: String) {
stopStream()
toast("Failed: $reason")
}
override fun onNewBitrate(bitrate: Long) {}
override fun onDisconnect() {
toast("Disconnected")
}
override fun onAuthError() {
stopStream()
toast("Auth error")
}
override fun onAuthSuccess() {
toast("Auth success")
}
}