Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mute/unmute added (for iOS only) #346

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
24 changes: 24 additions & 0 deletions RCTYouTubeManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,30 @@ - (dispatch_queue_t)methodQueue {
}];
}

RCT_EXPORT_METHOD(mute:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
RCTYouTube *youtube = (RCTYouTube*)viewRegistry[reactTag];
if ([youtube isKindOfClass:[RCTYouTube class]]) {
[youtube mute];
} else {
RCTLogError(@"Cannot mute: %@ (tag #%@) is not RCTYouTube", youtube, reactTag);
}
}];
}

RCT_EXPORT_METHOD(unMute:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
RCTYouTube *youtube = (RCTYouTube*)viewRegistry[reactTag];
if ([youtube isKindOfClass:[RCTYouTube class]]) {
[youtube unMute];
} else {
RCTLogError(@"Cannot unMute: %@ (tag #%@) is not RCTYouTube", youtube, reactTag);
}
}];
}

RCT_EXPORT_METHOD(nextVideo:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ The iOS implementation of this player uses the official YouTube iFrame under the
* `currentTime()`: Returns a Promise that results with the `currentTime` of the played video (in seconds) or errors with an errorMessage string. Should be used as an alternative for Android to `onProgress` event on iOS.
* `duration()` *(Android)*: Returns a Promise that results with the `duration` of the played video (in seconds) or errors with an errorMessage string. Should be used as an alternative for Android to `onProgress` event on iOS.
* `reloadIframe()` *(iOS)*: Specific props (`fullscreen`, `modestbranding`, `showinfo`, `rel`, `controls`, `origin`) can only be set at mounting and initial loading of the underlying WebView that holds the YouTube iFrame (Those are `<iframe>` parameters). If you want to change one of them during the lifecycle of the component, you should know the usability cost of loading the WebView again, and use this method right after the component received the updated prop.
* `mute()` *(iOS)*: Mutes (sets volume to 0) current iframe.
* `unMute()` *(iOS)*: Unmutes (sets volume to 100) current iframe.

### Standalone Player (iOS)
#### Setup
Expand Down
20 changes: 20 additions & 0 deletions YTPlayerView/YTPlayerView.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,26 @@ typedef NS_ENUM(NSInteger, YTPlayerError) {
*/
- (void)seekToSeconds:(float)seekToSeconds allowSeekAhead:(BOOL)allowSeekAhead;

/**
* Mute
* the JavaScript API:
* https://developers.google.com/youtube/iframe_api_reference#seekTo
*
* @param mutes video.

*/
- (void)mute;

/**
* UnMute
* the JavaScript API:
* https://developers.google.com/youtube/iframe_api_reference#seekTo
*
* @param unmutes video.

*/
- (void)unMute;

#pragma mark - Queuing videos

// Queueing functions for videos. These methods correspond to their JavaScript
Expand Down
8 changes: 8 additions & 0 deletions YTPlayerView/YTPlayerView.m
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ - (void)seekToSeconds:(float)seekToSeconds allowSeekAhead:(BOOL)allowSeekAhead {
[self stringFromEvaluatingJavaScript:command];
}

- (void)mute {
[self stringFromEvaluatingJavaScript:@"player.mute();"];
}

- (void)unMute {
[self stringFromEvaluatingJavaScript:@"player.unMute();"];
}

#pragma mark - Cueing methods

- (void)cueVideoById:(NSString *)videoId
Expand Down
9 changes: 5 additions & 4 deletions YouTube.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,31 +128,32 @@ export default class YouTube extends React.Component {
seekTo(seconds) {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this._nativeComponentRef),
UIManager.ReactYouTube.Commands.seekTo,
UIManager.getViewManagerConfig('ReactYouTube').Commands.seekTo,
[parseInt(seconds, 10)],
);
}

nextVideo() {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this._nativeComponentRef),
UIManager.ReactYouTube.Commands.nextVideo,
UIManager.getViewManagerConfig('ReactYouTube').Commands.nextVideo,

[],
);
}

previousVideo() {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this._nativeComponentRef),
UIManager.ReactYouTube.Commands.previousVideo,
UIManager.getViewManagerConfig('ReactYouTube').Commands.previousVideo,
[],
);
}

playVideoAt(index) {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this._nativeComponentRef),
UIManager.ReactYouTube.Commands.playVideoAt,
UIManager.getViewManagerConfig('ReactYouTube').Commands.playVideoAt,
[parseInt(index, 10)],
);
}
Expand Down
52 changes: 41 additions & 11 deletions YouTube.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export default class YouTube extends React.Component {
controls: PropTypes.oneOf([0, 1, 2]),
showinfo: PropTypes.bool,
modestbranding: PropTypes.bool,
showFullscreenButton: PropTypes.bool,
rel: PropTypes.bool,
origin: PropTypes.string,
onError: PropTypes.func,
Expand All @@ -65,17 +64,24 @@ export default class YouTube extends React.Component {

constructor(props) {
super(props);
if (props.playsInline !== undefined) {
throw new Error(
'YouTube.ios.js: `playsInline` prop was dropped. Please use `fullscreen`',
);
}

// iOS uses a YouTube iFrame under the hood. We need to create its initial params
// for a quick and clean load. After the initial loading, props changes will interact
// with the iframe via its instance's methods so it won't need to load the iframe again.
this.state = { playerParams: parsePlayerParams(props) };
this.state = {
playerParams: parsePlayerParams(props),
};
}

shouldComponentUpdate() {
// Prevent unnecessary renders before the native component is ready to accept them
if (this._isReady) return true;
return false;
else return false;
}

_onError = event => {
Expand All @@ -95,49 +101,73 @@ export default class YouTube extends React.Component {
};

_onChangeQuality = event => {
if (this.props.onChangeQuality) this.props.onChangeQuality(event.nativeEvent);
if (this.props.onChangeQuality) {
this.props.onChangeQuality(event.nativeEvent);
}
};

_onChangeFullscreen = event => {
if (this.props.onChangeFullscreen) this.props.onChangeFullscreen(event.nativeEvent);
if (this.props.onChangeFullscreen)
this.props.onChangeFullscreen(event.nativeEvent);
};

_onProgress = event => {
if (this.props.onProgress) this.props.onProgress(event.nativeEvent);
};

seekTo(seconds) {
NativeModules.YouTubeManager.seekTo(ReactNative.findNodeHandle(this), parseInt(seconds, 10));
NativeModules.YouTubeManager.seekTo(
ReactNative.findNodeHandle(this),
parseInt(seconds, 10),
);
}

mute() {
NativeModules.YouTubeManager.mute(ReactNative.findNodeHandle(this));
}

unMute() {
NativeModules.YouTubeManager.unMute(ReactNative.findNodeHandle(this));
}

nextVideo() {
NativeModules.YouTubeManager.nextVideo(ReactNative.findNodeHandle(this));
}

previousVideo() {
NativeModules.YouTubeManager.previousVideo(ReactNative.findNodeHandle(this));
NativeModules.YouTubeManager.previousVideo(
ReactNative.findNodeHandle(this),
);
}

playVideoAt(index) {
NativeModules.YouTubeManager.playVideoAt(ReactNative.findNodeHandle(this), parseInt(index, 10));
NativeModules.YouTubeManager.playVideoAt(
ReactNative.findNodeHandle(this),
parseInt(index, 10),
);
}

videosIndex() {
// Avoid calling the native method if there is only one video loaded for sure
if ((Array.isArray(this.props.videoIds) && !this.props.videoIds[1]) || this.props.videoId) {
if (
(Array.isArray(this.props.videoIds) && !this.props.videoIds[1]) ||
this.props.videoId
) {
return Promise.resolve(0);
}

return new Promise((resolve, reject) =>
NativeModules.YouTubeManager.videosIndex(ReactNative.findNodeHandle(this))
NativeModules.YouTubeManager
.videosIndex(ReactNative.findNodeHandle(this))
.then(index => resolve(index))
.catch(errorMessage => reject(errorMessage)),
);
}

currentTime() {
return new Promise((resolve, reject) =>
NativeModules.YouTubeManager.currentTime(ReactNative.findNodeHandle(this))
NativeModules.YouTubeManager
.currentTime(ReactNative.findNodeHandle(this))
.then(currentTime => resolve(currentTime))
.catch(errorMessage => reject(errorMessage)),
);
Expand Down
Binary file added android/libs/OLD_YouTubeAndroidPlayerApi.jar
Binary file not shown.
Binary file modified android/libs/YouTubeAndroidPlayerApi.jar
Binary file not shown.
12 changes: 11 additions & 1 deletion assets/YTPlayerView-iframe-player.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,22 @@
}
}

window.setInterval(getCurrentTime, 500);
window.setInterval(getCurrentTime, 300);

});

function onReady(event) {
window.location.href = 'ytplayer://onReady?data=' + event.data;
window.setTimeout(function(){
try {
if(window.frames[0]){
var elements = window.frames[0].document.getElementsByClassName('ytp-chrome-top');
if(elements[0]){
elements[0].innerHTML = '';
}
}
} catch (e){}
}, 1)
}

function onStateChange(event) {
Expand Down