@capgo/capacitor-screen-recorder 8.3.6 → 8.3.7

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.
@@ -45,9 +45,6 @@ android {
45
45
  sourceCompatibility JavaVersion.VERSION_21
46
46
  targetCompatibility JavaVersion.VERSION_21
47
47
  }
48
- testOptions {
49
- unitTests.returnDefaultValues = true
50
- }
51
48
  }
52
49
 
53
50
  kotlin {
@@ -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
- startListener?.onFailed(SecurityException("Required permissions were not granted"))
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
- startListener?.onFailed(IllegalStateException("Screen capture permission denied"))
106
+ notifyStartFailed(IllegalStateException("Screen capture permission denied"))
107
107
  return@registerForActivityResult
108
108
  }
109
109
  val file = resolveOutputFile()
110
110
  if (file == null) {
111
- startListener?.onFailed(IllegalStateException("Could not resolve screen recording output file"))
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
- broadcaster.registerReceiver(
171
- recordingStateHandler,
172
- IntentFilter().apply {
173
- addAction(STATE_IDLE)
174
- addAction(STATE_RECORDING)
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
- activity.bindService(session, connection, Context.BIND_AUTO_CREATE)
179
- activity.startService(session)
197
+ private fun rollbackFailedStart(error: Throwable) {
198
+ unregisterRecordingReceiver()
199
+ recordingSession = null
200
+ outputFile = null
201
+ notifyStartFailed(error)
180
202
  }
181
203
 
182
- private fun cleanupSession() {
183
- startListener = null
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: Throwable) {
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.6";
13
+ private final String pluginVersion = "8.3.7";
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
- final boolean recordAudio = call.getBoolean("recordAudio", false);
31
- final String format = call.getString("format");
32
- recordingWithAudio = recordAudio;
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
- final CapgoScrCast recorder = recordAudio ? audioRecorder : videoRecorder;
35
- final Options configuredOptions = VideoFormatResolver.INSTANCE.applyTo(recorder.getOptions(), format);
36
- recorder.updateOptions(configuredOptions);
37
- recorder.updateVideoFormat(format);
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
- call.setKeepAlive(true);
40
- recorder.record(
41
- new CapgoScrCast.StartListener() {
42
- @Override
43
- public void onStarted() {
44
- call.resolve();
45
- call.release(bridge);
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
- @Override
49
- public void onFailed(final Throwable error) {
50
- recordingWithAudio = false;
51
- final Exception exception = error instanceof Exception ? (Exception) error : new Exception(error);
52
- call.reject("Could not start screen recording", exception);
53
- call.release(bridge);
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
@@ -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.6"
10
+ private let pluginVersion: String = "8.3.7"
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.6",
3
+ "version": "8.3.7",
4
4
  "description": "Record device's screen",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",