@byteplus/react-native-live-pull 1.1.3-rc.3 → 1.2.0-rc.0

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 +254 -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 +51 -43
  15. package/lib/typescript/codegen/android/callback.d.ts +166 -0
  16. package/lib/typescript/codegen/android/errorcode.d.ts +123 -2
  17. package/lib/typescript/codegen/android/keytype.d.ts +501 -13
  18. package/lib/typescript/codegen/ios/api.d.ts +232 -16
  19. package/lib/typescript/codegen/ios/callback.d.ts +137 -1
  20. package/lib/typescript/codegen/ios/errorcode.d.ts +104 -0
  21. package/lib/typescript/codegen/ios/keytype.d.ts +460 -6
  22. package/lib/typescript/codegen/pack/api.d.ts +66 -57
  23. package/lib/typescript/codegen/pack/callback.d.ts +45 -21
  24. package/lib/typescript/codegen/pack/errorcode.d.ts +45 -15
  25. package/lib/typescript/codegen/pack/keytype.d.ts +388 -114
  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,151 @@ 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;
66
92
  }
93
+ [self updatePipController:completion];
94
+ } else {
95
+ if (completion) {
96
+ completion();
97
+ }
98
+ }
99
+ }
100
+
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;
106
+ }
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]);
67
117
  }
68
- [self.pipController prepareWithCompletion:prepareCompletion];
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];
69
132
  }
70
133
 
71
- - (void)setupPipVideoFrameAndSize {
72
- if (!CGSizeEqualToSize(self.pipVideoSize, CGSizeZero)) {
73
- [self.pipController setVideoSize:self.pipVideoSize];
134
+ - (void)initPipController {
135
+ if (self.pipController != nil) {
136
+ self.pipController.delegate = nil;
137
+ self.pipController = nil;
74
138
  }
75
- if (!CGRectEqualToRect(self.pipVideoFrame, CGRectZero)) {
76
- [self.pipController setVideoFrame:self.pipVideoFrame];
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
+ [self.pipController setContentView:self.contentView
162
+ completion:^{
163
+ if (completion) {
164
+ completion();
165
+ }
166
+ }];
167
+ }
168
+
169
+ // Notify all observers
170
+ - (void)notifyPipControllerReady {
171
+ if (!self.pipController) {
172
+ return;
173
+ }
174
+
175
+ AVPictureInPictureController *controller =
176
+ [self.pipController pictureInPictureController];
177
+
178
+ // copy observers to avoid modifying the dictionary while iterating
179
+ NSDictionary *observersCopy = [self.pipObservers copy];
180
+
181
+ // Notify all persistent observers
182
+ for (void (^observer)(AVPictureInPictureController *)
183
+ in observersCopy.allValues) {
184
+ if (observer) {
185
+ observer(controller);
186
+ }
77
187
  }
78
188
  }
79
189
 
80
190
  - (void)enableVideoFrameObserver {
81
- NSLog(@"PIP: Enable video frame observer");
82
191
  if (self.enableVideoObserver) {
83
192
  // If already enabled, disable then re-enable to ensure the observer is
84
193
  // re-registered
@@ -89,11 +198,12 @@ NSString *const kObserverKey = @"pip-observer";
89
198
  enableVideoFrameObserver:YES
90
199
  pixelFormat:VeLivePlayerPixelFormatBGRA32
91
200
  bufferType:VeLivePlayerVideoBufferTypeSampleBuffer];
92
- NSLog(@"PIP: Video frame observer enabled");
201
+ [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
202
+ [[VeLivePlayerMultiObserver sharedInstance] addObserver:kObserverKey
203
+ observer:self];
93
204
  }
94
205
 
95
206
  - (void)disableVideoFrameObserver {
96
- NSLog(@"PIP: Disable video frame observer");
97
207
  if (!self.enableVideoObserver) {
98
208
  return;
99
209
  }
@@ -101,94 +211,86 @@ NSString *const kObserverKey = @"pip-observer";
101
211
  [self.player enableVideoFrameObserver:NO
102
212
  pixelFormat:VeLivePlayerPixelFormatUnknown
103
213
  bufferType:VeLivePlayerVideoBufferTypeUnknown];
104
- NSLog(@"PIP: Video frame observer disabled");
214
+ [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
105
215
  }
106
216
 
107
217
  - (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];
218
+ if (!self.player) {
219
+ return;
220
+ }
115
221
 
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
- });
222
+ [self ensurePipControllerReady:self.player
223
+ completion:^{
224
+ if (@available(iOS 14.0, *)) {
225
+ [self.player setSupportPictureInPictureMode:YES];
226
+ BOOL startSuccess =
227
+ [self.pipController startPictureInPicture];
228
+ if (!startSuccess) {
229
+ NSLog(@"PIP: Failed to start picture-in-picture");
230
+ }
231
+ }
232
+ }];
138
233
  }
139
234
 
140
235
  - (void)stopPictureInPicture {
141
- [self disableVideoFrameObserver];
142
- [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
143
- [self.pipController stopPictureInPicture];
236
+ if (self.autoHideViewController) {
237
+ [self.pipController
238
+ stopPictureInPictureWithType:VePictureInPictureStopTypeFromApiRestore];
239
+ } else {
240
+ [self.pipController stopPictureInPicture];
241
+ }
144
242
  }
145
243
 
146
244
  - (void)destroyPictureInPicture {
147
245
  dispatch_async(dispatch_get_main_queue(), ^{
246
+ [self stopPictureInPicture];
247
+
248
+ // ensure this is called on the main thread
148
249
  [self disableVideoFrameObserver];
149
- [self.pipController destroyPictureInPicture];
150
- [self setPipController:nil];
151
- [[VeLivePlayerMultiObserver sharedInstance] removeObserver:kObserverKey];
152
- self.player = nil;
250
+
251
+ // clear delegate to avoid retain cycle
252
+ if (self.pipController) {
253
+ self.pipController.delegate = nil;
254
+ }
255
+
256
+ self.pipController = nil;
257
+
258
+ if (@available(iOS 14.2, *)) {
259
+ [self setCanStartPictureInPictureAutomaticallyFromInline:NO];
260
+ }
153
261
  });
154
262
  }
155
263
 
156
264
  - (BOOL)isPictureInPictureStarted {
157
- return VeLivePictureInPictureController.isPictureInPictureStarted;
265
+ return [VePictureInPictureController isPictureInPictureStarted];
158
266
  }
159
267
 
160
268
  - (BOOL)isPictureInPictureSupported {
161
- return [VeLivePictureInPictureController isPictureInPictureSupported];
269
+ return [VePictureInPictureController isPictureInPictureSupported];
162
270
  }
163
271
 
164
272
  - (void)enablePictureInPicture {
165
- NSLog(@"PIP: Enable picture-in-picture");
166
- self.pipAutoStart = YES;
167
- // main thread
273
+ _canStartPictureInPictureAutomaticallyFromInline = YES;
274
+ if (self.pipController != nil) {
275
+ if (@available(iOS 14.2, *)) {
276
+ self.pipController.canStartPictureInPictureAutomaticallyFromInline = YES;
277
+ }
278
+ }
168
279
  dispatch_async(dispatch_get_main_queue(), ^{
169
280
  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
- }];
281
+ [self ensurePipControllerReady:self.player completion:nil];
176
282
  }
177
283
  });
178
284
  }
179
285
 
180
286
  - (void)disablePictureInPicture {
181
- NSLog(@"PIP: Disable picture-in-picture");
182
- self.pipAutoStart = NO;
183
- if (!self.pipController) {
184
- return;
287
+ _canStartPictureInPictureAutomaticallyFromInline = NO;
288
+ if (self.pipController != nil) {
289
+ self.pipController.canStartPictureInPictureAutomaticallyFromInline = NO;
185
290
  }
186
291
  dispatch_async(dispatch_get_main_queue(), ^{
187
292
  if (@available(iOS 14.2, *)) {
188
- [self.pipController
189
- setCanStartPictureInPictureAutomaticallyFromInline:NO];
190
- [self.pipController destroyPictureInPicture];
191
- self.pipController = nil;
293
+ [self destroyPictureInPicture];
192
294
  }
193
295
  });
194
296
  }
@@ -201,73 +303,84 @@ NSString *const kObserverKey = @"pip-observer";
201
303
  - (void)onRenderVideoFrame:(TVLManager *_Nonnull)player
202
304
  videoFrame:(VeLivePlayerVideoFrame *_Nonnull)videoFrame {
203
305
  @autoreleasepool {
306
+ // 确保 pipController 存在且有效,避免在销毁过程中继续处理 buffer
307
+ if (!self.pipController || !self.enableVideoObserver) {
308
+ return;
309
+ }
310
+
204
311
  if (@available(iOS 15.0, *)) {
205
312
  if (videoFrame.bufferType == VeLivePlayerVideoBufferTypePixelBuffer) {
206
- [self.pipController enqueuePixelBuffer:videoFrame.pixelBuffer];
313
+ CVPixelBufferRef pixelBuffer = videoFrame.pixelBuffer;
314
+ if (pixelBuffer != NULL) {
315
+ [self.pipController enqueuePixelBuffer:pixelBuffer];
316
+ }
207
317
  } else if (videoFrame.bufferType ==
208
318
  VeLivePlayerVideoBufferTypeSampleBuffer) {
209
- [self.pipController enqueueSampleBuffer:videoFrame.sampleBuffer];
319
+ CMSampleBufferRef sampleBuffer = videoFrame.sampleBuffer;
320
+ if (sampleBuffer != NULL) {
321
+ [self.pipController enqueueSampleBuffer:sampleBuffer];
322
+ }
210
323
  }
211
324
  }
212
325
  }
213
326
  }
214
327
 
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
328
  - (void)onError:(TVLManager *)player error:(VeLivePlayerError *)error {
228
329
  NSLog(@"VeLiveQuickStartDemo: Error %ld, %@", error.code, error.errorMsg);
229
330
  }
230
331
 
231
- /// MARK: - VeLivePictureInPictureDelegate
232
- - (void)pictureInPictureIsReady:
233
- (VeLivePictureInPictureController *)pictureInPicture {
234
- NSLog(@"PIP: Picture-in-picture is ready");
235
- }
332
+ /// MARK: - VePictureInPictureDelegate
333
+ - (void)pictureInPictureController:
334
+ (VePictureInPictureController *)pictureInPictureController
335
+ statusChanged:(VePictureInPictureStatus)fromStatus
336
+ to:(VePictureInPictureStatus)toStatus {
337
+ switch (toStatus) {
338
+ case VePictureInPictureStatusIde: {
236
339
 
237
- - (void)pictureInPictureWillStart:
238
- (VeLivePictureInPictureController *)pictureInPicture {
239
- NSLog(@"PIP: Picture-in-picture will start...");
240
- }
340
+ } break;
341
+ case VePictureInPictureStatusPreparing: {
241
342
 
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];
343
+ } break;
344
+ case VePictureInPictureStatusReady: {
345
+ [self notifyPipControllerReady];
346
+ } break;
347
+ case VePictureInPictureStatusWillStart: {
348
+
349
+ } break;
350
+ case VePictureInPictureStatusDidStart: {
351
+ if (self.listener) {
352
+ [self.listener onStartPictureInPicture];
353
+ }
354
+ break;
355
+ case VePictureInPictureStatusWillChange: {
356
+
357
+ } break;
358
+ case VePictureInPictureStatusDidChange: {
359
+
360
+ } break;
361
+ case VePictureInPictureStatusRestoreUI: {
362
+
363
+ } break;
364
+ case VePictureInPictureStatusWillStop: {
365
+
366
+ } break;
367
+ case VePictureInPictureStatusDidStop: {
368
+ if (self.listener) {
369
+ [self.listener onStopPictureInPicture];
370
+ }
371
+ if (@available(iOS 14.2, *)) {
372
+ if (!self.canStartPictureInPictureAutomaticallyFromInline) {
373
+ [self destroyPictureInPicture];
374
+ }
375
+ }
376
+ } break;
377
+ case VePictureInPictureStatusError: {
378
+ if (self.listener) {
379
+ [self.listener onError:pictureInPictureController.error.code
380
+ extraData:pictureInPictureController.error.userInfo];
381
+ }
382
+ } break;
267
383
  }
268
- if (!self.pipAutoStart) {
269
- [self.pipController destroyPictureInPicture];
270
- self.pipController = nil;
271
384
  }
272
385
  }
273
386