@capgo/capacitor-screen-recorder 8.3.6 → 8.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +0 -3
- package/android/src/main/java/ee/forgr/plugin/screenrecorder/CapgoRecordingCoordinator.kt +23 -0
- package/android/src/main/java/ee/forgr/plugin/screenrecorder/CapgoScrCast.kt +47 -16
- package/android/src/main/java/ee/forgr/plugin/screenrecorder/MediaRecorderPrepare.kt +4 -1
- package/android/src/main/java/ee/forgr/plugin/screenrecorder/ScreenRecorderPlugin.java +38 -23
- package/android/src/main/java/ee/forgr/plugin/screenrecorder/service/CapgoRecorderService.kt +3 -1
- package/ios/Sources/ScreenRecorderPlugin/ScreenRecorderPlugin.swift +1 -1
- package/package.json +2 -2
package/android/build.gradle
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package ee.forgr.plugin.screenrecorder
|
|
2
|
+
|
|
3
|
+
internal object CapgoRecordingCoordinator {
|
|
4
|
+
private val lock = Any()
|
|
5
|
+
|
|
6
|
+
@Volatile
|
|
7
|
+
private var active = false
|
|
8
|
+
|
|
9
|
+
fun tryAcquire(): Boolean = synchronized(lock) {
|
|
10
|
+
if (active) {
|
|
11
|
+
false
|
|
12
|
+
} else {
|
|
13
|
+
active = true
|
|
14
|
+
true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fun release() {
|
|
19
|
+
synchronized(lock) {
|
|
20
|
+
active = false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -40,6 +40,7 @@ class CapgoScrCast private constructor(
|
|
|
40
40
|
private var serviceBinder: CapgoRecorderService? = null
|
|
41
41
|
private var outputFile: File? = null
|
|
42
42
|
private var startListener: StartListener? = null
|
|
43
|
+
private var receiverRegistered = false
|
|
43
44
|
|
|
44
45
|
private val metrics by lazy {
|
|
45
46
|
DisplayMetrics().apply { activity.windowManager.defaultDisplay.getMetrics(this) }
|
|
@@ -88,8 +89,7 @@ class CapgoScrCast private constructor(
|
|
|
88
89
|
if (report?.areAllPermissionsGranted() == true) {
|
|
89
90
|
startProjection.launch(Unit)
|
|
90
91
|
} else {
|
|
91
|
-
|
|
92
|
-
startListener = null
|
|
92
|
+
notifyStartFailed(SecurityException("Required permissions were not granted"))
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -103,12 +103,12 @@ class CapgoScrCast private constructor(
|
|
|
103
103
|
|
|
104
104
|
private val startProjection = activity.registerForActivityResult(CapgoRecordScreen()) { result ->
|
|
105
105
|
if (result.resultCode != Activity.RESULT_OK) {
|
|
106
|
-
|
|
106
|
+
notifyStartFailed(IllegalStateException("Screen capture permission denied"))
|
|
107
107
|
return@registerForActivityResult
|
|
108
108
|
}
|
|
109
109
|
val file = resolveOutputFile()
|
|
110
110
|
if (file == null) {
|
|
111
|
-
|
|
111
|
+
notifyStartFailed(IllegalStateException("Could not resolve screen recording output file"))
|
|
112
112
|
return@registerForActivityResult
|
|
113
113
|
}
|
|
114
114
|
startService(result, file)
|
|
@@ -126,7 +126,10 @@ class CapgoScrCast private constructor(
|
|
|
126
126
|
)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
fun record(listener: StartListener) {
|
|
129
|
+
fun record(listener: StartListener): Boolean {
|
|
130
|
+
if (!CapgoRecordingCoordinator.tryAcquire()) {
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
130
133
|
startListener = listener
|
|
131
134
|
val permissions = buildList {
|
|
132
135
|
add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
@@ -139,6 +142,13 @@ class CapgoScrCast private constructor(
|
|
|
139
142
|
.withPermissions(permissions)
|
|
140
143
|
.withListener(permissionListener)
|
|
141
144
|
.check()
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private fun notifyStartFailed(error: Throwable) {
|
|
149
|
+
startListener?.onFailed(error)
|
|
150
|
+
startListener = null
|
|
151
|
+
CapgoRecordingCoordinator.release()
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
fun stopRecording() {
|
|
@@ -167,25 +177,45 @@ class CapgoScrCast private constructor(
|
|
|
167
177
|
}
|
|
168
178
|
recordingSession = session
|
|
169
179
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
180
|
+
try {
|
|
181
|
+
broadcaster.registerReceiver(
|
|
182
|
+
recordingStateHandler,
|
|
183
|
+
IntentFilter().apply {
|
|
184
|
+
addAction(STATE_IDLE)
|
|
185
|
+
addAction(STATE_RECORDING)
|
|
186
|
+
},
|
|
187
|
+
)
|
|
188
|
+
receiverRegistered = true
|
|
189
|
+
activity.bindService(session, connection, Context.BIND_AUTO_CREATE)
|
|
190
|
+
activity.startService(session)
|
|
191
|
+
} catch (error: Exception) {
|
|
192
|
+
Log.e("CapgoScreenRecorder", "Failed to start screen recording service", error)
|
|
193
|
+
rollbackFailedStart(error)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
177
196
|
|
|
178
|
-
|
|
179
|
-
|
|
197
|
+
private fun rollbackFailedStart(error: Throwable) {
|
|
198
|
+
unregisterRecordingReceiver()
|
|
199
|
+
recordingSession = null
|
|
200
|
+
outputFile = null
|
|
201
|
+
notifyStartFailed(error)
|
|
180
202
|
}
|
|
181
203
|
|
|
182
|
-
private fun
|
|
183
|
-
|
|
204
|
+
private fun unregisterRecordingReceiver() {
|
|
205
|
+
if (!receiverRegistered) {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
184
208
|
try {
|
|
185
209
|
broadcaster.unregisterReceiver(recordingStateHandler)
|
|
186
210
|
} catch (ignored: Exception) {
|
|
187
211
|
Log.d("CapgoScreenRecorder", "Receiver already unregistered", ignored)
|
|
188
212
|
}
|
|
213
|
+
receiverRegistered = false
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private fun cleanupSession() {
|
|
217
|
+
startListener = null
|
|
218
|
+
unregisterRecordingReceiver()
|
|
189
219
|
|
|
190
220
|
try {
|
|
191
221
|
activity.unbindService(connection)
|
|
@@ -202,6 +232,7 @@ class CapgoScrCast private constructor(
|
|
|
202
232
|
}
|
|
203
233
|
}
|
|
204
234
|
outputFile = null
|
|
235
|
+
CapgoRecordingCoordinator.release()
|
|
205
236
|
}
|
|
206
237
|
|
|
207
238
|
interface StartListener {
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
package ee.forgr.plugin.screenrecorder
|
|
2
2
|
|
|
3
3
|
import android.media.MediaRecorder
|
|
4
|
+
import java.io.IOException
|
|
4
5
|
|
|
5
6
|
internal object MediaRecorderPrepare {
|
|
6
7
|
fun tryPrepare(recorder: MediaRecorder?): Throwable? {
|
|
7
8
|
return try {
|
|
8
9
|
recorder?.prepare()
|
|
9
10
|
null
|
|
10
|
-
} catch (error:
|
|
11
|
+
} catch (error: IOException) {
|
|
12
|
+
error
|
|
13
|
+
} catch (error: RuntimeException) {
|
|
11
14
|
error
|
|
12
15
|
}
|
|
13
16
|
}
|
|
@@ -10,7 +10,7 @@ import dev.bmcreations.scrcast.config.Options;
|
|
|
10
10
|
@CapacitorPlugin(name = "ScreenRecorder")
|
|
11
11
|
public class ScreenRecorderPlugin extends Plugin {
|
|
12
12
|
|
|
13
|
-
private final String pluginVersion = "8.3.
|
|
13
|
+
private final String pluginVersion = "8.3.8";
|
|
14
14
|
|
|
15
15
|
private CapgoScrCast videoRecorder;
|
|
16
16
|
private CapgoScrCast audioRecorder;
|
|
@@ -27,33 +27,48 @@ public class ScreenRecorderPlugin extends Plugin {
|
|
|
27
27
|
|
|
28
28
|
@PluginMethod
|
|
29
29
|
public void start(final PluginCall call) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
boolean keptAlive = false;
|
|
31
|
+
try {
|
|
32
|
+
final boolean recordAudio = call.getBoolean("recordAudio", false);
|
|
33
|
+
final String format = call.getString("format");
|
|
34
|
+
recordingWithAudio = recordAudio;
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
final CapgoScrCast recorder = recordAudio ? audioRecorder : videoRecorder;
|
|
37
|
+
final Options configuredOptions = VideoFormatResolver.INSTANCE.applyTo(recorder.getOptions(), format);
|
|
38
|
+
recorder.updateOptions(configuredOptions);
|
|
39
|
+
recorder.updateVideoFormat(format);
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
call.setKeepAlive(true);
|
|
42
|
+
keptAlive = true;
|
|
43
|
+
final boolean started = recorder.record(
|
|
44
|
+
new CapgoScrCast.StartListener() {
|
|
45
|
+
@Override
|
|
46
|
+
public void onStarted() {
|
|
47
|
+
call.resolve();
|
|
48
|
+
call.release(bridge);
|
|
49
|
+
}
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
@Override
|
|
52
|
+
public void onFailed(final Throwable error) {
|
|
53
|
+
recordingWithAudio = false;
|
|
54
|
+
final Exception exception = error instanceof Exception ? (Exception) error : new Exception(error);
|
|
55
|
+
call.reject("Could not start screen recording", exception);
|
|
56
|
+
call.release(bridge);
|
|
57
|
+
}
|
|
54
58
|
}
|
|
59
|
+
);
|
|
60
|
+
if (!started) {
|
|
61
|
+
recordingWithAudio = false;
|
|
62
|
+
call.reject("Could not start screen recording", new IllegalStateException("A screen recording is already in progress"));
|
|
63
|
+
call.release(bridge);
|
|
64
|
+
}
|
|
65
|
+
} catch (final Exception e) {
|
|
66
|
+
recordingWithAudio = false;
|
|
67
|
+
call.reject("Could not start screen recording", e);
|
|
68
|
+
if (keptAlive) {
|
|
69
|
+
call.release(bridge);
|
|
55
70
|
}
|
|
56
|
-
|
|
71
|
+
}
|
|
57
72
|
}
|
|
58
73
|
|
|
59
74
|
@PluginMethod
|
package/android/src/main/java/ee/forgr/plugin/screenrecorder/service/CapgoRecorderService.kt
CHANGED
|
@@ -128,10 +128,12 @@ class CapgoRecorderService : Service() {
|
|
|
128
128
|
mediaRecorder = createMediaRecorder().apply {
|
|
129
129
|
if (recordAudio) {
|
|
130
130
|
setAudioSource(AudioSource.MIC)
|
|
131
|
-
setAudioEncoder(AudioEncoder.AAC)
|
|
132
131
|
}
|
|
133
132
|
setVideoSource(VideoSource.SURFACE)
|
|
134
133
|
setOutputFormat(options.storage.outputFormat)
|
|
134
|
+
if (recordAudio) {
|
|
135
|
+
setAudioEncoder(AudioEncoder.AAC)
|
|
136
|
+
}
|
|
135
137
|
setOutputFile(outputFile)
|
|
136
138
|
with(options.video) {
|
|
137
139
|
setVideoSize(width, height)
|
|
@@ -7,7 +7,7 @@ import Capacitor
|
|
|
7
7
|
*/
|
|
8
8
|
@objc(ScreenRecorderPlugin)
|
|
9
9
|
public class ScreenRecorderPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
10
|
-
private let pluginVersion: String = "8.3.
|
|
10
|
+
private let pluginVersion: String = "8.3.8"
|
|
11
11
|
public let identifier = "ScreenRecorderPlugin"
|
|
12
12
|
public let jsName = "ScreenRecorder"
|
|
13
13
|
public let pluginMethods: [CAPPluginMethod] = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-screen-recorder",
|
|
3
|
-
"version": "8.3.
|
|
3
|
+
"version": "8.3.8",
|
|
4
4
|
"description": "Record device's screen",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@ionic/eslint-config": "^0.4.0",
|
|
67
67
|
"@ionic/prettier-config": "^4.0.0",
|
|
68
68
|
"@ionic/swiftlint-config": "^2.0.0",
|
|
69
|
-
"@types/node": "^
|
|
69
|
+
"@types/node": "^26.0.0",
|
|
70
70
|
"eslint": "^8.57.1",
|
|
71
71
|
"eslint-plugin-import": "^2.31.0",
|
|
72
72
|
"prettier": "^3.6.2",
|