Merge pull request #3211 from mysport12/master
Feature: audioOutput - Play over phone earpiece
This commit is contained in:
commit
0bf7f70e24
8
API.md
8
API.md
@ -294,6 +294,7 @@ var styles = StyleSheet.create({
|
||||
| [adTagUrl](#adTagUrl) | Android, iOS |
|
||||
| [allowsExternalPlayback](#allowsexternalplayback) | iOS |
|
||||
| [audioOnly](#audioonly) | All |
|
||||
| [audioOutput](#audioOutput) | Android, iOS |
|
||||
| [automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling) | iOS |
|
||||
| [backBufferDurationMs](#backBufferDurationMs) | Android |
|
||||
| [bufferConfig](#bufferconfig) | Android |
|
||||
@ -418,6 +419,13 @@ For this to work, the poster prop must be set.
|
||||
|
||||
Platforms: all
|
||||
|
||||
#### audioOutput
|
||||
Changes the audio output.
|
||||
* **speaker (default)** - plays through speaker
|
||||
* **earpiece** - plays through earpiece
|
||||
|
||||
Platforms: Android, iOS
|
||||
|
||||
#### automaticallyWaitsToMinimizeStalling
|
||||
A Boolean value that indicates whether the player should automatically delay playback in order to minimize stalling. For clients linked against iOS 10.0 and later
|
||||
* **false** - Immediately starts playback
|
||||
|
@ -1,5 +1,7 @@
|
||||
## Changelog
|
||||
|
||||
- Feature: playing audio over earpiece [#2887](https://github.com/react-native-video/react-native-video/issues/2887)
|
||||
|
||||
### Version 6.0.0-alpha.7
|
||||
- All: clean JS warnings (https://github.com/react-native-video/react-native-video/pull/3183)
|
||||
- Android: Add shutterView color configurtion (https://github.com/react-native-video/react-native-video/pull/3179)
|
||||
|
1
Video.js
1
Video.js
@ -515,6 +515,7 @@ Video.propTypes = {
|
||||
disableBuffering: PropTypes.bool,
|
||||
controls: PropTypes.bool,
|
||||
audioOnly: PropTypes.bool,
|
||||
audioOutput: PropTypes.oneOf(['earpiece', 'speaker']),
|
||||
fullscreenAutorotate: PropTypes.bool,
|
||||
fullscreenOrientation: PropTypes.oneOf(['all', 'landscape', 'portrait']),
|
||||
progressUpdateInterval: PropTypes.number,
|
||||
|
@ -0,0 +1,31 @@
|
||||
package com.brentvatne.exoplayer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
public enum AudioOutput {
|
||||
SPEAKER("speaker", C.STREAM_TYPE_MUSIC),
|
||||
EARPIECE("earpiece", C.STREAM_TYPE_VOICE_CALL);
|
||||
|
||||
private final int streamType;
|
||||
private final String mName;
|
||||
|
||||
AudioOutput(final String name, int stream) {
|
||||
mName = name;
|
||||
streamType = stream;
|
||||
}
|
||||
|
||||
public static AudioOutput get(String name) {
|
||||
for (AudioOutput d : values()) {
|
||||
if (d.mName.equalsIgnoreCase(name))
|
||||
return d;
|
||||
}
|
||||
return SPEAKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "(" + this.mName + ", " + streamType + ")";
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ import androidx.activity.OnBackPressedCallback;
|
||||
|
||||
import com.brentvatne.common.Track;
|
||||
import com.brentvatne.common.VideoTrack;
|
||||
import com.brentvatne.exoplayer.AudioOutput;
|
||||
import com.brentvatne.react.R;
|
||||
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
||||
import com.brentvatne.receiver.BecomingNoisyListener;
|
||||
@ -48,6 +49,7 @@ import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.Tracks;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
@ -162,6 +164,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private boolean muted = false;
|
||||
private boolean hasAudioFocus = false;
|
||||
private float rate = 1f;
|
||||
private AudioOutput audioOutput = AudioOutput.SPEAKER;
|
||||
private float audioVolume = 1f;
|
||||
private int minLoadRetryCount = 3;
|
||||
private int maxBitRate = 0;
|
||||
@ -653,6 +656,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
PlaybackParameters params = new PlaybackParameters(rate, 1f);
|
||||
player.setPlaybackParameters(params);
|
||||
changeAudioOutput(this.audioOutput);
|
||||
}
|
||||
|
||||
private DrmSessionManager initializePlayerDrm(ReactExoplayerView self) {
|
||||
@ -1819,6 +1823,29 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
private void changeAudioOutput(AudioOutput output) {
|
||||
if (player != null) {
|
||||
int usage = Util.getAudioUsageForStreamType(audioOutput.streamType);
|
||||
int contentType = Util.getAudioContentTypeForStreamType(audioOutput.streamType);
|
||||
AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(usage)
|
||||
.setContentType(contentType)
|
||||
.build();
|
||||
player.setAudioAttributes(audioAttributes, false);
|
||||
AudioManager audioManager = (AudioManager) themedReactContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.setMode(
|
||||
audioOutput == AudioOutput.SPEAKER ? AudioManager.MODE_NORMAL
|
||||
: AudioManager.MODE_IN_COMMUNICATION);
|
||||
audioManager.setSpeakerphoneOn(audioOutput == AudioOutput.SPEAKER);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAudioOutput(AudioOutput output) {
|
||||
if (audioOutput != output) {
|
||||
this.audioOutput = output;
|
||||
changeAudioOutput(output);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVolumeModifier(float volume) {
|
||||
audioVolume = volume;
|
||||
if (player != null) {
|
||||
|
@ -49,6 +49,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_TEXT_TRACKS = "textTracks";
|
||||
private static final String PROP_PAUSED = "paused";
|
||||
private static final String PROP_MUTED = "muted";
|
||||
private static final String PROP_AUDIO_OUTPUT = "audioOutput";
|
||||
private static final String PROP_VOLUME = "volume";
|
||||
private static final String PROP_BACK_BUFFER_DURATION_MS = "backBufferDurationMs";
|
||||
private static final String PROP_BUFFER_CONFIG = "bufferConfig";
|
||||
@ -277,6 +278,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setMutedModifier(muted);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_AUDIO_OUTPUT)
|
||||
public void setAudioOutput(final ReactExoplayerView videoView, final String audioOutput) {
|
||||
videoView.setAudioOutput(ReactExoplayerView.AudioOutput.get(audioOutput));
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_VOLUME, defaultFloat = 1.0f)
|
||||
public void setVolume(final ReactExoplayerView videoView, final float volume) {
|
||||
videoView.setVolumeModifier(volume);
|
||||
|
@ -197,7 +197,7 @@ enum RCTPlayerOperations {
|
||||
var options:AVAudioSession.CategoryOptions? = nil
|
||||
|
||||
if (ignoreSilentSwitch == "ignore") {
|
||||
category = AVAudioSession.Category.playback
|
||||
category = AVAudioSession.Category.playAndRecord
|
||||
} else if (ignoreSilentSwitch == "obey") {
|
||||
category = AVAudioSession.Category.ambient
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
private var _controls:Bool = false
|
||||
|
||||
/* Keep track of any modifiers, need to be applied after each play */
|
||||
private var _audioOutput: String = "speaker"
|
||||
private var _volume:Float = 1.0
|
||||
private var _rate:Float = 1.0
|
||||
private var _maxBitRate:Float?
|
||||
@ -517,6 +518,20 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
applyModifiers()
|
||||
}
|
||||
|
||||
@objc
|
||||
func setAudioOutput(_ audioOutput:String) {
|
||||
_audioOutput = audioOutput
|
||||
do {
|
||||
if audioOutput == "speaker" {
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
|
||||
} else if audioOutput == "earpiece" {
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.none)
|
||||
}
|
||||
} catch {
|
||||
print("Error occurred: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
func setVolume(_ volume:Float) {
|
||||
_volume = volume
|
||||
@ -587,6 +602,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
setMaxBitRate(_maxBitRate)
|
||||
}
|
||||
|
||||
setAudioOutput(_audioOutput)
|
||||
setSelectedAudioTrack(_selectedAudioTrackCriteria)
|
||||
setSelectedTextTrack(_selectedTextTrackCriteria)
|
||||
setResizeMode(_resizeMode)
|
||||
|
@ -17,6 +17,7 @@ RCT_EXPORT_VIEW_PROPERTY(selectedAudioTrack, NSDictionary);
|
||||
RCT_EXPORT_VIEW_PROPERTY(paused, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(controls, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(audioOutput, NSString);
|
||||
RCT_EXPORT_VIEW_PROPERTY(volume, float);
|
||||
RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(preventsDisplaySleepDuringVideoPlayback, BOOL);
|
||||
|
Loading…
Reference in New Issue
Block a user