[Video] More tweaks to `AVAudioSession` options (#4910)
parent
dd0d50a6f0
commit
5bfe5aa503
|
@ -1,6 +1,7 @@
|
||||||
import * as PlatformInfo from './src/PlatformInfo'
|
import * as PlatformInfo from './src/PlatformInfo'
|
||||||
|
import {AudioCategory} from './src/PlatformInfo/types'
|
||||||
import * as Referrer from './src/Referrer'
|
import * as Referrer from './src/Referrer'
|
||||||
import * as SharedPrefs from './src/SharedPrefs'
|
import * as SharedPrefs from './src/SharedPrefs'
|
||||||
import VisibilityView from './src/VisibilityView'
|
import VisibilityView from './src/VisibilityView'
|
||||||
|
|
||||||
export {PlatformInfo, Referrer, SharedPrefs, VisibilityView}
|
export {AudioCategory, PlatformInfo, Referrer, SharedPrefs, VisibilityView}
|
||||||
|
|
|
@ -8,14 +8,26 @@ public class ExpoPlatformInfoModule: Module {
|
||||||
return UIAccessibility.isReduceMotionEnabled
|
return UIAccessibility.isReduceMotionEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Function("setAudioCategory") { (audioCategoryString: String) in
|
||||||
|
let audioCategory = AVAudioSession.Category(rawValue: audioCategoryString)
|
||||||
|
try? AVAudioSession.sharedInstance().setCategory(audioCategory)
|
||||||
|
}
|
||||||
|
|
||||||
Function("setAudioMixWithOthers") { (mixWithOthers: Bool) in
|
Function("setAudioMixWithOthers") { (mixWithOthers: Bool) in
|
||||||
var options: AVAudioSession.CategoryOptions
|
var options: AVAudioSession.CategoryOptions
|
||||||
|
let currentCategory = AVAudioSession.sharedInstance().category
|
||||||
if mixWithOthers {
|
if mixWithOthers {
|
||||||
options = [.mixWithOthers]
|
options = [.mixWithOthers]
|
||||||
} else {
|
} else {
|
||||||
options = []
|
options = [.duckOthers]
|
||||||
}
|
}
|
||||||
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: options)
|
try? AVAudioSession
|
||||||
|
.sharedInstance()
|
||||||
|
.setCategory(
|
||||||
|
currentCategory,
|
||||||
|
mode: .default,
|
||||||
|
options: options
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {Platform} from 'react-native'
|
import {Platform} from 'react-native'
|
||||||
import {requireNativeModule} from 'expo-modules-core'
|
import {requireNativeModule} from 'expo-modules-core'
|
||||||
|
|
||||||
|
import {AudioCategory} from './types'
|
||||||
|
|
||||||
const NativeModule = requireNativeModule('ExpoPlatformInfo')
|
const NativeModule = requireNativeModule('ExpoPlatformInfo')
|
||||||
|
|
||||||
export function getIsReducedMotionEnabled(): boolean {
|
export function getIsReducedMotionEnabled(): boolean {
|
||||||
|
@ -11,3 +13,8 @@ export function setAudioMixWithOthers(mixWithOthers: boolean): void {
|
||||||
if (Platform.OS !== 'ios') return
|
if (Platform.OS !== 'ios') return
|
||||||
NativeModule.setAudioMixWithOthers(mixWithOthers)
|
NativeModule.setAudioMixWithOthers(mixWithOthers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setAudioCategory(audioCategory: AudioCategory): void {
|
||||||
|
if (Platform.OS !== 'ios') return
|
||||||
|
NativeModule.setAudioCategory(audioCategory)
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
import {NotImplementedError} from '../NotImplemented'
|
import {NotImplementedError} from '../NotImplemented'
|
||||||
|
import {AudioCategory} from './types'
|
||||||
|
|
||||||
export function getIsReducedMotionEnabled(): boolean {
|
export function getIsReducedMotionEnabled(): boolean {
|
||||||
throw new NotImplementedError()
|
throw new NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether the app's audio should mix with other apps' audio.
|
||||||
|
* @param mixWithOthers
|
||||||
|
*/
|
||||||
export function setAudioMixWithOthers(mixWithOthers: boolean): void {
|
export function setAudioMixWithOthers(mixWithOthers: boolean): void {
|
||||||
throw new NotImplementedError({mixWithOthers})
|
throw new NotImplementedError({mixWithOthers})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the audio category for the app.
|
||||||
|
* @param audioCategory
|
||||||
|
* @platform ios
|
||||||
|
*/
|
||||||
|
export function setAudioCategory(audioCategory: AudioCategory): void {
|
||||||
|
throw new NotImplementedError({audioCategory})
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {NotImplementedError} from '../NotImplemented'
|
import {NotImplementedError} from '../NotImplemented'
|
||||||
|
import {AudioCategory} from './types'
|
||||||
|
|
||||||
export function getIsReducedMotionEnabled(): boolean {
|
export function getIsReducedMotionEnabled(): boolean {
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
|
@ -10,3 +11,7 @@ export function getIsReducedMotionEnabled(): boolean {
|
||||||
export function setAudioMixWithOthers(mixWithOthers: boolean): void {
|
export function setAudioMixWithOthers(mixWithOthers: boolean): void {
|
||||||
throw new NotImplementedError({mixWithOthers})
|
throw new NotImplementedError({mixWithOthers})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setAudioCategory(audioCategory: AudioCategory): void {
|
||||||
|
throw new NotImplementedError({audioCategory})
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Sets the audio session category on iOS. In general, we should only need to use this for the `playback` and `ambient`
|
||||||
|
* categories. This enum however includes other categories that are available in the native API for clarity and
|
||||||
|
* potential future use.
|
||||||
|
* @see https://developer.apple.com/documentation/avfoundation/avaudiosession/category
|
||||||
|
* @platform ios
|
||||||
|
*/
|
||||||
|
export enum AudioCategory {
|
||||||
|
Ambient = 'AVAudioSessionCategoryAmbient',
|
||||||
|
Playback = 'AVAudioSessionCategoryPlayback',
|
||||||
|
_SoloAmbient = 'AVAudioSessionCategorySoloAmbient',
|
||||||
|
_Record = 'AVAudioSessionCategoryRecord',
|
||||||
|
_PlayAndRecord = 'AVAudioSessionCategoryPlayAndRecord',
|
||||||
|
_MultiRoute = 'AVAudioSessionCategoryMultiRoute',
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ import {Provider as PortalProvider} from '#/components/Portal'
|
||||||
import {Splash} from '#/Splash'
|
import {Splash} from '#/Splash'
|
||||||
import {Provider as TourProvider} from '#/tours'
|
import {Provider as TourProvider} from '#/tours'
|
||||||
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
||||||
import {PlatformInfo} from '../modules/expo-bluesky-swiss-army'
|
import {AudioCategory, PlatformInfo} from '../modules/expo-bluesky-swiss-army'
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync()
|
SplashScreen.preventAutoHideAsync()
|
||||||
|
|
||||||
|
@ -158,6 +158,7 @@ function App() {
|
||||||
const [isReady, setReady] = useState(false)
|
const [isReady, setReady] = useState(false)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
PlatformInfo.setAudioCategory(AudioCategory.Ambient)
|
||||||
PlatformInfo.setAudioMixWithOthers(true)
|
PlatformInfo.setAudioMixWithOthers(true)
|
||||||
initPersistedState().then(() => setReady(true))
|
initPersistedState().then(() => setReady(true))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
|
@ -12,7 +12,10 @@ import {android, atoms as a, useTheme} from '#/alf'
|
||||||
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
|
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
|
||||||
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {PlatformInfo} from '../../../../../../modules/expo-bluesky-swiss-army'
|
import {
|
||||||
|
AudioCategory,
|
||||||
|
PlatformInfo,
|
||||||
|
} from '../../../../../../modules/expo-bluesky-swiss-army'
|
||||||
|
|
||||||
export function VideoEmbedInnerNative() {
|
export function VideoEmbedInnerNative() {
|
||||||
const player = useVideoPlayer()
|
const player = useVideoPlayer()
|
||||||
|
@ -39,10 +42,12 @@ export function VideoEmbedInnerNative() {
|
||||||
style={a.flex_1}
|
style={a.flex_1}
|
||||||
nativeControls={true}
|
nativeControls={true}
|
||||||
onEnterFullscreen={() => {
|
onEnterFullscreen={() => {
|
||||||
|
PlatformInfo.setAudioCategory(AudioCategory.Playback)
|
||||||
PlatformInfo.setAudioMixWithOthers(false)
|
PlatformInfo.setAudioMixWithOthers(false)
|
||||||
player.muted = false
|
player.muted = false
|
||||||
}}
|
}}
|
||||||
onExitFullscreen={() => {
|
onExitFullscreen={() => {
|
||||||
|
PlatformInfo.setAudioCategory(AudioCategory.Ambient)
|
||||||
PlatformInfo.setAudioMixWithOthers(true)
|
PlatformInfo.setAudioMixWithOthers(true)
|
||||||
player.muted = true
|
player.muted = true
|
||||||
}}
|
}}
|
||||||
|
@ -96,12 +101,16 @@ function Controls({
|
||||||
}
|
}
|
||||||
}, [player])
|
}, [player])
|
||||||
|
|
||||||
const toggleSound = useCallback(() => {
|
const toggleMuted = useCallback(() => {
|
||||||
const newValue = !player.muted
|
const muted = !player.muted
|
||||||
// We want to set this to the _inverse_ of the new value, because we actually want for the audio to be mixed when
|
// We want to set this to the _inverse_ of the new value, because we actually want for the audio to be mixed when
|
||||||
// the video is muted, and vice versa.
|
// the video is muted, and vice versa.
|
||||||
PlatformInfo.setAudioMixWithOthers(!newValue)
|
const mix = !muted
|
||||||
player.muted = newValue
|
const category = muted ? AudioCategory.Ambient : AudioCategory.Playback
|
||||||
|
|
||||||
|
PlatformInfo.setAudioCategory(category)
|
||||||
|
PlatformInfo.setAudioMixWithOthers(mix)
|
||||||
|
player.muted = muted
|
||||||
}, [player])
|
}, [player])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -140,7 +149,7 @@ function Controls({
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
/>
|
/>
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={toggleSound}
|
onPress={toggleMuted}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
|
|
Loading…
Reference in New Issue