@volcengine/react-native-live-pull 1.1.3-rc.1 → 1.2.0-rc.1

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.
Files changed (31) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/com/volcengine/velive/rn/pull/ClassHelper.java +15 -0
  3. package/android/src/main/java/com/volcengine/velive/rn/pull/NativeVariableManager.java +1 -1
  4. package/android/src/main/java/com/volcengine/velive/rn/pull/VolcLiveModule.java +2 -0
  5. package/android/src/main/java/com/volcengine/velive/rn/pull/autogen/MethodSignature.java +66 -77
  6. package/android/src/main/java/com/volcengine/velive/rn/pull/pictureInpicture/FloatingWindowService.java +79 -15
  7. package/ios/VeLivePlayerMultiObserver.h +3 -2
  8. package/ios/VeLivePlayerMultiObserver.m +2 -2
  9. package/ios/include/react-native-velive-pull.modulemap +4 -0
  10. package/ios/pictureInpicture/PictureInPictureManager.h +21 -1
  11. package/ios/pictureInpicture/PictureInPictureManager.m +260 -141
  12. package/lib/commonjs/index.js +4455 -1648
  13. package/lib/module/index.js +4455 -1648
  14. package/lib/typescript/codegen/android/api.d.ts +18 -13
  15. package/lib/typescript/codegen/android/callback.d.ts +38 -1
  16. package/lib/typescript/codegen/android/errorcode.d.ts +58 -3
  17. package/lib/typescript/codegen/android/keytype.d.ts +168 -26
  18. package/lib/typescript/codegen/ios/api.d.ts +66 -54
  19. package/lib/typescript/codegen/ios/callback.d.ts +32 -5
  20. package/lib/typescript/codegen/ios/errorcode.d.ts +56 -2
  21. package/lib/typescript/codegen/ios/keytype.d.ts +261 -23
  22. package/lib/typescript/codegen/pack/api.d.ts +33 -27
  23. package/lib/typescript/codegen/pack/callback.d.ts +33 -9
  24. package/lib/typescript/codegen/pack/errorcode.d.ts +30 -5
  25. package/lib/typescript/codegen/pack/keytype.d.ts +209 -107
  26. package/lib/typescript/core/api.d.ts +13 -0
  27. package/lib/typescript/core/keytype.d.ts +18 -2
  28. package/package.json +1 -1
  29. package/react-native-velive-pull.podspec +12 -3
  30. package/ios/pictureInpicture/VeLivePictureInPictureController.h +0 -207
  31. package/ios/pictureInpicture/VeLivePictureInPictureController.m +0 -3393
@@ -1,26 +1,29 @@
1
1
  #import "PictureInPictureManager.h"
2
2
  #import "../VeLivePlayerMultiObserver.h"
3
- #import "TTSDKFramework/TVLManager.h"
4
- #import "VeLivePictureInPictureController.h"
5
3
  #import <AVKit/AVKit.h>
4
+ #import <TTSDKFramework/TTVideoLive.h>
6
5
  #import <UIKit/UIKit.h>
6
+ #import <VolcApiEngine/VePictureInPictureController.h>
7
+ #import <VolcApiEngine/VePictureInPictureDefine.h>
7
8
 
8
9
  @protocol VeLivePlayerObserver;
9
- @protocol VeLivePictureInPictureDelegate;
10
+ @protocol VePictureInPictureDelegate;
10
11
  @protocol VeLivePictureInPictureManagerListener;
11
12
 
12
13
  // Add class extension to declare private properties instead of redefining
13
14
  // interface
14
15
  @interface VeLivePictureInPictureManager () <
15
- VeLivePlayerObserver, VeLivePictureInPictureDelegate,
16
+ VeLivePlayerObserver, VePictureInPictureDelegate,
16
17
  VeLivePictureInPictureManagerListener>
17
- @property(nonatomic, strong) VeLivePictureInPictureController *pipController;
18
- @property(nonatomic, assign) CGRect pipVideoFrame;
19
- @property(nonatomic, assign) CGSize pipVideoSize;
18
+ @property(nonatomic, strong) VePictureInPictureController *pipController;
20
19
  @property(nonatomic, assign) BOOL enableVideoObserver;
21
20
  @property(nonatomic, strong) TVLManager *player;
21
+ @property(nonatomic, weak) UIView *contentView;
22
22
  @property(nonatomic, weak) id<VeLivePictureInPictureManagerListener> listener;
23
23
  @property(nonatomic, assign) BOOL pipAutoStart;
24
+ @property(nonatomic, strong)
25
+ NSMutableDictionary<NSString *, void (^)(AVPictureInPictureController *)>
26
+ *pipObservers;
24
27
  @end
25
28
 
26
29
  NSString *const kObserverKey = @"pip-observer";
@@ -40,45 +43,157 @@ NSString *const kObserverKey = @"pip-observer";
40
43
  return [self sharedInstance];
41
44
  }
42
45
 
43
- - (void)setupPlayer:(TVLManager *)player {
44
- if (self.player) {
45
- [self destroyPictureInPicture];
46
+ - (instancetype)init {
47
+ if (self = [super init]) {
48
+ _autoHideViewController = YES;
49
+ _pipObservers = [NSMutableDictionary dictionary];
50
+ if (@available(iOS 14.2, *)) {
51
+ _canStartPictureInPictureAutomaticallyFromInline = NO;
52
+ }
46
53
  }
47
- self.player = player;
54
+ return self;
55
+ }
48
56
 
49
- // Reset video frame observer status
50
- self.enableVideoObserver = NO;
51
- self.pipAutoStart = NO;
57
+ - (void)dealloc {
58
+ [self disableVideoFrameObserver];
59
+
60
+ if (self.pipController) {
61
+ self.pipController.delegate = nil;
62
+ self.pipController = nil;
63
+ }
64
+
65
+ [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
66
+ }
67
+
68
+ - (void)setupPlayer:(TVLManager *)player {
69
+ [self ensurePipControllerReady:player completion:nil];
52
70
  }
53
71
 
54
- - (void)setupPictureInPicturePrepareCompletion:
55
- (VELPipPrepareCompletionBlock)prepareCompletion {
72
+ - (void)ensurePipControllerReady:(TVLManager *)player
73
+ completion:(nullable void (^)(void))completion {
74
+ if (player && self.player != player) {
75
+ if (self.player) {
76
+ [self disableVideoFrameObserver];
77
+ }
78
+ self.player = player;
79
+ self.contentView = player.playerView;
80
+ }
81
+
56
82
  if (!self.pipController) {
57
- self.pipController = [[VeLivePictureInPictureController alloc]
58
- initWithType:VeLivePictureInPictureTypeAuto
59
- contentView:self.player.playerView];
60
- [self setupPipVideoFrameAndSize];
61
- self.pipController.delegate = self;
62
- self.pipController.contentController = nil;
63
- self.pipController.autoHideContentController = NO;
64
- if (@available(iOS 14.0, *)) {
65
- self.player.supportPictureInPictureMode = YES;
83
+ [self initPipController];
84
+ [self enableVideoFrameObserver];
85
+ [self updatePipController:completion];
86
+ }
87
+
88
+ if (self.contentView && self.pipController) {
89
+ if (@available(iOS 14.2, *)) {
90
+ self.pipController.canStartPictureInPictureAutomaticallyFromInline =
91
+ self.canStartPictureInPictureAutomaticallyFromInline;
92
+ }
93
+ [self updatePipController:completion];
94
+ } else {
95
+ if (completion) {
96
+ completion();
66
97
  }
67
98
  }
68
- [self.pipController prepareWithCompletion:prepareCompletion];
69
99
  }
70
100
 
71
- - (void)setupPipVideoFrameAndSize {
72
- if (!CGSizeEqualToSize(self.pipVideoSize, CGSizeZero)) {
73
- [self.pipController setVideoSize:self.pipVideoSize];
101
+ // Add a persistent observer for PIP controller status, returns observer ID
102
+ - (NSString *)addPipControllerObserver:
103
+ (void (^)(AVPictureInPictureController *pipController))observer {
104
+ if (!observer) {
105
+ return nil;
74
106
  }
75
- if (!CGRectEqualToRect(self.pipVideoFrame, CGRectZero)) {
76
- [self.pipController setVideoFrame:self.pipVideoFrame];
107
+
108
+ NSString *observerId = [NSString
109
+ stringWithFormat:@"observer_%@_%lu", [[NSUUID UUID] UUIDString],
110
+ (unsigned long)[NSDate date].timeIntervalSince1970];
111
+
112
+ self.pipObservers[observerId] = observer;
113
+
114
+ // If PIP controller is already ready, notify immediately
115
+ if (self.pipController) {
116
+ observer([self.pipController pictureInPictureController]);
117
+ }
118
+
119
+ return observerId;
120
+ }
121
+
122
+ // Remove observer by ID
123
+ - (void)removePipControllerObserver:(NSString *)observerId {
124
+ if (observerId) {
125
+ [self.pipObservers removeObjectForKey:observerId];
126
+ }
127
+ }
128
+
129
+ // Remove all observers
130
+ - (void)removeAllPipControllerObservers {
131
+ [self.pipObservers removeAllObjects];
132
+ }
133
+
134
+ - (void)initPipController {
135
+ if (self.pipController != nil) {
136
+ self.pipController.delegate = nil;
137
+ self.pipController = nil;
138
+ }
139
+ self.pipController = [[VePictureInPictureController alloc]
140
+ initWithType:VePictureInPictureTypeContentSource
141
+ contentView:self.player.playerView];
142
+ [self.pipController setRenderMode:1];
143
+ self.pipController.delegate = self;
144
+ self.pipController.autoConfigAudioSession = YES;
145
+ if (@available(iOS 14.2, *)) {
146
+ self.pipController.canStartPictureInPictureAutomaticallyFromInline =
147
+ self.canStartPictureInPictureAutomaticallyFromInline;
148
+ }
149
+ if (@available(iOS 14.0, *)) {
150
+ self.pipController.requiresLinearPlayback = NO;
151
+ }
152
+
153
+ if (self.pipObservers.count > 0) {
154
+ dispatch_async(dispatch_get_main_queue(), ^{
155
+ [self notifyPipControllerReady];
156
+ });
157
+ }
158
+ }
159
+
160
+ - (void)updatePipController:(nullable void (^)(void))completion {
161
+ VeLivePlayerVideoStreamInfo *info = [self.player getVideoStreamInfo];
162
+
163
+ if (!CGSizeEqualToSize(CGSizeZero, CGSizeMake(info.width, info.height))) {
164
+ [self.pipController setVideoSize:CGSizeMake(info.width, info.height) completion:nil];
165
+ }
166
+
167
+ [self.pipController setContentView:self.contentView
168
+ completion:^{
169
+ if (completion) {
170
+ completion();
171
+ }
172
+ }];
173
+ }
174
+
175
+ // Notify all observers
176
+ - (void)notifyPipControllerReady {
177
+ if (!self.pipController) {
178
+ return;
179
+ }
180
+
181
+ AVPictureInPictureController *controller =
182
+ [self.pipController pictureInPictureController];
183
+
184
+ // copy observers to avoid modifying the dictionary while iterating
185
+ NSDictionary *observersCopy = [self.pipObservers copy];
186
+
187
+ // Notify all persistent observers
188
+ for (void (^observer)(AVPictureInPictureController *)
189
+ in observersCopy.allValues) {
190
+ if (observer) {
191
+ observer(controller);
192
+ }
77
193
  }
78
194
  }
79
195
 
80
196
  - (void)enableVideoFrameObserver {
81
- NSLog(@"PIP: Enable video frame observer");
82
197
  if (self.enableVideoObserver) {
83
198
  // If already enabled, disable then re-enable to ensure the observer is
84
199
  // re-registered
@@ -89,11 +204,12 @@ NSString *const kObserverKey = @"pip-observer";
89
204
  enableVideoFrameObserver:YES
90
205
  pixelFormat:VeLivePlayerPixelFormatBGRA32
91
206
  bufferType:VeLivePlayerVideoBufferTypeSampleBuffer];
92
- NSLog(@"PIP: Video frame observer enabled");
207
+ [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
208
+ [[VeLivePlayerMultiObserver sharedInstance] addObserver:kObserverKey
209
+ observer:self];
93
210
  }
94
211
 
95
212
  - (void)disableVideoFrameObserver {
96
- NSLog(@"PIP: Disable video frame observer");
97
213
  if (!self.enableVideoObserver) {
98
214
  return;
99
215
  }
@@ -101,94 +217,86 @@ NSString *const kObserverKey = @"pip-observer";
101
217
  [self.player enableVideoFrameObserver:NO
102
218
  pixelFormat:VeLivePlayerPixelFormatUnknown
103
219
  bufferType:VeLivePlayerVideoBufferTypeUnknown];
104
- NSLog(@"PIP: Video frame observer disabled");
220
+ [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
105
221
  }
106
222
 
107
223
  - (void)startPictureInPicture {
108
- NSLog(@"PIP: Start picture-in-picture");
109
- [self enableVideoFrameObserver];
110
-
111
- // Ensure observer is properly added
112
- [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
113
- [[VeLivePlayerMultiObserver sharedInstance] addObserver:kObserverKey
114
- observer:self];
224
+ if (!self.player) {
225
+ return;
226
+ }
115
227
 
116
- // Use main thread with delay to ensure state is updated
117
- dispatch_async(dispatch_get_main_queue(), ^{
118
- [self setupPictureInPicturePrepareCompletion:^(
119
- VeLivePictureInPictureController *_Nonnull pipController,
120
- NSError *_Nullable error) {
121
- if (error != nil) {
122
- NSLog(@"PIP: Failed to start picture-in-picture: %@", error);
123
- return;
124
- }
125
- if (!self.player.isPlaying) {
126
- NSLog(@"PIP: Please start playing before entering PIP mode");
127
- return;
128
- }
129
- if (!self.pipController.canStartPictureInPicture) {
130
- NSLog(@"PIP: Cannot start picture-in-picture now, please try again "
131
- @"later");
132
- return;
133
- }
134
- NSLog(@"PIP: Ready to start picture-in-picture");
135
- [self.pipController startPictureInPicture];
136
- }];
137
- });
228
+ [self ensurePipControllerReady:self.player
229
+ completion:^{
230
+ if (@available(iOS 14.0, *)) {
231
+ [self.player setSupportPictureInPictureMode:YES];
232
+ BOOL startSuccess =
233
+ [self.pipController startPictureInPicture];
234
+ if (!startSuccess) {
235
+ NSLog(@"PIP: Failed to start picture-in-picture");
236
+ }
237
+ }
238
+ }];
138
239
  }
139
240
 
140
241
  - (void)stopPictureInPicture {
141
- [self disableVideoFrameObserver];
142
- [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
143
- [self.pipController stopPictureInPicture];
242
+ if (self.autoHideViewController) {
243
+ [self.pipController
244
+ stopPictureInPictureWithType:VePictureInPictureStopTypeFromApiRestore];
245
+ } else {
246
+ [self.pipController stopPictureInPicture];
247
+ }
144
248
  }
145
249
 
146
250
  - (void)destroyPictureInPicture {
147
251
  dispatch_async(dispatch_get_main_queue(), ^{
252
+ [self stopPictureInPicture];
253
+
254
+ // ensure this is called on the main thread
148
255
  [self disableVideoFrameObserver];
149
- [self.pipController destroyPictureInPicture];
150
- [self setPipController:nil];
151
- [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
152
- self.player = nil;
256
+
257
+ // clear delegate to avoid retain cycle
258
+ if (self.pipController) {
259
+ self.pipController.delegate = nil;
260
+ }
261
+
262
+ self.pipController = nil;
263
+
264
+ if (@available(iOS 14.2, *)) {
265
+ [self setCanStartPictureInPictureAutomaticallyFromInline:NO];
266
+ }
153
267
  });
154
268
  }
155
269
 
156
270
  - (BOOL)isPictureInPictureStarted {
157
- return VeLivePictureInPictureController.isPictureInPictureStarted;
271
+ return [VePictureInPictureController isPictureInPictureStarted];
158
272
  }
159
273
 
160
274
  - (BOOL)isPictureInPictureSupported {
161
- return [VeLivePictureInPictureController isPictureInPictureSupported];
275
+ return [VePictureInPictureController isPictureInPictureSupported];
162
276
  }
163
277
 
164
278
  - (void)enablePictureInPicture {
165
- NSLog(@"PIP: Enable picture-in-picture");
166
- self.pipAutoStart = YES;
167
- // main thread
279
+ _canStartPictureInPictureAutomaticallyFromInline = YES;
280
+ if (self.pipController != nil) {
281
+ if (@available(iOS 14.2, *)) {
282
+ self.pipController.canStartPictureInPictureAutomaticallyFromInline = YES;
283
+ }
284
+ }
168
285
  dispatch_async(dispatch_get_main_queue(), ^{
169
286
  if (@available(iOS 14.2, *)) {
170
- [self setupPictureInPicturePrepareCompletion:^(
171
- VeLivePictureInPictureController *_Nonnull pipController,
172
- NSError *_Nullable error) {
173
- // Set in callback to ensure controller is ready
174
- [pipController setCanStartPictureInPictureAutomaticallyFromInline:YES];
175
- }];
287
+ [self ensurePipControllerReady:self.player completion:nil];
176
288
  }
177
289
  });
178
290
  }
179
291
 
180
292
  - (void)disablePictureInPicture {
181
- NSLog(@"PIP: Disable picture-in-picture");
182
- self.pipAutoStart = NO;
183
- if (!self.pipController) {
184
- return;
293
+ _canStartPictureInPictureAutomaticallyFromInline = NO;
294
+ if (self.pipController != nil) {
295
+ self.pipController.canStartPictureInPictureAutomaticallyFromInline = NO;
185
296
  }
186
297
  dispatch_async(dispatch_get_main_queue(), ^{
187
298
  if (@available(iOS 14.2, *)) {
188
- [self.pipController
189
- setCanStartPictureInPictureAutomaticallyFromInline:NO];
190
- [self.pipController destroyPictureInPicture];
191
- self.pipController = nil;
299
+ [self destroyPictureInPicture];
192
300
  }
193
301
  });
194
302
  }
@@ -201,73 +309,84 @@ NSString *const kObserverKey = @"pip-observer";
201
309
  - (void)onRenderVideoFrame:(TVLManager *_Nonnull)player
202
310
  videoFrame:(VeLivePlayerVideoFrame *_Nonnull)videoFrame {
203
311
  @autoreleasepool {
312
+ // 确保 pipController 存在且有效,避免在销毁过程中继续处理 buffer
313
+ if (!self.pipController || !self.enableVideoObserver) {
314
+ return;
315
+ }
316
+
204
317
  if (@available(iOS 15.0, *)) {
205
318
  if (videoFrame.bufferType == VeLivePlayerVideoBufferTypePixelBuffer) {
206
- [self.pipController enqueuePixelBuffer:videoFrame.pixelBuffer];
319
+ CVPixelBufferRef pixelBuffer = videoFrame.pixelBuffer;
320
+ if (pixelBuffer != NULL) {
321
+ [self.pipController enqueuePixelBuffer:pixelBuffer];
322
+ }
207
323
  } else if (videoFrame.bufferType ==
208
324
  VeLivePlayerVideoBufferTypeSampleBuffer) {
209
- [self.pipController enqueueSampleBuffer:videoFrame.sampleBuffer];
325
+ CMSampleBufferRef sampleBuffer = videoFrame.sampleBuffer;
326
+ if (sampleBuffer != NULL) {
327
+ [self.pipController enqueueSampleBuffer:sampleBuffer];
328
+ }
210
329
  }
211
330
  }
212
331
  }
213
332
  }
214
333
 
215
- - (void)onVideoSizeChanged:(TVLManager *)player
216
- width:(int)width
217
- height:(int)height {
218
- self.pipVideoSize = CGSizeMake(width, height);
219
- if (!CGSizeEqualToSize(CGSizeZero, player.videoAreaFrame.size)) {
220
- self.pipVideoFrame = player.videoAreaFrame;
221
- } else {
222
- self.pipVideoFrame = player.playerView.frame;
223
- }
224
- [self setupPipVideoFrameAndSize];
225
- }
226
-
227
334
  - (void)onError:(TVLManager *)player error:(VeLivePlayerError *)error {
228
335
  NSLog(@"VeLiveQuickStartDemo: Error %ld, %@", error.code, error.errorMsg);
229
336
  }
230
337
 
231
- /// MARK: - VeLivePictureInPictureDelegate
232
- - (void)pictureInPictureIsReady:
233
- (VeLivePictureInPictureController *)pictureInPicture {
234
- NSLog(@"PIP: Picture-in-picture is ready");
235
- }
338
+ /// MARK: - VePictureInPictureDelegate
339
+ - (void)pictureInPictureController:
340
+ (VePictureInPictureController *)pictureInPictureController
341
+ statusChanged:(VePictureInPictureStatus)fromStatus
342
+ to:(VePictureInPictureStatus)toStatus {
343
+ switch (toStatus) {
344
+ case VePictureInPictureStatusIde: {
236
345
 
237
- - (void)pictureInPictureWillStart:
238
- (VeLivePictureInPictureController *)pictureInPicture {
239
- NSLog(@"PIP: Picture-in-picture will start...");
240
- }
346
+ } break;
347
+ case VePictureInPictureStatusPreparing: {
241
348
 
242
- - (void)pictureInPictureDidStart:
243
- (VeLivePictureInPictureController *)pictureInPicture {
244
- NSLog(@"PIP: Picture-in-picture did start");
245
- if (self.listener) {
246
- [self.listener onStartPictureInPicture];
247
- }
248
- }
249
- - (void)pictureInPicture:(VeLivePictureInPictureController *)pictureInPicture
250
- failedToStartWithError:(NSError *)error {
251
- NSLog(@"PIP: Failed to start picture-in-picture: %@", error);
252
- if (self.listener) {
253
- [self.listener onError:error.code extraData:error.userInfo];
254
- }
255
- }
256
- - (void)pictureInPictureWillStop:
257
- (VeLivePictureInPictureController *)pictureInPicture
258
- isUserStop:(BOOL)isUserStop {
259
- NSLog(@"PIP: Picture-in-picture will stop");
260
- }
261
- - (void)pictureInPictureDidStop:
262
- (VeLivePictureInPictureController *)pictureInPicture
263
- isUserStop:(BOOL)isUserStop {
264
- NSLog(@"PIP: Picture-in-picture stopped");
265
- if (self.listener) {
266
- [self.listener onStopPictureInPicture];
349
+ } break;
350
+ case VePictureInPictureStatusReady: {
351
+ [self notifyPipControllerReady];
352
+ } break;
353
+ case VePictureInPictureStatusWillStart: {
354
+
355
+ } break;
356
+ case VePictureInPictureStatusDidStart: {
357
+ if (self.listener) {
358
+ [self.listener onStartPictureInPicture];
359
+ }
360
+ break;
361
+ case VePictureInPictureStatusWillChange: {
362
+
363
+ } break;
364
+ case VePictureInPictureStatusDidChange: {
365
+
366
+ } break;
367
+ case VePictureInPictureStatusRestoreUI: {
368
+
369
+ } break;
370
+ case VePictureInPictureStatusWillStop: {
371
+
372
+ } break;
373
+ case VePictureInPictureStatusDidStop: {
374
+ if (self.listener) {
375
+ [self.listener onStopPictureInPicture];
376
+ }
377
+ if (@available(iOS 14.2, *)) {
378
+ if (!self.canStartPictureInPictureAutomaticallyFromInline) {
379
+ [self destroyPictureInPicture];
380
+ }
381
+ }
382
+ } break;
383
+ case VePictureInPictureStatusError: {
384
+ if (self.listener) {
385
+ [self.listener onError:pictureInPictureController.error.code
386
+ extraData:pictureInPictureController.error.userInfo];
387
+ }
388
+ } break;
267
389
  }
268
- if (!self.pipAutoStart) {
269
- [self.pipController destroyPictureInPicture];
270
- self.pipController = nil;
271
390
  }
272
391
  }
273
392