react-native-unified-player 0.3.7 → 0.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/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/unifiedplayer/UnifiedPlayerModule.kt +69 -0
- package/android/src/main/java/com/unifiedplayer/UnifiedPlayerView.kt +235 -0
- package/ios/UnifiedPlayerModule.m +94 -0
- package/ios/UnifiedPlayerUIView.h +13 -0
- package/ios/UnifiedPlayerViewManager.m +234 -0
- package/lib/module/index.js +41 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +13 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +59 -0
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
package="com.unifiedplayer">
|
|
3
3
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
4
4
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
5
|
+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
|
|
6
|
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
|
|
7
|
+
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
|
5
8
|
<application android:hardwareAccelerated="true">
|
|
6
9
|
</application>
|
|
7
10
|
</manifest>
|
|
@@ -8,6 +8,8 @@ import com.facebook.react.uimanager.UIManagerModule
|
|
|
8
8
|
import android.util.Log
|
|
9
9
|
import com.facebook.react.bridge.UiThreadUtil
|
|
10
10
|
import android.view.View
|
|
11
|
+
import android.os.Environment
|
|
12
|
+
import java.io.File
|
|
11
13
|
|
|
12
14
|
class UnifiedPlayerModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
13
15
|
companion object {
|
|
@@ -195,4 +197,71 @@ class UnifiedPlayerModule(private val reactContext: ReactApplicationContext) : R
|
|
|
195
197
|
promise.reject("CAPTURE_ERROR", "Error in capture method: ${e.message}", e)
|
|
196
198
|
}
|
|
197
199
|
}
|
|
200
|
+
|
|
201
|
+
@ReactMethod
|
|
202
|
+
fun startRecording(viewTag: Int, outputPath: String?, promise: Promise) {
|
|
203
|
+
Log.d(TAG, "Native startRecording method called with viewTag: $viewTag, outputPath: $outputPath")
|
|
204
|
+
try {
|
|
205
|
+
val playerView = getPlayerViewByTag(viewTag)
|
|
206
|
+
if (playerView != null) {
|
|
207
|
+
UiThreadUtil.runOnUiThread {
|
|
208
|
+
try {
|
|
209
|
+
// Determine the output path
|
|
210
|
+
val finalOutputPath = if (outputPath.isNullOrEmpty()) {
|
|
211
|
+
// Use app-specific storage for Android 10+ (API level 29+)
|
|
212
|
+
val moviesDir = File(reactApplicationContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "recordings")
|
|
213
|
+
if (!moviesDir.exists()) {
|
|
214
|
+
moviesDir.mkdirs()
|
|
215
|
+
}
|
|
216
|
+
val timestamp = System.currentTimeMillis()
|
|
217
|
+
File(moviesDir, "recording_$timestamp.mp4").absolutePath
|
|
218
|
+
} else {
|
|
219
|
+
outputPath
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Start recording
|
|
223
|
+
val result = playerView.startRecording(finalOutputPath)
|
|
224
|
+
Log.d(TAG, "Start recording command executed successfully, result: $result")
|
|
225
|
+
promise.resolve(result)
|
|
226
|
+
} catch (e: Exception) {
|
|
227
|
+
Log.e(TAG, "Error during startRecording: ${e.message}", e)
|
|
228
|
+
promise.reject("RECORDING_ERROR", "Error during startRecording: ${e.message}", e)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
Log.e(TAG, "Player view not found for tag: $viewTag")
|
|
233
|
+
promise.reject("VIEW_NOT_FOUND", "Player view not found for tag: $viewTag")
|
|
234
|
+
}
|
|
235
|
+
} catch (e: Exception) {
|
|
236
|
+
Log.e(TAG, "Error in startRecording method: ${e.message}", e)
|
|
237
|
+
promise.reject("RECORDING_ERROR", "Error in startRecording method: ${e.message}", e)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@ReactMethod
|
|
242
|
+
fun stopRecording(viewTag: Int, promise: Promise) {
|
|
243
|
+
Log.d(TAG, "Native stopRecording method called with viewTag: $viewTag")
|
|
244
|
+
try {
|
|
245
|
+
val playerView = getPlayerViewByTag(viewTag)
|
|
246
|
+
if (playerView != null) {
|
|
247
|
+
UiThreadUtil.runOnUiThread {
|
|
248
|
+
try {
|
|
249
|
+
// Stop recording
|
|
250
|
+
val filePath = playerView.stopRecording()
|
|
251
|
+
Log.d(TAG, "Stop recording command executed successfully, filePath: $filePath")
|
|
252
|
+
promise.resolve(filePath)
|
|
253
|
+
} catch (e: Exception) {
|
|
254
|
+
Log.e(TAG, "Error during stopRecording: ${e.message}", e)
|
|
255
|
+
promise.reject("RECORDING_ERROR", "Error during stopRecording: ${e.message}", e)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
Log.e(TAG, "Player view not found for tag: $viewTag")
|
|
260
|
+
promise.reject("VIEW_NOT_FOUND", "Player view not found for tag: $viewTag")
|
|
261
|
+
}
|
|
262
|
+
} catch (e: Exception) {
|
|
263
|
+
Log.e(TAG, "Error in stopRecording method: ${e.message}", e)
|
|
264
|
+
promise.reject("RECORDING_ERROR", "Error in stopRecording method: ${e.message}", e)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
198
267
|
}
|
|
@@ -25,6 +25,15 @@ import com.google.android.exoplayer2.video.VideoSize
|
|
|
25
25
|
import com.facebook.react.bridge.WritableMap
|
|
26
26
|
import com.facebook.react.bridge.ReactContext
|
|
27
27
|
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
28
|
+
import java.io.File
|
|
29
|
+
import java.io.IOException
|
|
30
|
+
import android.media.MediaCodec
|
|
31
|
+
import android.media.MediaCodecInfo
|
|
32
|
+
import android.media.MediaFormat
|
|
33
|
+
import android.media.MediaMuxer
|
|
34
|
+
import android.view.Surface
|
|
35
|
+
import java.nio.ByteBuffer
|
|
36
|
+
import android.os.Environment
|
|
28
37
|
import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_COMPLETE
|
|
29
38
|
import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_ERROR
|
|
30
39
|
import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_LOAD_START
|
|
@@ -36,6 +45,15 @@ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_RESUMED
|
|
|
36
45
|
import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_STALLED
|
|
37
46
|
|
|
38
47
|
class UnifiedPlayerView(context: Context) : FrameLayout(context) {
|
|
48
|
+
// Recording related variables
|
|
49
|
+
private var mediaRecorder: MediaMuxer? = null
|
|
50
|
+
private var videoEncoder: MediaCodec? = null
|
|
51
|
+
private var recordingSurface: Surface? = null
|
|
52
|
+
private var isRecording = false
|
|
53
|
+
private var outputPath: String? = null
|
|
54
|
+
private var recordingThread: Thread? = null
|
|
55
|
+
private var videoTrackIndex = -1
|
|
56
|
+
private val bufferInfo = MediaCodec.BufferInfo()
|
|
39
57
|
companion object {
|
|
40
58
|
private const val TAG = "UnifiedPlayerView"
|
|
41
59
|
}
|
|
@@ -457,4 +475,221 @@ bitmap.let {
|
|
|
457
475
|
""
|
|
458
476
|
}
|
|
459
477
|
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Start recording the video to the specified output path
|
|
481
|
+
* @param outputPath Path where to save the recording
|
|
482
|
+
* @return true if recording started successfully
|
|
483
|
+
*/
|
|
484
|
+
fun startRecording(outputPath: String): Boolean {
|
|
485
|
+
Log.d(TAG, "startRecording called with outputPath: $outputPath")
|
|
486
|
+
|
|
487
|
+
if (isRecording) {
|
|
488
|
+
Log.w(TAG, "Recording is already in progress")
|
|
489
|
+
return false
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
player?.let { exoPlayer ->
|
|
494
|
+
// Get the current media item's URI
|
|
495
|
+
val currentUri = exoPlayer.currentMediaItem?.localConfiguration?.uri?.toString()
|
|
496
|
+
if (currentUri == null) {
|
|
497
|
+
Log.e(TAG, "Current media URI is null")
|
|
498
|
+
return false
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
Log.d(TAG, "Current media URI: $currentUri")
|
|
502
|
+
|
|
503
|
+
// Store the output path
|
|
504
|
+
this.outputPath = if (outputPath.isNullOrEmpty()) {
|
|
505
|
+
// Use app-specific storage for Android 10+ (API level 29+)
|
|
506
|
+
val appContext = context.applicationContext
|
|
507
|
+
val moviesDir = File(appContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "recordings")
|
|
508
|
+
if (!moviesDir.exists()) {
|
|
509
|
+
moviesDir.mkdirs()
|
|
510
|
+
}
|
|
511
|
+
File(moviesDir, "recording_${System.currentTimeMillis()}.mp4").absolutePath
|
|
512
|
+
} else {
|
|
513
|
+
outputPath
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Create parent directories if they don't exist
|
|
517
|
+
val outputFile = File(this.outputPath)
|
|
518
|
+
outputFile.parentFile?.mkdirs()
|
|
519
|
+
|
|
520
|
+
// Log the final output path
|
|
521
|
+
Log.d(TAG, "Recording will be saved to: ${this.outputPath}")
|
|
522
|
+
|
|
523
|
+
// Start a background thread to download the file
|
|
524
|
+
Thread {
|
|
525
|
+
try {
|
|
526
|
+
// Create a URL from the URI
|
|
527
|
+
val url = java.net.URL(currentUri)
|
|
528
|
+
|
|
529
|
+
// Open connection
|
|
530
|
+
val connection = url.openConnection() as java.net.HttpURLConnection
|
|
531
|
+
connection.requestMethod = "GET"
|
|
532
|
+
connection.connectTimeout = 15000
|
|
533
|
+
connection.readTimeout = 15000
|
|
534
|
+
connection.doInput = true
|
|
535
|
+
connection.connect()
|
|
536
|
+
|
|
537
|
+
// Check if the connection was successful
|
|
538
|
+
if (connection.responseCode != java.net.HttpURLConnection.HTTP_OK) {
|
|
539
|
+
Log.e(TAG, "HTTP error code: ${connection.responseCode}")
|
|
540
|
+
return@Thread
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Get the input stream
|
|
544
|
+
val inputStream = connection.inputStream
|
|
545
|
+
|
|
546
|
+
// Create the output file
|
|
547
|
+
val outputFile = File(this.outputPath!!)
|
|
548
|
+
|
|
549
|
+
// Create the output stream
|
|
550
|
+
val outputStream = outputFile.outputStream()
|
|
551
|
+
|
|
552
|
+
// Create a buffer
|
|
553
|
+
val buffer = ByteArray(1024)
|
|
554
|
+
var bytesRead: Int
|
|
555
|
+
var totalBytesRead: Long = 0
|
|
556
|
+
val fileSize = connection.contentLength.toLong()
|
|
557
|
+
|
|
558
|
+
// Read from the input stream and write to the output stream
|
|
559
|
+
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
|
560
|
+
outputStream.write(buffer, 0, bytesRead)
|
|
561
|
+
totalBytesRead += bytesRead
|
|
562
|
+
|
|
563
|
+
// Log progress
|
|
564
|
+
if (fileSize > 0) {
|
|
565
|
+
val progress = (totalBytesRead * 100 / fileSize).toInt()
|
|
566
|
+
Log.d(TAG, "Download progress: $progress%")
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Close the streams
|
|
571
|
+
outputStream.flush()
|
|
572
|
+
outputStream.close()
|
|
573
|
+
inputStream.close()
|
|
574
|
+
|
|
575
|
+
Log.d(TAG, "File downloaded successfully to ${this.outputPath}")
|
|
576
|
+
} catch (e: Exception) {
|
|
577
|
+
Log.e(TAG, "Error downloading file: ${e.message}", e)
|
|
578
|
+
}
|
|
579
|
+
}.start()
|
|
580
|
+
|
|
581
|
+
isRecording = true
|
|
582
|
+
Log.d(TAG, "Recording started successfully")
|
|
583
|
+
return true
|
|
584
|
+
} ?: run {
|
|
585
|
+
Log.e(TAG, "Cannot start recording: player is null")
|
|
586
|
+
return false
|
|
587
|
+
}
|
|
588
|
+
} catch (e: Exception) {
|
|
589
|
+
Log.e(TAG, "Error starting recording: ${e.message}", e)
|
|
590
|
+
return false
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Stop recording and save the video
|
|
596
|
+
* @return Path to the saved recording
|
|
597
|
+
*/
|
|
598
|
+
fun stopRecording(): String {
|
|
599
|
+
Log.d(TAG, "stopRecording called")
|
|
600
|
+
|
|
601
|
+
if (!isRecording) {
|
|
602
|
+
Log.w(TAG, "No recording in progress")
|
|
603
|
+
return ""
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Simply mark recording as stopped
|
|
607
|
+
isRecording = false
|
|
608
|
+
|
|
609
|
+
// Wait a moment to ensure any background operations complete
|
|
610
|
+
try {
|
|
611
|
+
Thread.sleep(500)
|
|
612
|
+
} catch (e: InterruptedException) {
|
|
613
|
+
Log.e(TAG, "Sleep interrupted: ${e.message}")
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Return the path where the recording was saved
|
|
617
|
+
val savedPath = outputPath ?: ""
|
|
618
|
+
Log.d(TAG, "Recording stopped successfully, saved to: $savedPath")
|
|
619
|
+
|
|
620
|
+
return savedPath
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
private fun cleanupRecording() {
|
|
624
|
+
try {
|
|
625
|
+
videoEncoder?.stop()
|
|
626
|
+
videoEncoder?.release()
|
|
627
|
+
videoEncoder = null
|
|
628
|
+
|
|
629
|
+
recordingSurface?.release()
|
|
630
|
+
recordingSurface = null
|
|
631
|
+
|
|
632
|
+
mediaRecorder?.stop()
|
|
633
|
+
mediaRecorder?.release()
|
|
634
|
+
mediaRecorder = null
|
|
635
|
+
|
|
636
|
+
videoTrackIndex = -1
|
|
637
|
+
isRecording = false
|
|
638
|
+
} catch (e: Exception) {
|
|
639
|
+
Log.e(TAG, "Error cleaning up recording resources: ${e.message}", e)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private inner class RecordingRunnable : Runnable {
|
|
644
|
+
override fun run() {
|
|
645
|
+
try {
|
|
646
|
+
// Add video track to muxer
|
|
647
|
+
val videoFormat = videoEncoder?.outputFormat
|
|
648
|
+
if (videoFormat != null && mediaRecorder != null) {
|
|
649
|
+
videoTrackIndex = mediaRecorder!!.addTrack(videoFormat)
|
|
650
|
+
} else {
|
|
651
|
+
Log.e(TAG, "Cannot add track: videoFormat or mediaRecorder is null")
|
|
652
|
+
videoTrackIndex = -1
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Start the muxer
|
|
656
|
+
mediaRecorder?.start()
|
|
657
|
+
|
|
658
|
+
// Process encoding
|
|
659
|
+
while (isRecording) {
|
|
660
|
+
val encoderStatus = videoEncoder?.dequeueOutputBuffer(bufferInfo, 10000) ?: -1
|
|
661
|
+
|
|
662
|
+
if (encoderStatus >= 0) {
|
|
663
|
+
val encodedData = videoEncoder?.getOutputBuffer(encoderStatus)
|
|
664
|
+
|
|
665
|
+
if ((bufferInfo.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
|
|
666
|
+
// Ignore codec config data
|
|
667
|
+
bufferInfo.size = 0
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if (bufferInfo.size > 0 && encodedData != null && mediaRecorder != null && videoTrackIndex >= 0) {
|
|
671
|
+
encodedData.position(bufferInfo.offset)
|
|
672
|
+
encodedData.limit(bufferInfo.offset + bufferInfo.size)
|
|
673
|
+
|
|
674
|
+
mediaRecorder!!.writeSampleData(videoTrackIndex, encodedData, bufferInfo)
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
videoEncoder?.releaseOutputBuffer(encoderStatus, false)
|
|
678
|
+
|
|
679
|
+
if ((bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
|
680
|
+
break
|
|
681
|
+
}
|
|
682
|
+
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
|
683
|
+
// Handle format change if needed
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Signal end of stream to encoder
|
|
688
|
+
videoEncoder?.signalEndOfInputStream()
|
|
689
|
+
|
|
690
|
+
} catch (e: Exception) {
|
|
691
|
+
Log.e(TAG, "Error in recording thread: ${e.message}", e)
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
460
695
|
}
|
|
@@ -216,4 +216,98 @@ RCT_EXPORT_METHOD(capture:(nonnull NSNumber *)reactTag
|
|
|
216
216
|
}];
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
RCT_EXPORT_METHOD(startRecording:(nonnull NSNumber *)reactTag
|
|
220
|
+
outputPath:(NSString *)outputPath
|
|
221
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
222
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
223
|
+
{
|
|
224
|
+
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
225
|
+
UIView *view = viewRegistry[reactTag];
|
|
226
|
+
if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
|
|
227
|
+
RCTLogError(@"Invalid view returned from registry, expecting UnifiedPlayerUIView, got: %@", view);
|
|
228
|
+
reject(@"E_INVALID_VIEW", @"Expected UnifiedPlayerUIView", nil);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
UnifiedPlayerUIView *playerView = (UnifiedPlayerUIView *)view;
|
|
233
|
+
|
|
234
|
+
// If no output path is provided, create a default one in the Documents directory
|
|
235
|
+
NSString *finalOutputPath = outputPath;
|
|
236
|
+
if (!finalOutputPath || [finalOutputPath isEqualToString:@""]) {
|
|
237
|
+
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
|
|
238
|
+
NSString *timestamp = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]];
|
|
239
|
+
finalOutputPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"recording_%@.mp4", timestamp]];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
BOOL success = [playerView startRecordingToPath:finalOutputPath];
|
|
243
|
+
if (success) {
|
|
244
|
+
resolve(@YES);
|
|
245
|
+
} else {
|
|
246
|
+
reject(@"E_RECORDING_FAILED", @"Failed to start recording", nil);
|
|
247
|
+
}
|
|
248
|
+
}];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
RCT_EXPORT_METHOD(stopRecording:(nonnull NSNumber *)reactTag
|
|
252
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
253
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
254
|
+
{
|
|
255
|
+
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
256
|
+
UIView *view = viewRegistry[reactTag];
|
|
257
|
+
if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
|
|
258
|
+
RCTLogError(@"Invalid view returned from registry, expecting UnifiedPlayerUIView, got: %@", view);
|
|
259
|
+
reject(@"E_INVALID_VIEW", @"Expected UnifiedPlayerUIView", nil);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
UnifiedPlayerUIView *playerView = (UnifiedPlayerUIView *)view;
|
|
264
|
+
NSString *filePath = [playerView stopRecording];
|
|
265
|
+
|
|
266
|
+
if (filePath && ![filePath isEqualToString:@""]) {
|
|
267
|
+
resolve(filePath);
|
|
268
|
+
} else {
|
|
269
|
+
reject(@"E_RECORDING_FAILED", @"Failed to stop recording or no recording in progress", nil);
|
|
270
|
+
}
|
|
271
|
+
}];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
RCT_EXPORT_METHOD(saveVideo:(nonnull NSNumber *)reactTag
|
|
275
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
276
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
277
|
+
{
|
|
278
|
+
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
279
|
+
UIView *view = viewRegistry[reactTag];
|
|
280
|
+
if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
|
|
281
|
+
RCTLogError(@"Invalid view returned from registry, expecting UnifiedPlayerUIView, got: %@", view);
|
|
282
|
+
reject(@"E_INVALID_VIEW", @"Expected UnifiedPlayerUIView", nil);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
UnifiedPlayerUIView *playerView = (UnifiedPlayerUIView *)view;
|
|
287
|
+
|
|
288
|
+
// Create a file path in the Documents directory
|
|
289
|
+
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
|
|
290
|
+
NSString *timestamp = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]];
|
|
291
|
+
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"saved_video_%@.mp4", timestamp]];
|
|
292
|
+
|
|
293
|
+
// Start recording
|
|
294
|
+
BOOL success = [playerView startRecordingToPath:filePath];
|
|
295
|
+
if (!success) {
|
|
296
|
+
reject(@"E_RECORDING_FAILED", @"Failed to start recording", nil);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Record for 5 seconds (or adjust as needed)
|
|
301
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
302
|
+
NSString *savedFilePath = [playerView stopRecording];
|
|
303
|
+
|
|
304
|
+
if (savedFilePath && ![savedFilePath isEqualToString:@""]) {
|
|
305
|
+
resolve(savedFilePath);
|
|
306
|
+
} else {
|
|
307
|
+
reject(@"E_RECORDING_FAILED", @"Failed to stop recording or no recording in progress", nil);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}];
|
|
311
|
+
}
|
|
312
|
+
|
|
219
313
|
@end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
#import <React/RCTView.h>
|
|
3
3
|
#import <React/RCTComponent.h>
|
|
4
4
|
#import <MobileVLCKit/MobileVLCKit.h>
|
|
5
|
+
#import <AVFoundation/AVFoundation.h>
|
|
6
|
+
#import <CoreVideo/CoreVideo.h>
|
|
5
7
|
|
|
6
8
|
NS_ASSUME_NONNULL_BEGIN
|
|
7
9
|
|
|
@@ -17,6 +19,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
17
19
|
@property (nonatomic, assign) VLCMediaPlayerState previousState;
|
|
18
20
|
@property (nonatomic, assign) BOOL hasRenderedVideo;
|
|
19
21
|
@property (nonatomic, assign) BOOL readyEventSent;
|
|
22
|
+
@property (nonatomic, assign) BOOL isRecording;
|
|
23
|
+
@property (nonatomic, strong) AVAssetWriter *assetWriter;
|
|
24
|
+
@property (nonatomic, strong) AVAssetWriterInput *assetWriterVideoInput;
|
|
25
|
+
@property (nonatomic, strong) AVAssetWriterInputPixelBufferAdaptor *assetWriterPixelBufferAdaptor;
|
|
26
|
+
@property (nonatomic, strong) NSString *recordingPath;
|
|
27
|
+
// We'll use associated objects instead of a property for CADisplayLink
|
|
28
|
+
@property (nonatomic, assign) NSInteger frameCount;
|
|
20
29
|
|
|
21
30
|
// Event callbacks
|
|
22
31
|
@property (nonatomic, copy) RCTDirectEventBlock onLoadStart;
|
|
@@ -37,6 +46,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
37
46
|
- (float)getCurrentTime;
|
|
38
47
|
- (float)getDuration;
|
|
39
48
|
- (void)captureFrameWithCompletion:(void (^)(NSString * _Nullable base64String, NSError * _Nullable error))completion;
|
|
49
|
+
- (void)captureFrameForRecording;
|
|
50
|
+
- (BOOL)startRecordingToPath:(NSString *)outputPath;
|
|
51
|
+
- (void)startFrameCapture;
|
|
52
|
+
- (NSString *)stopRecording;
|
|
40
53
|
|
|
41
54
|
@end
|
|
42
55
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#import <React/RCTUIManagerUtils.h>
|
|
8
8
|
#import <React/RCTComponent.h>
|
|
9
9
|
#import <MobileVLCKit/MobileVLCKit.h>
|
|
10
|
+
#import <objc/runtime.h>
|
|
10
11
|
#import "UnifiedPlayerModule.h"
|
|
11
12
|
#import "UnifiedPlayerUIView.h"
|
|
12
13
|
|
|
@@ -388,6 +389,227 @@
|
|
|
388
389
|
}
|
|
389
390
|
}
|
|
390
391
|
|
|
392
|
+
- (BOOL)startRecordingToPath:(NSString *)outputPath {
|
|
393
|
+
RCTLogInfo(@"[UnifiedPlayerViewManager] startRecordingToPath: %@", outputPath);
|
|
394
|
+
|
|
395
|
+
if (_isRecording) {
|
|
396
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Recording is already in progress");
|
|
397
|
+
return NO;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (!_player || !_player.isPlaying) {
|
|
401
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Cannot start recording: Player is not playing");
|
|
402
|
+
return NO;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Store the recording path
|
|
406
|
+
_recordingPath = [outputPath copy];
|
|
407
|
+
|
|
408
|
+
// Create directory if it doesn't exist
|
|
409
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
410
|
+
NSString *directory = [outputPath stringByDeletingLastPathComponent];
|
|
411
|
+
if (![fileManager fileExistsAtPath:directory]) {
|
|
412
|
+
NSError *error = nil;
|
|
413
|
+
[fileManager createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:&error];
|
|
414
|
+
if (error) {
|
|
415
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Failed to create directory: %@", error);
|
|
416
|
+
return NO;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Set up AVAssetWriter
|
|
421
|
+
NSURL *outputURL = [NSURL fileURLWithPath:outputPath];
|
|
422
|
+
|
|
423
|
+
// Remove existing file if it exists
|
|
424
|
+
if ([fileManager fileExistsAtPath:outputPath]) {
|
|
425
|
+
NSError *error = nil;
|
|
426
|
+
[fileManager removeItemAtPath:outputPath error:&error];
|
|
427
|
+
if (error) {
|
|
428
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Failed to remove existing file: %@", error);
|
|
429
|
+
return NO;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
NSError *error = nil;
|
|
434
|
+
_assetWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeMPEG4 error:&error];
|
|
435
|
+
if (error) {
|
|
436
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Failed to create asset writer: %@", error);
|
|
437
|
+
return NO;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Get video dimensions
|
|
441
|
+
CGSize videoSize = _player.videoSize;
|
|
442
|
+
if (videoSize.width <= 0 || videoSize.height <= 0) {
|
|
443
|
+
// Use view size as fallback
|
|
444
|
+
videoSize = self.bounds.size;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Configure video settings
|
|
448
|
+
NSDictionary *videoSettings = @{
|
|
449
|
+
AVVideoCodecKey: AVVideoCodecTypeH264,
|
|
450
|
+
AVVideoWidthKey: @((int)videoSize.width),
|
|
451
|
+
AVVideoHeightKey: @((int)videoSize.height),
|
|
452
|
+
AVVideoCompressionPropertiesKey: @{
|
|
453
|
+
AVVideoAverageBitRateKey: @(2000000), // 2 Mbps
|
|
454
|
+
AVVideoProfileLevelKey: AVVideoProfileLevelH264HighAutoLevel
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
// Create video input
|
|
459
|
+
_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
|
|
460
|
+
_assetWriterVideoInput.expectsMediaDataInRealTime = YES;
|
|
461
|
+
|
|
462
|
+
if ([_assetWriter canAddInput:_assetWriterVideoInput]) {
|
|
463
|
+
[_assetWriter addInput:_assetWriterVideoInput];
|
|
464
|
+
} else {
|
|
465
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Cannot add video input to asset writer");
|
|
466
|
+
return NO;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Create a pixel buffer adaptor for writing pixel buffers
|
|
470
|
+
NSDictionary *pixelBufferAttributes = @{
|
|
471
|
+
(NSString *)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
|
472
|
+
(NSString *)kCVPixelBufferWidthKey: @((int)videoSize.width),
|
|
473
|
+
(NSString *)kCVPixelBufferHeightKey: @((int)videoSize.height),
|
|
474
|
+
(NSString *)kCVPixelBufferCGImageCompatibilityKey: @YES,
|
|
475
|
+
(NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @YES
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
_assetWriterPixelBufferAdaptor = [AVAssetWriterInputPixelBufferAdaptor
|
|
479
|
+
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_assetWriterVideoInput
|
|
480
|
+
sourcePixelBufferAttributes:pixelBufferAttributes];
|
|
481
|
+
|
|
482
|
+
// Start recording session
|
|
483
|
+
if ([_assetWriter startWriting]) {
|
|
484
|
+
[_assetWriter startSessionAtSourceTime:kCMTimeZero];
|
|
485
|
+
_isRecording = YES;
|
|
486
|
+
|
|
487
|
+
// Start a timer to capture frames
|
|
488
|
+
[self startFrameCapture];
|
|
489
|
+
|
|
490
|
+
RCTLogInfo(@"[UnifiedPlayerViewManager] Recording started successfully");
|
|
491
|
+
return YES;
|
|
492
|
+
} else {
|
|
493
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Failed to start writing: %@", _assetWriter.error);
|
|
494
|
+
return NO;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
- (void)startFrameCapture {
|
|
499
|
+
RCTLogInfo(@"[UnifiedPlayerViewManager] Frame capture started");
|
|
500
|
+
|
|
501
|
+
// Create a CADisplayLink to capture frames at the screen refresh rate
|
|
502
|
+
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(captureFrameForRecording)];
|
|
503
|
+
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
|
504
|
+
|
|
505
|
+
// Store the display link as an associated object
|
|
506
|
+
objc_setAssociatedObject(self, "displayLinkKey", displayLink, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
507
|
+
|
|
508
|
+
// Initialize frame count
|
|
509
|
+
_frameCount = 0;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
- (void)captureFrameForRecording {
|
|
513
|
+
if (!_isRecording || !_assetWriterVideoInput.isReadyForMoreMediaData) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Create a bitmap context to draw the current view
|
|
518
|
+
CGSize size = _player.videoSize;
|
|
519
|
+
if (size.width <= 0 || size.height <= 0) {
|
|
520
|
+
size = self.bounds.size;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Create a pixel buffer
|
|
524
|
+
CVPixelBufferRef pixelBuffer = NULL;
|
|
525
|
+
CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, _assetWriterPixelBufferAdaptor.pixelBufferPool, &pixelBuffer);
|
|
526
|
+
|
|
527
|
+
if (status != kCVReturnSuccess || pixelBuffer == NULL) {
|
|
528
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Failed to create pixel buffer");
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Lock the pixel buffer
|
|
533
|
+
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
|
534
|
+
|
|
535
|
+
// Get the pixel buffer address
|
|
536
|
+
void *pixelData = CVPixelBufferGetBaseAddress(pixelBuffer);
|
|
537
|
+
|
|
538
|
+
// Create a bitmap context
|
|
539
|
+
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
540
|
+
CGContextRef context = CGBitmapContextCreate(pixelData,
|
|
541
|
+
size.width,
|
|
542
|
+
size.height,
|
|
543
|
+
8,
|
|
544
|
+
CVPixelBufferGetBytesPerRow(pixelBuffer),
|
|
545
|
+
colorSpace,
|
|
546
|
+
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
|
|
547
|
+
|
|
548
|
+
// Draw the current view into the context
|
|
549
|
+
UIGraphicsPushContext(context);
|
|
550
|
+
[self.layer renderInContext:context];
|
|
551
|
+
UIGraphicsPopContext();
|
|
552
|
+
|
|
553
|
+
// Clean up
|
|
554
|
+
CGContextRelease(context);
|
|
555
|
+
CGColorSpaceRelease(colorSpace);
|
|
556
|
+
|
|
557
|
+
// Unlock the pixel buffer
|
|
558
|
+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
|
559
|
+
|
|
560
|
+
// Calculate the presentation time
|
|
561
|
+
CMTime presentationTime = CMTimeMake(_frameCount, 30); // 30 fps
|
|
562
|
+
|
|
563
|
+
// Append the pixel buffer to the asset writer
|
|
564
|
+
if (![_assetWriterPixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:presentationTime]) {
|
|
565
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Failed to append pixel buffer: %@", _assetWriter.error);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Release the pixel buffer
|
|
569
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
570
|
+
|
|
571
|
+
// Increment the frame count
|
|
572
|
+
_frameCount++;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
- (NSString *)stopRecording {
|
|
576
|
+
RCTLogInfo(@"[UnifiedPlayerViewManager] stopRecording called");
|
|
577
|
+
|
|
578
|
+
if (!_isRecording) {
|
|
579
|
+
RCTLogError(@"[UnifiedPlayerViewManager] No recording in progress");
|
|
580
|
+
return @"";
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Stop frame capture by stopping the display link
|
|
584
|
+
CADisplayLink *displayLink = objc_getAssociatedObject(self, "displayLinkKey");
|
|
585
|
+
if (displayLink) {
|
|
586
|
+
[displayLink invalidate];
|
|
587
|
+
objc_setAssociatedObject(self, "displayLinkKey", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Finish writing
|
|
591
|
+
[_assetWriterVideoInput markAsFinished];
|
|
592
|
+
[_assetWriter finishWritingWithCompletionHandler:^{
|
|
593
|
+
if (self->_assetWriter.status == AVAssetWriterStatusCompleted) {
|
|
594
|
+
RCTLogInfo(@"[UnifiedPlayerViewManager] Recording completed successfully");
|
|
595
|
+
} else {
|
|
596
|
+
RCTLogError(@"[UnifiedPlayerViewManager] Recording failed: %@", self->_assetWriter.error);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Clean up
|
|
600
|
+
self->_assetWriter = nil;
|
|
601
|
+
self->_assetWriterVideoInput = nil;
|
|
602
|
+
self->_assetWriterPixelBufferAdaptor = nil;
|
|
603
|
+
self->_isRecording = NO;
|
|
604
|
+
self->_frameCount = 0;
|
|
605
|
+
}];
|
|
606
|
+
|
|
607
|
+
NSString *path = _recordingPath;
|
|
608
|
+
_recordingPath = nil;
|
|
609
|
+
|
|
610
|
+
return path;
|
|
611
|
+
}
|
|
612
|
+
|
|
391
613
|
- (void)setAutoplay:(BOOL)autoplay {
|
|
392
614
|
_autoplay = autoplay;
|
|
393
615
|
}
|
|
@@ -556,6 +778,18 @@
|
|
|
556
778
|
// Remove all observers
|
|
557
779
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
558
780
|
|
|
781
|
+
// Stop recording if in progress
|
|
782
|
+
if (_isRecording) {
|
|
783
|
+
[self stopRecording];
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Clean up display link if it exists
|
|
787
|
+
CADisplayLink *displayLink = objc_getAssociatedObject(self, "displayLinkKey");
|
|
788
|
+
if (displayLink) {
|
|
789
|
+
[displayLink invalidate];
|
|
790
|
+
objc_setAssociatedObject(self, "displayLinkKey", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
791
|
+
}
|
|
792
|
+
|
|
559
793
|
// Stop playback and release player
|
|
560
794
|
[_player stop];
|
|
561
795
|
_player.delegate = nil;
|
package/lib/module/index.js
CHANGED
|
@@ -163,6 +163,47 @@ export const UnifiedPlayer = {
|
|
|
163
163
|
console.log('Error calling capture:', error instanceof Error ? error.message : String(error));
|
|
164
164
|
return Promise.reject(error);
|
|
165
165
|
}
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Start recording the video
|
|
169
|
+
* @param viewTag - The tag of the player view
|
|
170
|
+
* @param outputPath - Optional path where to save the recording (platform-specific)
|
|
171
|
+
* @returns Promise resolving to true if recording started successfully
|
|
172
|
+
*/
|
|
173
|
+
startRecording: (viewTag, outputPath) => {
|
|
174
|
+
try {
|
|
175
|
+
console.log('UnifiedPlayer.startRecording called with viewTag:', viewTag);
|
|
176
|
+
return UnifiedPlayerModule.startRecording(viewTag, outputPath).then(result => {
|
|
177
|
+
console.log('Native startRecording method called successfully');
|
|
178
|
+
return result;
|
|
179
|
+
}).catch(error => {
|
|
180
|
+
console.log('Error calling startRecording:', error instanceof Error ? error.message : String(error));
|
|
181
|
+
throw error;
|
|
182
|
+
});
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.log('Error calling startRecording:', error instanceof Error ? error.message : String(error));
|
|
185
|
+
return Promise.reject(error);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
/**
|
|
189
|
+
* Stop recording the video
|
|
190
|
+
* @param viewTag - The tag of the player view
|
|
191
|
+
* @returns Promise resolving to the path of the saved recording
|
|
192
|
+
*/
|
|
193
|
+
stopRecording: viewTag => {
|
|
194
|
+
try {
|
|
195
|
+
console.log('UnifiedPlayer.stopRecording called with viewTag:', viewTag);
|
|
196
|
+
return UnifiedPlayerModule.stopRecording(viewTag).then(filePath => {
|
|
197
|
+
console.log('Native stopRecording method called successfully');
|
|
198
|
+
return filePath;
|
|
199
|
+
}).catch(error => {
|
|
200
|
+
console.log('Error calling stopRecording:', error instanceof Error ? error.message : String(error));
|
|
201
|
+
throw error;
|
|
202
|
+
});
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.log('Error calling stopRecording:', error instanceof Error ? error.message : String(error));
|
|
205
|
+
return Promise.reject(error);
|
|
206
|
+
}
|
|
166
207
|
}
|
|
167
208
|
};
|
|
168
209
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["forwardRef","requireNativeComponent","UIManager","NativeModules","Platform","jsx","_jsx","LINKING_ERROR","select","ios","default","getViewManagerConfig","UnifiedPlayer","Error","NativeUnifiedPlayerView","UnifiedPlayerModule","UnifiedPlayerEventTypes","LOAD_START","READY","ERROR","PROGRESS","COMPLETE","STALLED","RESUMED","PLAYING","PAUSED","UnifiedPlayerEvents","UnifiedPlayerView","props","ref","play","viewTag","console","log","then","result","catch","error","message","String","Promise","reject","pause","seekTo","time","getCurrentTime","getDuration","capture","base64String"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["forwardRef","requireNativeComponent","UIManager","NativeModules","Platform","jsx","_jsx","LINKING_ERROR","select","ios","default","getViewManagerConfig","UnifiedPlayer","Error","NativeUnifiedPlayerView","UnifiedPlayerModule","UnifiedPlayerEventTypes","LOAD_START","READY","ERROR","PROGRESS","COMPLETE","STALLED","RESUMED","PLAYING","PAUSED","UnifiedPlayerEvents","UnifiedPlayerView","props","ref","play","viewTag","console","log","then","result","catch","error","message","String","Promise","reject","pause","seekTo","time","getCurrentTime","getDuration","capture","base64String","startRecording","outputPath","stopRecording","filePath"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -75,5 +75,18 @@ export declare const UnifiedPlayer: {
|
|
|
75
75
|
* @returns Promise resolving to the base64 encoded image string
|
|
76
76
|
*/
|
|
77
77
|
capture: (viewTag: number) => Promise<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Start recording the video
|
|
80
|
+
* @param viewTag - The tag of the player view
|
|
81
|
+
* @param outputPath - Optional path where to save the recording (platform-specific)
|
|
82
|
+
* @returns Promise resolving to true if recording started successfully
|
|
83
|
+
*/
|
|
84
|
+
startRecording: (viewTag: number, outputPath?: string) => Promise<boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Stop recording the video
|
|
87
|
+
* @param viewTag - The tag of the player view
|
|
88
|
+
* @returns Promise resolving to the path of the saved recording
|
|
89
|
+
*/
|
|
90
|
+
stopRecording: (viewTag: number) => Promise<string>;
|
|
78
91
|
};
|
|
79
92
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAkBtB,MAAM,MAAM,kBAAkB,GAAG;IAE/B,QAAQ,EAAE,MAAM,CAAC;IAGjB,KAAK,EAAE,SAAS,CAAC;IAGjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,IAAI,CAAC,EAAE,OAAO,CAAC;IAGf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAGzB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAG3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAG/B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAGhC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAGvE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAG/B,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAG/B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAGtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAYF,eAAO,MAAM,uBAAuB;;;;;;;;;;CAUnC,CAAC;AAGF,eAAO,MAAM,mBAAmB,KAA8B,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,iBAAiB,8LAK5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB;;;;OAIG;oBACa,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwBzC;;;;OAIG;qBACc,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwB1C;;;;;OAKG;sBACe,MAAM,QAAQ,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IA6BzD;;;;OAIG;8BACuB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAalD;;;;OAIG;2BACoB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAa/C;;;;OAIG;uBACgB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAkBtB,MAAM,MAAM,kBAAkB,GAAG;IAE/B,QAAQ,EAAE,MAAM,CAAC;IAGjB,KAAK,EAAE,SAAS,CAAC;IAGjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,IAAI,CAAC,EAAE,OAAO,CAAC;IAGf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAGzB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAG3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAG/B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAGhC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAGvE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAG/B,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAG/B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAGtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAYF,eAAO,MAAM,uBAAuB;;;;;;;;;;CAUnC,CAAC;AAGF,eAAO,MAAM,mBAAmB,KAA8B,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,iBAAiB,8LAK5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB;;;;OAIG;oBACa,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwBzC;;;;OAIG;qBACc,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwB1C;;;;;OAKG;sBACe,MAAM,QAAQ,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IA6BzD;;;;OAIG;8BACuB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAalD;;;;OAIG;2BACoB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAa/C;;;;OAIG;uBACgB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAwB3C;;;;;OAKG;8BACuB,MAAM,eAAe,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwBxE;;;;OAIG;6BACsB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;CAuBlD,CAAC"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -263,4 +263,63 @@ export const UnifiedPlayer = {
|
|
|
263
263
|
return Promise.reject(error);
|
|
264
264
|
}
|
|
265
265
|
},
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Start recording the video
|
|
269
|
+
* @param viewTag - The tag of the player view
|
|
270
|
+
* @param outputPath - Optional path where to save the recording (platform-specific)
|
|
271
|
+
* @returns Promise resolving to true if recording started successfully
|
|
272
|
+
*/
|
|
273
|
+
startRecording: (viewTag: number, outputPath?: string): Promise<boolean> => {
|
|
274
|
+
try {
|
|
275
|
+
console.log('UnifiedPlayer.startRecording called with viewTag:', viewTag);
|
|
276
|
+
return UnifiedPlayerModule.startRecording(viewTag, outputPath)
|
|
277
|
+
.then((result: boolean) => {
|
|
278
|
+
console.log('Native startRecording method called successfully');
|
|
279
|
+
return result;
|
|
280
|
+
})
|
|
281
|
+
.catch((error: any) => {
|
|
282
|
+
console.log(
|
|
283
|
+
'Error calling startRecording:',
|
|
284
|
+
error instanceof Error ? error.message : String(error)
|
|
285
|
+
);
|
|
286
|
+
throw error;
|
|
287
|
+
});
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.log(
|
|
290
|
+
'Error calling startRecording:',
|
|
291
|
+
error instanceof Error ? error.message : String(error)
|
|
292
|
+
);
|
|
293
|
+
return Promise.reject(error);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Stop recording the video
|
|
299
|
+
* @param viewTag - The tag of the player view
|
|
300
|
+
* @returns Promise resolving to the path of the saved recording
|
|
301
|
+
*/
|
|
302
|
+
stopRecording: (viewTag: number): Promise<string> => {
|
|
303
|
+
try {
|
|
304
|
+
console.log('UnifiedPlayer.stopRecording called with viewTag:', viewTag);
|
|
305
|
+
return UnifiedPlayerModule.stopRecording(viewTag)
|
|
306
|
+
.then((filePath: string) => {
|
|
307
|
+
console.log('Native stopRecording method called successfully');
|
|
308
|
+
return filePath;
|
|
309
|
+
})
|
|
310
|
+
.catch((error: any) => {
|
|
311
|
+
console.log(
|
|
312
|
+
'Error calling stopRecording:',
|
|
313
|
+
error instanceof Error ? error.message : String(error)
|
|
314
|
+
);
|
|
315
|
+
throw error;
|
|
316
|
+
});
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.log(
|
|
319
|
+
'Error calling stopRecording:',
|
|
320
|
+
error instanceof Error ? error.message : String(error)
|
|
321
|
+
);
|
|
322
|
+
return Promise.reject(error);
|
|
323
|
+
}
|
|
324
|
+
},
|
|
266
325
|
};
|