Skip to content

Commit

Permalink
feat: add onVolumeChange event (#3322)
Browse files Browse the repository at this point in the history
* feat: implement `onVolumeChange` event
  • Loading branch information
KrzysztofMoch authored Nov 4, 2023
1 parent 50e0b33 commit cdbc856
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Changelog

## Next
- Android, iOS: add onVolumeChange event #3322

### Version 6.0.0-alpha.9
- All: add built-in typescript support [#3266](https://github.com/react-native-video/react-native-video/pull/3266)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public VideoEventEmitter(ReactContext reactContext) {
private static final String EVENT_AUDIO_BECOMING_NOISY = "onVideoAudioBecomingNoisy";
private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged";
private static final String EVENT_PLAYBACK_RATE_CHANGE = "onPlaybackRateChange";
private static final String EVENT_VOLUME_CHANGE = "onVolumeChange";
private static final String EVENT_AUDIO_TRACKS = "onAudioTracks";
private static final String EVENT_TEXT_TRACKS = "onTextTracks";
private static final String EVENT_VIDEO_TRACKS = "onVideoTracks";
Expand All @@ -76,6 +77,7 @@ public VideoEventEmitter(ReactContext reactContext) {
EVENT_AUDIO_BECOMING_NOISY,
EVENT_AUDIO_FOCUS_CHANGE,
EVENT_PLAYBACK_RATE_CHANGE,
EVENT_VOLUME_CHANGE,
EVENT_AUDIO_TRACKS,
EVENT_TEXT_TRACKS,
EVENT_VIDEO_TRACKS,
Expand Down Expand Up @@ -105,6 +107,7 @@ public VideoEventEmitter(ReactContext reactContext) {
EVENT_AUDIO_BECOMING_NOISY,
EVENT_AUDIO_FOCUS_CHANGE,
EVENT_PLAYBACK_RATE_CHANGE,
EVENT_VOLUME_CHANGE,
EVENT_AUDIO_TRACKS,
EVENT_TEXT_TRACKS,
EVENT_VIDEO_TRACKS,
Expand Down Expand Up @@ -140,6 +143,7 @@ public VideoEventEmitter(ReactContext reactContext) {
private static final String EVENT_PROP_HAS_AUDIO_FOCUS = "hasAudioFocus";
private static final String EVENT_PROP_IS_BUFFERING = "isBuffering";
private static final String EVENT_PROP_PLAYBACK_RATE = "playbackRate";
private static final String EVENT_PROP_VOLUME = "volume";

private static final String EVENT_PROP_ERROR = "error";
private static final String EVENT_PROP_ERROR_STRING = "errorString";
Expand Down Expand Up @@ -379,6 +383,11 @@ public void playbackRateChange(float rate) {
receiveEvent(EVENT_PLAYBACK_RATE_CHANGE, map);
}

public void volumeChange(float volume) {
WritableMap map = Arguments.createMap();
map.putDouble(EVENT_PROP_VOLUME, volume);
receiveEvent(EVENT_VOLUME_CHANGE, map);
}

public void timedMetadata(ArrayList<TimedMetadata> _metadataArrayList) {
if (_metadataArrayList.size() == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,11 @@ public void onPlaybackParametersChanged(PlaybackParameters params) {
eventEmitter.playbackRateChange(params.speed);
}

@Override
public void onVolumeChanged(float volume) {
eventEmitter.volumeChange(volume);
}

@Override
public void onIsPlayingChanged(boolean isPlaying) {
eventEmitter.playbackStateChanged(isPlaying);
Expand Down
22 changes: 21 additions & 1 deletion docs/pages/component/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This page shows the list of available callbacks to handle player notifications
| [onTimedMetadata](#ontimedmetadata) | Android, iOS |
| [onTextTracks](#ontexttracks) | Android |
| [onVideoTracks](#onvideotracks) | Android |
| [onVolumeChange](#onvolumechange) | Android, iOS |


## Details
Expand Down Expand Up @@ -507,4 +508,23 @@ Example:
}
```

Platforms: Android
Platforms: Android

### `onVolumeChange`
Callback function that is called when the volume of player changes.
> Note: This event applies to the volume of the player, not the volume of the device.
Payload:

Property | Type | Description
--- | --- | ---
volume | number | The volume of the player (between 0 and 1)

Example:
```javascript
{
volume: 0.5
}
```

Platforms: Android, iOS
3 changes: 3 additions & 0 deletions ios/Video/Features/RCTPlayerObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc {
func handlePlaybackBufferKeyEmpty(playerItem:AVPlayerItem, change:NSKeyValueObservedChange<Bool>)
func handlePlaybackLikelyToKeepUp(playerItem:AVPlayerItem, change:NSKeyValueObservedChange<Bool>)
func handlePlaybackRateChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>)
func handleVolumeChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>)
func handleExternalPlaybackActiveChange(player: AVPlayer, change: NSKeyValueObservedChange<Bool>)
func handleViewControllerOverlayViewFrameChange(overlayView:UIView, change:NSKeyValueObservedChange<CGRect>)
}
Expand Down Expand Up @@ -74,6 +75,7 @@ class RCTPlayerObserver: NSObject {
private var _timeObserver:Any?

private var _playerRateChangeObserver:NSKeyValueObservation?
private var _playerVolumeChangeObserver:NSKeyValueObservation?
private var _playerExternalPlaybackActiveObserver:NSKeyValueObservation?
private var _playerItemStatusObserver:NSKeyValueObservation?
private var _playerPlaybackBufferEmptyObserver:NSKeyValueObservation?
Expand All @@ -95,6 +97,7 @@ class RCTPlayerObserver: NSObject {
}

_playerRateChangeObserver = player.observe(\.rate, options: [.old], changeHandler: _handlers.handlePlaybackRateChange)
_playerVolumeChangeObserver = player.observe(\.volume, options: [.old] ,changeHandler: _handlers.handleVolumeChange)
_playerExternalPlaybackActiveObserver = player.observe(\.isExternalPlaybackActive, changeHandler: _handlers.handleExternalPlaybackActiveChange)
}

Expand Down
12 changes: 12 additions & 0 deletions ios/Video/RCTVideo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc var onPlaybackStalled: RCTDirectEventBlock?
@objc var onPlaybackResume: RCTDirectEventBlock?
@objc var onPlaybackRateChange: RCTDirectEventBlock?
@objc var onVolumeChange: RCTDirectEventBlock?
@objc var onVideoPlaybackStateChanged: RCTDirectEventBlock?
@objc var onVideoExternalPlaybackChange: RCTDirectEventBlock?
@objc var onPictureInPictureStatusChanged: RCTDirectEventBlock?
Expand Down Expand Up @@ -1237,6 +1238,17 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
_playbackStalled = false
}
}

func handleVolumeChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>) {
guard let _player = _player else { return }

if(player.rate == change.oldValue && change.oldValue != nil) {
return
}

onVolumeChange?(["volume": NSNumber(value: _player.volume),
"target": reactTag as Any])
}

func handleExternalPlaybackActiveChange(player: AVPlayer, change: NSKeyValueObservedChange<Bool>) {
guard let _player = _player else { return }
Expand Down
1 change: 1 addition & 0 deletions ios/Video/RCTVideoManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ @interface RCT_EXTERN_MODULE(RCTVideoManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVolumeChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoPlaybackStateChanged, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoExternalPlaybackChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGetLicense, RCTDirectEventBlock);
Expand Down
9 changes: 9 additions & 0 deletions src/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onFullscreenPlayerDidDismiss,
onReadyForDisplay,
onPlaybackRateChange,
onVolumeChange,
onAudioBecomingNoisy,
onPictureInPictureStatusChanged,
onRestoreUserInterfaceForPictureInPictureStop,
Expand Down Expand Up @@ -344,6 +345,13 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
[onPlaybackRateChange],
);

const _onVolumeChange = useCallback(
(e: NativeSyntheticEvent<Readonly<{volume: number}>>) => {
onVolumeChange?.(e.nativeEvent);
},
[onVolumeChange],
);

const _onReadyForDisplay = useCallback(() => {
setShowPoster(false);
onReadyForDisplay?.();
Expand Down Expand Up @@ -509,6 +517,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onAudioFocusChanged={_onAudioFocusChanged}
onReadyForDisplay={_onReadyForDisplay}
onPlaybackRateChange={_onPlaybackRateChange}
onVolumeChange={_onVolumeChange}
onVideoAudioBecomingNoisy={onAudioBecomingNoisy}
onPictureInPictureStatusChanged={_onPictureInPictureStatusChanged}
onRestoreUserInterfaceForPictureInPictureStop={
Expand Down
5 changes: 5 additions & 0 deletions src/VideoNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ export type OnPlaybackData = Readonly<{
playbackRate: number;
}>;

export type onVolumeChangeData = Readonly<{
volume: number;
}>;

export type OnExternalPlaybackChangeData = Readonly<{
isExternalPlaybackActive: boolean;
}>;
Expand Down Expand Up @@ -326,6 +330,7 @@ export interface VideoNativeProps extends ViewProps {
) => void; // ios, android
onReadyForDisplay?: (event: NativeSyntheticEvent<Readonly<object>>) => void;
onPlaybackRateChange?: (event: NativeSyntheticEvent<OnPlaybackData>) => void; // all
onVolumeChange?: (event: NativeSyntheticEvent<onVolumeChangeData>) => void; // android, ios
onVideoExternalPlaybackChange?: (
event: NativeSyntheticEvent<OnExternalPlaybackChangeData>,
) => void;
Expand Down
5 changes: 5 additions & 0 deletions src/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ export type OnPlaybackData = Readonly<{
playbackRate: number;
}>;

export type OnVolumeChangeData = Readonly<{
volume: number;
}>;

export type OnExternalPlaybackChangeData = Readonly<{
isExternalPlaybackActive: boolean;
}>;
Expand Down Expand Up @@ -153,6 +157,7 @@ export interface ReactVideoEvents {
e: OnPictureInPictureStatusChangedData,
) => void; //iOS
onPlaybackRateChange?: (e: OnPlaybackData) => void; //All
onVolumeChange?: (e: OnVolumeChangeData) => void; //Android, iOS
onProgress?: (e: OnProgressData) => void; //All
onReadyForDisplay?: () => void; //Android, iOS
onReceiveAdEvent?: (e: OnReceiveAdEventData) => void; //Android, iOS
Expand Down

0 comments on commit cdbc856

Please sign in to comment.