feat: add onVolumeChange event (#3322)

* feat: implement `onVolumeChange` event
This commit is contained in:
Krzysztof Moch 2023-11-04 18:11:54 +01:00 committed by GitHub
parent 50e0b33bf6
commit cdbc856387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 71 additions and 1 deletions

View File

@ -1,6 +1,7 @@
## Changelog ## Changelog
## Next ## Next
- Android, iOS: add onVolumeChange event #3322
### Version 6.0.0-alpha.9 ### Version 6.0.0-alpha.9
- All: add built-in typescript support [#3266](https://github.com/react-native-video/react-native-video/pull/3266) - All: add built-in typescript support [#3266](https://github.com/react-native-video/react-native-video/pull/3266)

View File

@ -50,6 +50,7 @@ public class VideoEventEmitter {
private static final String EVENT_AUDIO_BECOMING_NOISY = "onVideoAudioBecomingNoisy"; private static final String EVENT_AUDIO_BECOMING_NOISY = "onVideoAudioBecomingNoisy";
private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged"; private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged";
private static final String EVENT_PLAYBACK_RATE_CHANGE = "onPlaybackRateChange"; 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_AUDIO_TRACKS = "onAudioTracks";
private static final String EVENT_TEXT_TRACKS = "onTextTracks"; private static final String EVENT_TEXT_TRACKS = "onTextTracks";
private static final String EVENT_VIDEO_TRACKS = "onVideoTracks"; private static final String EVENT_VIDEO_TRACKS = "onVideoTracks";
@ -76,6 +77,7 @@ public class VideoEventEmitter {
EVENT_AUDIO_BECOMING_NOISY, EVENT_AUDIO_BECOMING_NOISY,
EVENT_AUDIO_FOCUS_CHANGE, EVENT_AUDIO_FOCUS_CHANGE,
EVENT_PLAYBACK_RATE_CHANGE, EVENT_PLAYBACK_RATE_CHANGE,
EVENT_VOLUME_CHANGE,
EVENT_AUDIO_TRACKS, EVENT_AUDIO_TRACKS,
EVENT_TEXT_TRACKS, EVENT_TEXT_TRACKS,
EVENT_VIDEO_TRACKS, EVENT_VIDEO_TRACKS,
@ -105,6 +107,7 @@ public class VideoEventEmitter {
EVENT_AUDIO_BECOMING_NOISY, EVENT_AUDIO_BECOMING_NOISY,
EVENT_AUDIO_FOCUS_CHANGE, EVENT_AUDIO_FOCUS_CHANGE,
EVENT_PLAYBACK_RATE_CHANGE, EVENT_PLAYBACK_RATE_CHANGE,
EVENT_VOLUME_CHANGE,
EVENT_AUDIO_TRACKS, EVENT_AUDIO_TRACKS,
EVENT_TEXT_TRACKS, EVENT_TEXT_TRACKS,
EVENT_VIDEO_TRACKS, EVENT_VIDEO_TRACKS,
@ -140,6 +143,7 @@ public class VideoEventEmitter {
private static final String EVENT_PROP_HAS_AUDIO_FOCUS = "hasAudioFocus"; 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_IS_BUFFERING = "isBuffering";
private static final String EVENT_PROP_PLAYBACK_RATE = "playbackRate"; 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 = "error";
private static final String EVENT_PROP_ERROR_STRING = "errorString"; private static final String EVENT_PROP_ERROR_STRING = "errorString";
@ -379,6 +383,11 @@ public class VideoEventEmitter {
receiveEvent(EVENT_PLAYBACK_RATE_CHANGE, map); 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) { public void timedMetadata(ArrayList<TimedMetadata> _metadataArrayList) {
if (_metadataArrayList.size() == 0) { if (_metadataArrayList.size() == 0) {

View File

@ -1434,6 +1434,11 @@ public class ReactExoplayerView extends FrameLayout implements
eventEmitter.playbackRateChange(params.speed); eventEmitter.playbackRateChange(params.speed);
} }
@Override
public void onVolumeChanged(float volume) {
eventEmitter.volumeChange(volume);
}
@Override @Override
public void onIsPlayingChanged(boolean isPlaying) { public void onIsPlayingChanged(boolean isPlaying) {
eventEmitter.playbackStateChanged(isPlaying); eventEmitter.playbackStateChanged(isPlaying);

View File

@ -29,6 +29,7 @@ This page shows the list of available callbacks to handle player notifications
| [onTimedMetadata](#ontimedmetadata) | Android, iOS | | [onTimedMetadata](#ontimedmetadata) | Android, iOS |
| [onTextTracks](#ontexttracks) | Android | | [onTextTracks](#ontexttracks) | Android |
| [onVideoTracks](#onvideotracks) | Android | | [onVideoTracks](#onvideotracks) | Android |
| [onVolumeChange](#onvolumechange) | Android, iOS |
## Details ## Details
@ -508,3 +509,22 @@ 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

View File

@ -19,6 +19,7 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc {
func handlePlaybackBufferKeyEmpty(playerItem:AVPlayerItem, change:NSKeyValueObservedChange<Bool>) func handlePlaybackBufferKeyEmpty(playerItem:AVPlayerItem, change:NSKeyValueObservedChange<Bool>)
func handlePlaybackLikelyToKeepUp(playerItem:AVPlayerItem, change:NSKeyValueObservedChange<Bool>) func handlePlaybackLikelyToKeepUp(playerItem:AVPlayerItem, change:NSKeyValueObservedChange<Bool>)
func handlePlaybackRateChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>) func handlePlaybackRateChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>)
func handleVolumeChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>)
func handleExternalPlaybackActiveChange(player: AVPlayer, change: NSKeyValueObservedChange<Bool>) func handleExternalPlaybackActiveChange(player: AVPlayer, change: NSKeyValueObservedChange<Bool>)
func handleViewControllerOverlayViewFrameChange(overlayView:UIView, change:NSKeyValueObservedChange<CGRect>) func handleViewControllerOverlayViewFrameChange(overlayView:UIView, change:NSKeyValueObservedChange<CGRect>)
} }
@ -74,6 +75,7 @@ class RCTPlayerObserver: NSObject {
private var _timeObserver:Any? private var _timeObserver:Any?
private var _playerRateChangeObserver:NSKeyValueObservation? private var _playerRateChangeObserver:NSKeyValueObservation?
private var _playerVolumeChangeObserver:NSKeyValueObservation?
private var _playerExternalPlaybackActiveObserver:NSKeyValueObservation? private var _playerExternalPlaybackActiveObserver:NSKeyValueObservation?
private var _playerItemStatusObserver:NSKeyValueObservation? private var _playerItemStatusObserver:NSKeyValueObservation?
private var _playerPlaybackBufferEmptyObserver:NSKeyValueObservation? private var _playerPlaybackBufferEmptyObserver:NSKeyValueObservation?
@ -95,6 +97,7 @@ class RCTPlayerObserver: NSObject {
} }
_playerRateChangeObserver = player.observe(\.rate, options: [.old], changeHandler: _handlers.handlePlaybackRateChange) _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) _playerExternalPlaybackActiveObserver = player.observe(\.isExternalPlaybackActive, changeHandler: _handlers.handleExternalPlaybackActiveChange)
} }

View File

@ -107,6 +107,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc var onPlaybackStalled: RCTDirectEventBlock? @objc var onPlaybackStalled: RCTDirectEventBlock?
@objc var onPlaybackResume: RCTDirectEventBlock? @objc var onPlaybackResume: RCTDirectEventBlock?
@objc var onPlaybackRateChange: RCTDirectEventBlock? @objc var onPlaybackRateChange: RCTDirectEventBlock?
@objc var onVolumeChange: RCTDirectEventBlock?
@objc var onVideoPlaybackStateChanged: RCTDirectEventBlock? @objc var onVideoPlaybackStateChanged: RCTDirectEventBlock?
@objc var onVideoExternalPlaybackChange: RCTDirectEventBlock? @objc var onVideoExternalPlaybackChange: RCTDirectEventBlock?
@objc var onPictureInPictureStatusChanged: RCTDirectEventBlock? @objc var onPictureInPictureStatusChanged: RCTDirectEventBlock?
@ -1238,6 +1239,17 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
} }
} }
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>) { func handleExternalPlaybackActiveChange(player: AVPlayer, change: NSKeyValueObservedChange<Bool>) {
guard let _player = _player else { return } guard let _player = _player else { return }
onVideoExternalPlaybackChange?(["isExternalPlaybackActive": NSNumber(value: _player.isExternalPlaybackActive), onVideoExternalPlaybackChange?(["isExternalPlaybackActive": NSNumber(value: _player.isExternalPlaybackActive),

View File

@ -57,6 +57,7 @@ RCT_EXPORT_VIEW_PROPERTY(onReadyForDisplay, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVolumeChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoPlaybackStateChanged, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoPlaybackStateChanged, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoExternalPlaybackChange, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoExternalPlaybackChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGetLicense, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onGetLicense, RCTDirectEventBlock);

View File

@ -82,6 +82,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onFullscreenPlayerDidDismiss, onFullscreenPlayerDidDismiss,
onReadyForDisplay, onReadyForDisplay,
onPlaybackRateChange, onPlaybackRateChange,
onVolumeChange,
onAudioBecomingNoisy, onAudioBecomingNoisy,
onPictureInPictureStatusChanged, onPictureInPictureStatusChanged,
onRestoreUserInterfaceForPictureInPictureStop, onRestoreUserInterfaceForPictureInPictureStop,
@ -344,6 +345,13 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
[onPlaybackRateChange], [onPlaybackRateChange],
); );
const _onVolumeChange = useCallback(
(e: NativeSyntheticEvent<Readonly<{volume: number}>>) => {
onVolumeChange?.(e.nativeEvent);
},
[onVolumeChange],
);
const _onReadyForDisplay = useCallback(() => { const _onReadyForDisplay = useCallback(() => {
setShowPoster(false); setShowPoster(false);
onReadyForDisplay?.(); onReadyForDisplay?.();
@ -509,6 +517,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onAudioFocusChanged={_onAudioFocusChanged} onAudioFocusChanged={_onAudioFocusChanged}
onReadyForDisplay={_onReadyForDisplay} onReadyForDisplay={_onReadyForDisplay}
onPlaybackRateChange={_onPlaybackRateChange} onPlaybackRateChange={_onPlaybackRateChange}
onVolumeChange={_onVolumeChange}
onVideoAudioBecomingNoisy={onAudioBecomingNoisy} onVideoAudioBecomingNoisy={onAudioBecomingNoisy}
onPictureInPictureStatusChanged={_onPictureInPictureStatusChanged} onPictureInPictureStatusChanged={_onPictureInPictureStatusChanged}
onRestoreUserInterfaceForPictureInPictureStop={ onRestoreUserInterfaceForPictureInPictureStop={

View File

@ -218,6 +218,10 @@ export type OnPlaybackData = Readonly<{
playbackRate: number; playbackRate: number;
}>; }>;
export type onVolumeChangeData = Readonly<{
volume: number;
}>;
export type OnExternalPlaybackChangeData = Readonly<{ export type OnExternalPlaybackChangeData = Readonly<{
isExternalPlaybackActive: boolean; isExternalPlaybackActive: boolean;
}>; }>;
@ -326,6 +330,7 @@ export interface VideoNativeProps extends ViewProps {
) => void; // ios, android ) => void; // ios, android
onReadyForDisplay?: (event: NativeSyntheticEvent<Readonly<object>>) => void; onReadyForDisplay?: (event: NativeSyntheticEvent<Readonly<object>>) => void;
onPlaybackRateChange?: (event: NativeSyntheticEvent<OnPlaybackData>) => void; // all onPlaybackRateChange?: (event: NativeSyntheticEvent<OnPlaybackData>) => void; // all
onVolumeChange?: (event: NativeSyntheticEvent<onVolumeChangeData>) => void; // android, ios
onVideoExternalPlaybackChange?: ( onVideoExternalPlaybackChange?: (
event: NativeSyntheticEvent<OnExternalPlaybackChangeData>, event: NativeSyntheticEvent<OnExternalPlaybackChangeData>,
) => void; ) => void;

View File

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