Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion android/src/main/java/jp/manse/BrightcovePlayerManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
public class BrightcovePlayerManager extends SimpleViewManager<BrightcovePlayerView> {
public static final String REACT_CLASS = "BrightcovePlayer";
public static final int COMMAND_SEEK_TO = 1;
public static final int COMMAND_STOP_PLAYBACK = 2;
public static final String EVENT_READY = "ready";
public static final String EVENT_PLAY = "play";
public static final String EVENT_PAUSE = "pause";
Expand Down Expand Up @@ -108,7 +109,9 @@ public void setFullscreen(BrightcovePlayerView view, boolean fullscreen) {
public Map<String, Integer> getCommandsMap() {
return MapBuilder.of(
"seekTo",
COMMAND_SEEK_TO
COMMAND_SEEK_TO,
"stopPlayback",
COMMAND_STOP_PLAYBACK
);
}

Expand All @@ -121,6 +124,10 @@ public void receiveCommand(BrightcovePlayerView view, int commandType, @Nullable
view.seekTo((int)(args.getDouble(0) * 1000));
return;
}
case COMMAND_STOP_PLAYBACK:{
view.stopPlayback();
return;
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions android/src/main/java/jp/manse/BrightcovePlayerView.java
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ public void seekTo(int time) {
this.playerVideoView.seekTo(time);
}

//We need to stop the player to avoid a potential memory leak.
public void stopPlayback(){
if(this.playerVideoView != null){
this.playerVideoView.stopPlayback();
}
}

private void updateBitRate() {
if (this.bitRate == 0) return;
ExoPlayerVideoDisplayComponent videoDisplay = ((ExoPlayerVideoDisplayComponent) this.playerVideoView.getVideoDisplay());
Expand Down
101 changes: 67 additions & 34 deletions ios/BrightcovePlayer.m
Original file line number Diff line number Diff line change
@@ -1,34 +1,63 @@
#import "BrightcovePlayer.h"
#import "BrightcovePlayerOfflineVideoManager.h"
#import "BrightcovePlayerUtil.h"

@interface BrightcovePlayer () <BCOVPlaybackControllerDelegate, BCOVPUIPlayerViewDelegate>

@property NSString* loadedVideoToken;
@end

@implementation BrightcovePlayer

- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setup];
[self setupOfflineVideoTokenObserver];
}
return self;
}

- (void)dealloc
{
[NSNotificationCenter.defaultCenter removeObserver:self];
}

- (void)setupOfflineVideoTokenObserver {

[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didRemoveOfflineVideoToken:) name:BrightcovePlayerUtil.didRemoveOfflineVideoTokenNotificationName object:nil];
}

- (void)didRemoveOfflineVideoToken:(NSNotification*)notification {
NSDictionary *dict = notification.userInfo;
NSString* token = [dict valueForKey:BrightcovePlayerUtil.kDidRemoveOfflineVideoToken];

if ([self.loadedVideoToken isEqualToString:token]) {
NSLog(@"%@ %s TOKEN DELETED: %@", self, __FUNCTION__, token);
self.loadedVideoToken = nil;
}
}

- (void)setup {
_playbackController = [BCOVPlayerSDKManager.sharedManager createPlaybackController];
_playbackController.delegate = self;
_playbackController.autoPlay = NO;
_playbackController.autoAdvance = YES;

self.playbackController = [BCOVPlayerSDKManager.sharedManager createPlaybackController];
self.playbackController.delegate = self;
self.playbackController.autoPlay = NO;
self.playbackController.autoAdvance = YES;

_playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:self.playbackController options:nil controlsView:[BCOVPUIBasicControlView basicControlViewWithVODLayout] ];
_playerView.delegate = self;
_playerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_playerView.backgroundColor = UIColor.blackColor;
self.playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:self.playbackController options:nil controlsView:[BCOVPUIBasicControlView basicControlViewWithVODLayout] ];
self.playerView.delegate = self;
self.playerView.backgroundColor = UIColor.blackColor;

_targetVolume = 1.0;
_autoPlay = NO;
self.targetVolume = 1.0;
self.autoPlay = NO;

[self addSubview:_playerView];
[self addSubview:self.playerView];
self.playerView.translatesAutoresizingMaskIntoConstraints = NO;
NSArray* constraints = [NSArray arrayWithObjects:[self.playerView.topAnchor constraintEqualToAnchor:self.topAnchor],
[self.playerView.leftAnchor constraintEqualToAnchor:self.leftAnchor],
[self.playerView.rightAnchor constraintEqualToAnchor:self.rightAnchor],
[self.playerView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
nil];
[NSLayoutConstraint activateConstraints:constraints];
}

- (void)setupService {
Expand All @@ -39,27 +68,31 @@ - (void)setupService {
}

- (void)loadMovie {
if (_videoToken) {
BCOVVideo *video = [[BrightcovePlayerOfflineVideoManager sharedManager] videoObjectFromOfflineVideoToken:_videoToken];
if (video) {
[self.playbackController setVideos: @[ video ]];
}
return;
}
if (!_playbackService) return;
if (_videoId) {
[_playbackService findVideoWithVideoID:_videoId parameters:nil completion:^(BCOVVideo *video, NSDictionary *jsonResponse, NSError *error) {
if (video) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
if (self.videoToken) {
BCOVVideo *video = [[BrightcovePlayerOfflineVideoManager sharedManager] videoObjectFromOfflineVideoToken:self.videoToken];
if (video && ![self.loadedVideoToken isEqualToString:self.videoToken]) {
[self.playbackController setVideos: @[ video ]];
self.loadedVideoToken = video.properties[kBCOVOfflineVideoTokenPropertyKey];
NSLog(@"%@ %s SET VIDEO %@ FOR TOKEN: %@", self, __FUNCTION__, video.properties[kBCOVVideoPropertyKeyName], self.videoToken);
}
}];
} else if (_referenceId) {
[_playbackService findVideoWithReferenceID:_referenceId parameters:nil completion:^(BCOVVideo *video, NSDictionary *jsonResponse, NSError *error) {
if (video) {
[self.playbackController setVideos: @[ video ]];
}
}];
}
return;
}
if (!self.playbackService) return;
if (self.videoId) {
[self.playbackService findVideoWithVideoID:self.videoId parameters:nil completion:^(BCOVVideo *video, NSDictionary *jsonResponse, NSError *error) {
if (video) {
[self.playbackController setVideos: @[ video ]];
}
}];
} else if (self.referenceId) {
[self.playbackService findVideoWithReferenceID:self.referenceId parameters:nil completion:^(BCOVVideo *video, NSDictionary *jsonResponse, NSError *error) {
if (video) {
[self.playbackController setVideos: @[ video ]];
}
}];
}
});
}

- (id<BCOVPlaybackController>)createPlaybackController {
Expand Down Expand Up @@ -106,11 +139,11 @@ - (void)setAutoPlay:(BOOL)autoPlay {
}

- (void)setPlay:(BOOL)play {
if (_playing == play) return;
if (self.playing == play) return;
if (play) {
[_playbackController play];
[self.playbackController play];
} else {
[_playbackController pause];
[self.playbackController pause];
}
}

Expand Down
2 changes: 2 additions & 0 deletions ios/BrightcovePlayerUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@

@interface BrightcovePlayerUtil : RCTEventEmitter<RCTBridgeModule, BCOVOfflineVideoManagerDelegate>
@property (nonatomic) BCOVPlaybackService *playbackService;
+(NSString*)didRemoveOfflineVideoTokenNotificationName;
+(NSString*)kDidRemoveOfflineVideoToken;
@end
93 changes: 78 additions & 15 deletions ios/BrightcovePlayerUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@
static NSString *const kPlaylistName = @"name";
static NSString *const kPlaylistDescription = @"description";
static NSString *const kPlaylistDuration = @"duration";
static NSString *const didRemoveOfflineVideoTokenNotificationNameConst = @"DidRemoveOfflineVideoToken";
static NSString *const kdidRemoveOfflineVideoTokenConst = @"DidRemoveOfflineVideoToken";

@implementation BrightcovePlayerUtil {
bool hasListeners;
}

+(NSString*)didRemoveOfflineVideoTokenNotificationName {
return didRemoveOfflineVideoTokenNotificationNameConst;
}

+(NSString*)kDidRemoveOfflineVideoToken {
return kdidRemoveOfflineVideoTokenConst;
}

RCT_EXPORT_MODULE();

- (NSArray<NSString *> *)supportedEvents {
Expand All @@ -45,14 +55,39 @@ - (void)stopObserving {
reject(kErrorCode, error.description, error);
return;
}
[[BrightcovePlayerOfflineVideoManager sharedManager] requestVideoDownload:video parameters:[self generateDownloadParameterWithBitRate:bitRate] completion:^(BCOVOfflineVideoToken offlineVideoToken, NSError *error) {

AVURLAsset *avURLAsset = [[BrightcovePlayerOfflineVideoManager sharedManager] urlAssetForVideo:video error:nil];
// If mediaSelections is `nil` the SDK will default to the AVURLAsset's `preferredMediaSelection`
NSArray<AVMediaSelection *> *mediaSelections = nil;

if (@available(iOS 11.0, *)) {
mediaSelections = avURLAsset.allMediaSelections;

AVMediaSelectionGroup *legibleMediaSelectionGroup = [avURLAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
AVMediaSelectionGroup *audibleMediaSelectionGroup = [avURLAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];

int counter = 0;
for (AVMediaSelection *s in mediaSelections)
{
AVMediaSelectionOption *legibleMediaSelectionOption = [s selectedMediaOptionInMediaSelectionGroup:legibleMediaSelectionGroup];
AVMediaSelectionOption *audibleMediaSelectionOption = [s selectedMediaOptionInMediaSelectionGroup:audibleMediaSelectionGroup];

NSLog(@"AVMediaSelection option %i | legible display name: %@", counter, legibleMediaSelectionOption.displayName ?: @"nil");
NSLog(@"AVMediaSelection option %i | audible display name: %@", counter, audibleMediaSelectionOption.displayName ?: @"nil");

counter++;
}
}

[BrightcovePlayerOfflineVideoManager sharedManager].delegate = self;
[[BrightcovePlayerOfflineVideoManager sharedManager] requestVideoDownload:video mediaSelections:mediaSelections parameters:[self generateDownloadParameterWithBitRate:bitRate] completion:^(BCOVOfflineVideoToken offlineVideoToken, NSError *error) {
if (error) {
reject(kErrorCode, error.description, error);
return;
}
[NSUserDefaults.standardUserDefaults setObject: @{kUserDefaultKeyOfflineAccountId: accountId,
kUserDefaultKeyOfflineVideoId: video.properties[kBCOVVideoPropertyKeyId]
}
}
forKey:[kUserDefaultKeyOfflinePrefix stringByAppendingString:offlineVideoToken]];
[NSUserDefaults.standardUserDefaults synchronize];
[self sendOfflineNotification];
Expand All @@ -68,20 +103,43 @@ - (void)stopObserving {
reject(kErrorCode, error.description, error);
return;
}
[BrightcovePlayerOfflineVideoManager sharedManager].delegate = self;
[[BrightcovePlayerOfflineVideoManager sharedManager] requestVideoDownload:video parameters:[self generateDownloadParameterWithBitRate:bitRate] completion:^(BCOVOfflineVideoToken offlineVideoToken, NSError *error) {
if (error) {
reject(kErrorCode, error.description, error);
return;

AVURLAsset *avURLAsset = [[BrightcovePlayerOfflineVideoManager sharedManager] urlAssetForVideo:video error:nil];
// If mediaSelections is `nil` the SDK will default to the AVURLAsset's `preferredMediaSelection`
NSArray<AVMediaSelection *> *mediaSelections = nil;

if (@available(iOS 11.0, *)) {
mediaSelections = avURLAsset.allMediaSelections;;
AVMediaSelectionGroup *legibleMediaSelectionGroup = [avURLAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
AVMediaSelectionGroup *audibleMediaSelectionGroup = [avURLAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];

int counter = 0;
for (AVMediaSelection *s in mediaSelections)
{
AVMediaSelectionOption *legibleMediaSelectionOption = [s selectedMediaOptionInMediaSelectionGroup:legibleMediaSelectionGroup];
AVMediaSelectionOption *audibleMediaSelectionOption = [s selectedMediaOptionInMediaSelectionGroup:audibleMediaSelectionGroup];

NSLog(@"AVMediaSelection option %i | legible display name: %@", counter, legibleMediaSelectionOption.displayName ?: @"nil");
NSLog(@"AVMediaSelection option %i | audible display name: %@", counter, audibleMediaSelectionOption.displayName ?: @"nil");

counter++;
}
[NSUserDefaults.standardUserDefaults setObject: @{kUserDefaultKeyOfflineAccountId: accountId,
kUserDefaultKeyOfflineVideoId: video.properties[kBCOVVideoPropertyKeyId]
}
forKey:[kUserDefaultKeyOfflinePrefix stringByAppendingString:offlineVideoToken]];
[NSUserDefaults.standardUserDefaults synchronize];
[self sendOfflineNotification];
resolve(offlineVideoToken);
}];
}

[BrightcovePlayerOfflineVideoManager sharedManager].delegate = self;
[[BrightcovePlayerOfflineVideoManager sharedManager] requestVideoDownload:video mediaSelections:mediaSelections parameters:[self generateDownloadParameterWithBitRate:bitRate] completion:^(BCOVOfflineVideoToken offlineVideoToken, NSError *error) {
if (error) {
reject(kErrorCode, error.description, error);
return;
}
[NSUserDefaults.standardUserDefaults setObject: @{kUserDefaultKeyOfflineAccountId: accountId,
kUserDefaultKeyOfflineVideoId: video.properties[kBCOVVideoPropertyKeyId]
}
forKey:[kUserDefaultKeyOfflinePrefix stringByAppendingString:offlineVideoToken]];
[NSUserDefaults.standardUserDefaults synchronize];
[self sendOfflineNotification];
resolve(offlineVideoToken);
}];
}];
}

Expand All @@ -94,10 +152,15 @@ - (void)stopObserving {
reject(kErrorCode, kErrorMessageDelete, nil);
return;
}

BCOVVideo *video = [[BrightcovePlayerOfflineVideoManager sharedManager] videoObjectFromOfflineVideoToken:videoToken];
NSLog(@"%@ %s ATTEMPTING TO DELETE VIDEO %@ WITH TOKEN: %@", self, __FUNCTION__, video.properties[kBCOVVideoPropertyKeyName], videoToken);

[BrightcovePlayerOfflineVideoManager sharedManager].delegate = self;
[[BrightcovePlayerOfflineVideoManager sharedManager] cancelVideoDownload:videoToken];
[[BrightcovePlayerOfflineVideoManager sharedManager] deleteOfflineVideo:videoToken];
[NSUserDefaults.standardUserDefaults removeObjectForKey:[kUserDefaultKeyOfflinePrefix stringByAppendingString:videoToken]];
[NSNotificationCenter.defaultCenter postNotificationName:BrightcovePlayerUtil.didRemoveOfflineVideoTokenNotificationName object:nil userInfo:@{BrightcovePlayerUtil.kDidRemoveOfflineVideoToken: videoToken}];
[NSUserDefaults.standardUserDefaults synchronize];
[self sendOfflineNotification];
resolve(nil);
Expand Down
13 changes: 13 additions & 0 deletions src/BrightcovePlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ BrightcovePlayer.prototype.seekTo = Platform.select({
}
});

BrightcovePlayer.prototype.stopPlayback = Platform.select({
ios: function () {
//no method for ios
},
android: function () {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this._root),
UIManager.BrightcovePlayer.Commands.stopPlayback,
[]
);
}
});

BrightcovePlayer.propTypes = {
...(ViewPropTypes || View.propTypes),
policyKey: PropTypes.string,
Expand Down