@livekit/react-native 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -10
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/livekit/reactnative/video/SimulcastVideoEncoderFactoryWrapper.kt +2 -1
- package/ios/AudioUtils.h +9 -0
- package/ios/AudioUtils.m +48 -0
- package/ios/LivekitReactNative.m +45 -0
- package/ios/LivekitReactNative.xcodeproj/project.xcworkspace/xcuserdata/davidliu.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/lib/commonjs/audio/AudioManager.js +108 -0
- package/lib/commonjs/audio/AudioManager.js.map +1 -0
- package/lib/commonjs/audio/AudioSession.js +31 -0
- package/lib/commonjs/audio/AudioSession.js.map +1 -1
- package/lib/commonjs/index.js +71 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/logger.js +32 -0
- package/lib/commonjs/logger.js.map +1 -0
- package/lib/module/audio/AudioManager.js +92 -0
- package/lib/module/audio/AudioManager.js.map +1 -0
- package/lib/module/audio/AudioSession.js +29 -0
- package/lib/module/audio/AudioSession.js.map +1 -1
- package/lib/module/index.js +4 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/logger.js +18 -0
- package/lib/module/logger.js.map +1 -0
- package/lib/typescript/audio/AudioManager.d.ts +11 -0
- package/lib/typescript/audio/AudioSession.d.ts +13 -0
- package/lib/typescript/index.d.ts +5 -2
- package/lib/typescript/logger.d.ts +13 -0
- package/package.json +6 -5
- package/src/audio/AudioManager.ts +119 -0
- package/src/audio/AudioSession.ts +74 -0
- package/src/index.tsx +18 -0
- package/src/logger.ts +23 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { RoomEvent } from 'livekit-client';
|
|
4
|
+
import AudioSession, { getDefaultAppleAudioConfigurationForMode } from './AudioSession';
|
|
5
|
+
import { log } from '..';
|
|
6
|
+
/**
|
|
7
|
+
* Handles setting the appropriate AVAudioSession options automatically
|
|
8
|
+
* depending on the audio track states of the Room.
|
|
9
|
+
*
|
|
10
|
+
* @param room
|
|
11
|
+
* @param preferSpeakerOutput
|
|
12
|
+
* @param onConfigureNativeAudio A custom method for determining options used.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export function useIOSAudioManagement(room) {
|
|
16
|
+
let preferSpeakerOutput = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
17
|
+
let onConfigureNativeAudio = arguments.length > 2 ? arguments[2] : undefined;
|
|
18
|
+
const [localTrackCount, setLocalTrackCount] = useState(0);
|
|
19
|
+
const [remoteTrackCount, setRemoteTrackCount] = useState(0);
|
|
20
|
+
const trackState = useMemo(() => computeAudioTrackState(localTrackCount, remoteTrackCount), [localTrackCount, remoteTrackCount]);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (Platform.OS !== 'ios') {
|
|
23
|
+
return () => {};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
27
|
+
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
28
|
+
|
|
29
|
+
let onLocalPublished = () => {
|
|
30
|
+
setLocalTrackCount(localTrackCount + 1);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
let onLocalUnpublished = () => {
|
|
34
|
+
if (localTrackCount - 1 < 0) {
|
|
35
|
+
log.warn('mismatched local audio track count! attempted to reduce track count below zero.');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setLocalTrackCount(Math.max(localTrackCount - 1, 0));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let onRemotePublished = () => {
|
|
42
|
+
setRemoteTrackCount(remoteTrackCount + 1);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
let onRemoteUnpublished = () => {
|
|
46
|
+
if (remoteTrackCount - 1 < 0) {
|
|
47
|
+
log.warn('mismatched remote audio track count! attempted to reduce track count below zero.');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setRemoteTrackCount(Math.max(remoteTrackCount - 1, 0));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
room.on(RoomEvent.LocalTrackPublished, onLocalPublished).on(RoomEvent.LocalTrackUnpublished, onLocalUnpublished).on(RoomEvent.TrackPublished, onRemotePublished).on(RoomEvent.TrackUnpublished, onRemoteUnpublished);
|
|
54
|
+
return () => {
|
|
55
|
+
room.off(RoomEvent.LocalTrackPublished, onLocalPublished).off(RoomEvent.LocalTrackUnpublished, onLocalUnpublished).off(RoomEvent.TrackPublished, onRemotePublished).off(RoomEvent.TrackUnpublished, onRemoteUnpublished);
|
|
56
|
+
};
|
|
57
|
+
}, [room, localTrackCount, remoteTrackCount]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (Platform.OS !== 'ios') {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let configFunc = onConfigureNativeAudio !== null && onConfigureNativeAudio !== void 0 ? onConfigureNativeAudio : getDefaultAppleAudioConfigurationForMode;
|
|
64
|
+
let audioConfig = configFunc(trackState, preferSpeakerOutput);
|
|
65
|
+
AudioSession.setAppleAudioConfiguration(audioConfig);
|
|
66
|
+
}, [trackState, onConfigureNativeAudio, preferSpeakerOutput]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function computeAudioTrackState(localTracks, remoteTracks) {
|
|
70
|
+
if (localTracks > 0 && remoteTracks > 0) {
|
|
71
|
+
return 'localAndRemote';
|
|
72
|
+
} else if (localTracks > 0 && remoteTracks === 0) {
|
|
73
|
+
return 'localOnly';
|
|
74
|
+
} else if (localTracks === 0 && remoteTracks > 0) {
|
|
75
|
+
return 'remoteOnly';
|
|
76
|
+
} else {
|
|
77
|
+
return 'none';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getLocalAudioTrackCount(room) {
|
|
82
|
+
return room.localParticipant.audioTracks.entries.length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getRemoteAudioTrackCount(room) {
|
|
86
|
+
var audioTracks = 0;
|
|
87
|
+
room.participants.forEach(participant => {
|
|
88
|
+
audioTracks += participant.audioTracks.entries.length;
|
|
89
|
+
});
|
|
90
|
+
return audioTracks;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=AudioManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["AudioManager.ts"],"names":["useState","useEffect","useMemo","Platform","RoomEvent","AudioSession","getDefaultAppleAudioConfigurationForMode","log","useIOSAudioManagement","room","preferSpeakerOutput","onConfigureNativeAudio","localTrackCount","setLocalTrackCount","remoteTrackCount","setRemoteTrackCount","trackState","computeAudioTrackState","OS","getLocalAudioTrackCount","getRemoteAudioTrackCount","onLocalPublished","onLocalUnpublished","warn","Math","max","onRemotePublished","onRemoteUnpublished","on","LocalTrackPublished","LocalTrackUnpublished","TrackPublished","TrackUnpublished","off","configFunc","audioConfig","setAppleAudioConfiguration","localTracks","remoteTracks","localParticipant","audioTracks","entries","length","participants","forEach","participant"],"mappings":"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","sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { Platform } from 'react-native';\nimport { RoomEvent, type Room } from 'livekit-client';\nimport AudioSession, {\n getDefaultAppleAudioConfigurationForMode,\n type AppleAudioConfiguration,\n type AudioTrackState,\n} from './AudioSession';\nimport { log } from '..';\n\n/**\n * Handles setting the appropriate AVAudioSession options automatically\n * depending on the audio track states of the Room.\n *\n * @param room\n * @param preferSpeakerOutput\n * @param onConfigureNativeAudio A custom method for determining options used.\n */\nexport function useIOSAudioManagement(\n room: Room,\n preferSpeakerOutput: boolean = true,\n onConfigureNativeAudio?: (\n trackState: AudioTrackState,\n preferSpeakerOutput: boolean\n ) => AppleAudioConfiguration\n) {\n const [localTrackCount, setLocalTrackCount] = useState(0);\n const [remoteTrackCount, setRemoteTrackCount] = useState(0);\n const trackState = useMemo(\n () => computeAudioTrackState(localTrackCount, remoteTrackCount),\n [localTrackCount, remoteTrackCount]\n );\n\n useEffect(() => {\n if (Platform.OS !== 'ios') {\n return () => {};\n }\n\n setLocalTrackCount(getLocalAudioTrackCount(room));\n setRemoteTrackCount(getRemoteAudioTrackCount(room));\n\n let onLocalPublished = () => {\n setLocalTrackCount(localTrackCount + 1);\n };\n let onLocalUnpublished = () => {\n if (localTrackCount - 1 < 0) {\n log.warn(\n 'mismatched local audio track count! attempted to reduce track count below zero.'\n );\n }\n setLocalTrackCount(Math.max(localTrackCount - 1, 0));\n };\n let onRemotePublished = () => {\n setRemoteTrackCount(remoteTrackCount + 1);\n };\n let onRemoteUnpublished = () => {\n if (remoteTrackCount - 1 < 0) {\n log.warn(\n 'mismatched remote audio track count! attempted to reduce track count below zero.'\n );\n }\n setRemoteTrackCount(Math.max(remoteTrackCount - 1, 0));\n };\n\n room\n .on(RoomEvent.LocalTrackPublished, onLocalPublished)\n .on(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)\n .on(RoomEvent.TrackPublished, onRemotePublished)\n .on(RoomEvent.TrackUnpublished, onRemoteUnpublished);\n\n return () => {\n room\n .off(RoomEvent.LocalTrackPublished, onLocalPublished)\n .off(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)\n .off(RoomEvent.TrackPublished, onRemotePublished)\n .off(RoomEvent.TrackUnpublished, onRemoteUnpublished);\n };\n }, [room, localTrackCount, remoteTrackCount]);\n\n useEffect(() => {\n if (Platform.OS !== 'ios') {\n return;\n }\n\n let configFunc =\n onConfigureNativeAudio ?? getDefaultAppleAudioConfigurationForMode;\n let audioConfig = configFunc(trackState, preferSpeakerOutput);\n\n AudioSession.setAppleAudioConfiguration(audioConfig);\n }, [trackState, onConfigureNativeAudio, preferSpeakerOutput]);\n}\n\nfunction computeAudioTrackState(\n localTracks: number,\n remoteTracks: number\n): AudioTrackState {\n if (localTracks > 0 && remoteTracks > 0) {\n return 'localAndRemote';\n } else if (localTracks > 0 && remoteTracks === 0) {\n return 'localOnly';\n } else if (localTracks === 0 && remoteTracks > 0) {\n return 'remoteOnly';\n } else {\n return 'none';\n }\n}\n\nfunction getLocalAudioTrackCount(room: Room): number {\n return room.localParticipant.audioTracks.entries.length;\n}\n\nfunction getRemoteAudioTrackCount(room: Room): number {\n var audioTracks = 0;\n room.participants.forEach((participant) => {\n audioTracks += participant.audioTracks.entries.length;\n });\n\n return audioTracks;\n}\n"]}
|
|
@@ -57,6 +57,29 @@ export const AndroidAudioTypePresets = {
|
|
|
57
57
|
audioAttributesContentType: 'unknown'
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
|
+
export function getDefaultAppleAudioConfigurationForMode(mode) {
|
|
61
|
+
let preferSpeakerOutput = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
62
|
+
|
|
63
|
+
if (mode === 'remoteOnly') {
|
|
64
|
+
return {
|
|
65
|
+
audioCategory: 'playback',
|
|
66
|
+
audioCategoryOptions: ['mixWithOthers'],
|
|
67
|
+
audioMode: 'spokenAudio'
|
|
68
|
+
};
|
|
69
|
+
} else if (mode === 'localAndRemote' || mode === 'localOnly') {
|
|
70
|
+
return {
|
|
71
|
+
audioCategory: 'playAndRecord',
|
|
72
|
+
audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],
|
|
73
|
+
audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat'
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
audioCategory: 'soloAmbient',
|
|
79
|
+
audioCategoryOptions: [],
|
|
80
|
+
audioMode: 'default'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
60
83
|
export default class AudioSession {}
|
|
61
84
|
|
|
62
85
|
_defineProperty(AudioSession, "configureAudio", async config => {
|
|
@@ -90,4 +113,10 @@ _defineProperty(AudioSession, "showAudioRoutePicker", async () => {
|
|
|
90
113
|
await LivekitReactNative.showAudioRoutePicker();
|
|
91
114
|
}
|
|
92
115
|
});
|
|
116
|
+
|
|
117
|
+
_defineProperty(AudioSession, "setAppleAudioConfiguration", async config => {
|
|
118
|
+
if (Platform.OS === 'ios') {
|
|
119
|
+
await LivekitReactNative.setAppleAudioConfiguration(config);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
93
122
|
//# sourceMappingURL=AudioSession.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["AudioSession.ts"],"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","LivekitReactNative","Proxy","get","Error","AndroidAudioTypePresets","communication","manageAudioFocus","audioMode","audioFocusMode","audioStreamType","audioAttributesUsageType","audioAttributesContentType","media","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker"],"mappings":";;AAAA,SAASA,aAAT,EAAwBC,QAAxB,QAAwC,cAAxC;AACA,MAAMC,aAAa,GAChB,gFAAD,GACAD,QAAQ,CAACE,MAAT,CAAgB;AAAEC,EAAAA,GAAG,EAAE,gCAAP;AAAyCC,EAAAA,OAAO,EAAE;AAAlD,CAAhB,CADA,GAEA,sDAFA,GAGA,6CAJF;AAMA,MAAMC,kBAAkB,GAAGN,aAAa,CAACM,kBAAd,GACvBN,aAAa,CAACM,kBADS,GAEvB,IAAIC,KAAJ,CACE,EADF,EAEE;AACEC,EAAAA,GAAG,GAAG;AACJ,UAAM,IAAIC,KAAJ,CAAUP,aAAV,CAAN;AACD;;AAHH,CAFF,CAFJ;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA6GA,OAAO,MAAMQ,uBASZ,GAAG;AACFC,EAAAA,aAAa,EAAE;AACbC,IAAAA,gBAAgB,EAAE,IADL;AAEbC,IAAAA,SAAS,EAAE,iBAFE;AAGbC,IAAAA,cAAc,EAAE,MAHH;AAIbC,IAAAA,eAAe,EAAE,WAJJ;AAKbC,IAAAA,wBAAwB,EAAE,oBALb;AAMbC,IAAAA,0BAA0B,EAAE;AANf,GADb;AASFC,EAAAA,KAAK,EAAE;AACLN,IAAAA,gBAAgB,EAAE,IADb;AAELC,IAAAA,SAAS,EAAE,QAFN;AAGLC,IAAAA,cAAc,EAAE,MAHX;AAILC,IAAAA,eAAe,EAAE,OAJZ;AAKLC,IAAAA,wBAAwB,EAAE,OALrB;AAMLC,IAAAA,0BAA0B,EAAE;AANvB;AATL,CATG;AA4BP,eAAe,MAAME,YAAN,CAAmB;;gBAAbA,Y,oBAMK,MAAOC,MAAP,IAAsC;AAC5D,QAAMd,kBAAkB,CAACe,cAAnB,CAAkCD,MAAlC,CAAN;AACD,C;;gBARkBD,Y,uBAaQ,YAAY;AACrC,QAAMb,kBAAkB,CAACgB,iBAAnB,EAAN;AACD,C;;gBAfkBH,Y,sBAoBO,YAAY;AACpC,QAAMb,kBAAkB,CAACiB,gBAAnB,EAAN;AACD,C;;gBAtBkBJ,Y,qBAgDM,YAA+B;AACtD,MAAIlB,QAAQ,CAACuB,EAAT,KAAgB,KAApB,EAA2B;AACzB,WAAO,CAAC,SAAD,EAAY,eAAZ,CAAP;AACD,GAFD,MAEO,IAAIvB,QAAQ,CAACuB,EAAT,KAAgB,SAApB,EAA+B;AACpC,WAAQ,MAAMlB,kBAAkB,CAACmB,eAAnB,EAAd;AACD,GAFM,MAEA;AACL,WAAO,EAAP;AACD;AACF,C;;gBAxDkBN,Y,uBAiEQ,MAAOO,QAAP,IAA4B;AACrD,QAAMpB,kBAAkB,CAACqB,iBAAnB,CAAqCD,QAArC,CAAN;AACD,C;;gBAnEkBP,Y,0BA0EW,YAAY;AACxC,MAAIlB,QAAQ,CAACuB,EAAT,KAAgB,KAApB,EAA2B;AACzB,UAAMlB,kBAAkB,CAACsB,oBAAnB,EAAN;AACD;AACF,C","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LivekitReactNative = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\n/**\n * Configuration for the underlying AudioSession.\n *\n * ----\n * Android specific options:\n *\n * * preferredOutputList - The preferred order in which to automatically select an audio output.\n * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.\n *\n * By default, the order is set to:\n * 1. `\"bluetooth\"\n * 2. `\"headset\"``\n * 3. `\"speaker\"`\n * 4. `\"earpiece\"`\n *\n * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the\n * audio options to use on Android.\n *\n * See {@link AndroidAudioTypePresets} for pre-configured values.\n *\n * ----\n * iOS\n *\n * * defaultOutput - The default preferred output to use when a wired headset or bluetooth output is unavailable.\n *\n * By default, this is set to `\"speaker\"`\n */\nexport type AudioConfiguration = {\n android?: {\n preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];\n audioTypeOptions: AndroidAudioTypeOptions;\n };\n ios?: {\n defaultOutput?: 'speaker' | 'earpiece';\n };\n};\n\nexport type AndroidAudioTypeOptions = {\n /**\n * Whether LiveKit should handle managing the audio focus or not.\n *\n * Defaults to true.\n */\n manageAudioFocus?: boolean;\n\n /**\n * Corresponds to {@link https://developer.android.com/reference/android/media/AudioManager#setMode(int)}\n *\n * Defaults to 'inCommunication'.\n */\n audioMode?:\n | 'normal'\n | 'callScreening'\n | 'inCall'\n | 'inCommunication'\n | 'ringtone';\n\n /**\n * Corresponds to the duration hint when requesting audio focus.\n *\n * Defaults to 'gain'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN}\n */\n audioFocusMode?:\n | 'gain'\n | 'gainTransient'\n | 'gainTransientExclusive'\n | 'gainTransientMayDuck';\n\n /**\n * Corresponds to Android's AudioAttributes usage type.\n *\n * Defaults to 'voiceCommunication'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesUsageType?:\n | 'alarm'\n | 'assistanceAccessibility'\n | 'assistanceNavigationGuidance'\n | 'assistanceSonification'\n | 'assistant'\n | 'game'\n | 'media'\n | 'notification'\n | 'notificationEvent'\n | 'notificationRingtone'\n | 'unknown'\n | 'voiceCommunication'\n | 'voiceCommunicationSignalling';\n\n /**\n * Corresponds to Android's AndroidAttributes content type.\n *\n * Defaults to 'speech'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesContentType?:\n | 'movie'\n | 'music'\n | 'sonification'\n | 'speech'\n | 'unknown';\n\n /**\n * Corresponds to the stream type when requesting audio focus. Used on pre-O devices.\n *\n * Defaults to 'voiceCall'\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL}\n */\n audioStreamType?:\n | 'accessibility'\n | 'alarm'\n | 'dtmf'\n | 'music'\n | 'notification'\n | 'ring'\n | 'system'\n | 'voiceCall';\n\n /**\n * On certain Android devices, audio routing does not function properly and\n * bluetooth microphones will not work unless audio mode is set to\n * `inCommunication` or `inCall`. Audio routing is turned off those cases.\n *\n * If this set to true, will attempt to do audio routing regardless of audio mode.\n *\n * Defaults to false.\n */\n forceHandleAudioRouting?: boolean;\n};\n\nexport const AndroidAudioTypePresets: {\n /**\n * A pre-configured AndroidAudioConfiguration for voice communication.\n */\n communication: AndroidAudioTypeOptions;\n /**\n * A pre-configured AndroidAudioConfiguration for media playback.\n */\n media: AndroidAudioTypeOptions;\n} = {\n communication: {\n manageAudioFocus: true,\n audioMode: 'inCommunication',\n audioFocusMode: 'gain',\n audioStreamType: 'voiceCall',\n audioAttributesUsageType: 'voiceCommunication',\n audioAttributesContentType: 'speech',\n },\n media: {\n manageAudioFocus: true,\n audioMode: 'normal',\n audioFocusMode: 'gain',\n audioStreamType: 'music',\n audioAttributesUsageType: 'media',\n audioAttributesContentType: 'unknown',\n },\n} as const;\n\nexport default class AudioSession {\n /**\n * Applies the provided audio configuration to the underlying AudioSession.\n *\n * Must be called prior to connecting to a Room for the configuration to apply correctly.\n */\n static configureAudio = async (config: AudioConfiguration) => {\n await LivekitReactNative.configureAudio(config);\n };\n\n /**\n * Starts an AudioSession.\n */\n static startAudioSession = async () => {\n await LivekitReactNative.startAudioSession();\n };\n\n /**\n * Stops the existing AudioSession.\n */\n static stopAudioSession = async () => {\n await LivekitReactNative.stopAudioSession();\n };\n\n /**\n * Gets the available audio outputs for use with {@link selectAudioOutput}.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * For Android, will return if available:\n * * \"speaker\"\n * * \"earpiece\"\n * * \"headset\"\n * * \"bluetooth\"\n *\n * ----\n *\n * For iOS, due to OS limitations, the only available types are:\n * * \"default\" - Use default iOS audio routing\n * * \"force_speaker\" - Force audio output through speaker\n *\n * See also {@link showAudioRoutePicker} to display a route picker that\n * can choose between other audio devices (i.e. headset/bluetooth/airplay),\n * or use a library like `react-native-avroutepicker` for a native platform\n * control.\n *\n * @returns the available audio output types\n */\n static getAudioOutputs = async (): Promise<string[]> => {\n if (Platform.OS === 'ios') {\n return ['default', 'force_speaker'];\n } else if (Platform.OS === 'android') {\n return (await LivekitReactNative.getAudioOutputs()) as string[];\n } else {\n return [];\n }\n };\n\n /**\n * Select the provided audio output if available.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * @param deviceId A deviceId retrieved from {@link getAudioOutputs}\n */\n static selectAudioOutput = async (deviceId: string) => {\n await LivekitReactNative.selectAudioOutput(deviceId);\n };\n\n /**\n * iOS only, requires iOS 11+.\n *\n * Displays an AVRoutePickerView for the user to choose their audio output.\n */\n static showAudioRoutePicker = async () => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.showAudioRoutePicker();\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["AudioSession.ts"],"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","LivekitReactNative","Proxy","get","Error","AndroidAudioTypePresets","communication","manageAudioFocus","audioMode","audioFocusMode","audioStreamType","audioAttributesUsageType","audioAttributesContentType","media","getDefaultAppleAudioConfigurationForMode","mode","preferSpeakerOutput","audioCategory","audioCategoryOptions","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker","setAppleAudioConfiguration"],"mappings":"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","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LivekitReactNative = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\n/**\n * Configuration for the underlying AudioSession.\n *\n * ----\n * Android specific options:\n *\n * * preferredOutputList - The preferred order in which to automatically select an audio output.\n * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.\n *\n * By default, the order is set to:\n * 1. `\"bluetooth\"\n * 2. `\"headset\"``\n * 3. `\"speaker\"`\n * 4. `\"earpiece\"`\n *\n * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the\n * audio options to use on Android.\n *\n * See {@link AndroidAudioTypePresets} for pre-configured values.\n *\n * ----\n * iOS\n *\n * * defaultOutput - The default preferred output to use when a wired headset or bluetooth output is unavailable.\n *\n * By default, this is set to `\"speaker\"`\n */\nexport type AudioConfiguration = {\n android?: {\n preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];\n audioTypeOptions: AndroidAudioTypeOptions;\n };\n ios?: {\n defaultOutput?: 'speaker' | 'earpiece';\n };\n};\n\nexport type AndroidAudioTypeOptions = {\n /**\n * Whether LiveKit should handle managing the audio focus or not.\n *\n * Defaults to true.\n */\n manageAudioFocus?: boolean;\n\n /**\n * Corresponds to {@link https://developer.android.com/reference/android/media/AudioManager#setMode(int)}\n *\n * Defaults to 'inCommunication'.\n */\n audioMode?:\n | 'normal'\n | 'callScreening'\n | 'inCall'\n | 'inCommunication'\n | 'ringtone';\n\n /**\n * Corresponds to the duration hint when requesting audio focus.\n *\n * Defaults to 'gain'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN}\n */\n audioFocusMode?:\n | 'gain'\n | 'gainTransient'\n | 'gainTransientExclusive'\n | 'gainTransientMayDuck';\n\n /**\n * Corresponds to Android's AudioAttributes usage type.\n *\n * Defaults to 'voiceCommunication'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesUsageType?:\n | 'alarm'\n | 'assistanceAccessibility'\n | 'assistanceNavigationGuidance'\n | 'assistanceSonification'\n | 'assistant'\n | 'game'\n | 'media'\n | 'notification'\n | 'notificationEvent'\n | 'notificationRingtone'\n | 'unknown'\n | 'voiceCommunication'\n | 'voiceCommunicationSignalling';\n\n /**\n * Corresponds to Android's AndroidAttributes content type.\n *\n * Defaults to 'speech'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesContentType?:\n | 'movie'\n | 'music'\n | 'sonification'\n | 'speech'\n | 'unknown';\n\n /**\n * Corresponds to the stream type when requesting audio focus. Used on pre-O devices.\n *\n * Defaults to 'voiceCall'\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL}\n */\n audioStreamType?:\n | 'accessibility'\n | 'alarm'\n | 'dtmf'\n | 'music'\n | 'notification'\n | 'ring'\n | 'system'\n | 'voiceCall';\n\n /**\n * On certain Android devices, audio routing does not function properly and\n * bluetooth microphones will not work unless audio mode is set to\n * `inCommunication` or `inCall`. Audio routing is turned off those cases.\n *\n * If this set to true, will attempt to do audio routing regardless of audio mode.\n *\n * Defaults to false.\n */\n forceHandleAudioRouting?: boolean;\n};\n\nexport const AndroidAudioTypePresets: {\n /**\n * A pre-configured AndroidAudioConfiguration for voice communication.\n */\n communication: AndroidAudioTypeOptions;\n /**\n * A pre-configured AndroidAudioConfiguration for media playback.\n */\n media: AndroidAudioTypeOptions;\n} = {\n communication: {\n manageAudioFocus: true,\n audioMode: 'inCommunication',\n audioFocusMode: 'gain',\n audioStreamType: 'voiceCall',\n audioAttributesUsageType: 'voiceCommunication',\n audioAttributesContentType: 'speech',\n },\n media: {\n manageAudioFocus: true,\n audioMode: 'normal',\n audioFocusMode: 'gain',\n audioStreamType: 'music',\n audioAttributesUsageType: 'media',\n audioAttributesContentType: 'unknown',\n },\n} as const;\n\nexport type AppleAudioMode =\n | 'default'\n | 'gameChat'\n | 'measurement'\n | 'moviePlayback'\n | 'spokenAudio'\n | 'videoChat'\n | 'videoRecording'\n | 'voiceChat'\n | 'voicePrompt';\n\nexport type AppleAudioCategory =\n | 'soloAmbient'\n | 'playback'\n | 'record'\n | 'playAndRecord'\n | 'multiRoute';\n\nexport type AppleAudioCategoryOption =\n | 'mixWithOthers'\n | 'duckOthers'\n | 'interruptSpokenAudioAndMixWithOthers'\n | 'allowBluetooth'\n | 'allowBluetoothA2DP'\n | 'allowAirPlay'\n | 'defaultToSpeaker';\n\nexport type AppleAudioConfiguration = {\n audioCategory?: AppleAudioCategory;\n audioCategoryOptions?: AppleAudioCategoryOption[];\n audioMode?: AppleAudioMode;\n};\n\nexport type AudioTrackState =\n | 'none'\n | 'remoteOnly'\n | 'localOnly'\n | 'localAndRemote';\n\nexport function getDefaultAppleAudioConfigurationForMode(\n mode: AudioTrackState,\n preferSpeakerOutput: boolean = true\n): AppleAudioConfiguration {\n if (mode === 'remoteOnly') {\n return {\n audioCategory: 'playback',\n audioCategoryOptions: ['mixWithOthers'],\n audioMode: 'spokenAudio',\n };\n } else if (mode === 'localAndRemote' || mode === 'localOnly') {\n return {\n audioCategory: 'playAndRecord',\n audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],\n audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat',\n };\n }\n\n return {\n audioCategory: 'soloAmbient',\n audioCategoryOptions: [],\n audioMode: 'default',\n };\n}\n\nexport default class AudioSession {\n /**\n * Applies the provided audio configuration to the underlying AudioSession.\n *\n * Must be called prior to connecting to a Room for the configuration to apply correctly.\n *\n * See also useIOSAudioManagement for automatic configuration of iOS audio options.\n */\n static configureAudio = async (config: AudioConfiguration) => {\n await LivekitReactNative.configureAudio(config);\n };\n\n /**\n * Starts an AudioSession.\n */\n static startAudioSession = async () => {\n await LivekitReactNative.startAudioSession();\n };\n\n /**\n * Stops the existing AudioSession.\n */\n static stopAudioSession = async () => {\n await LivekitReactNative.stopAudioSession();\n };\n\n /**\n * Gets the available audio outputs for use with {@link selectAudioOutput}.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * For Android, will return if available:\n * * \"speaker\"\n * * \"earpiece\"\n * * \"headset\"\n * * \"bluetooth\"\n *\n * ----\n *\n * For iOS, due to OS limitations, the only available types are:\n * * \"default\" - Use default iOS audio routing\n * * \"force_speaker\" - Force audio output through speaker\n *\n * See also {@link showAudioRoutePicker} to display a route picker that\n * can choose between other audio devices (i.e. headset/bluetooth/airplay),\n * or use a library like `react-native-avroutepicker` for a native platform\n * control.\n *\n * @returns the available audio output types\n */\n static getAudioOutputs = async (): Promise<string[]> => {\n if (Platform.OS === 'ios') {\n return ['default', 'force_speaker'];\n } else if (Platform.OS === 'android') {\n return (await LivekitReactNative.getAudioOutputs()) as string[];\n } else {\n return [];\n }\n };\n\n /**\n * Select the provided audio output if available.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * @param deviceId A deviceId retrieved from {@link getAudioOutputs}\n */\n static selectAudioOutput = async (deviceId: string) => {\n await LivekitReactNative.selectAudioOutput(deviceId);\n };\n\n /**\n * iOS only, requires iOS 11+.\n *\n * Displays an AVRoutePickerView for the user to choose their audio output.\n */\n static showAudioRoutePicker = async () => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.showAudioRoutePicker();\n }\n };\n\n static setAppleAudioConfiguration = async (\n config: AppleAudioConfiguration\n ) => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.setAppleAudioConfiguration(config);\n }\n };\n}\n"]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';
|
|
2
2
|
import { setupURLPolyfill } from 'react-native-url-polyfill';
|
|
3
3
|
import 'fastestsmallesttextencoderdecoder';
|
|
4
|
-
import AudioSession, { AndroidAudioTypePresets, AndroidAudioTypeOptions } from './audio/AudioSession';
|
|
4
|
+
import AudioSession, { AndroidAudioTypePresets, AndroidAudioTypeOptions, AppleAudioCategory, AppleAudioCategoryOption, AppleAudioConfiguration, AppleAudioMode, AudioTrackState, getDefaultAppleAudioConfigurationForMode } from './audio/AudioSession';
|
|
5
5
|
import { PixelRatio, Platform } from 'react-native';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -77,5 +77,7 @@ function shimIterator() {
|
|
|
77
77
|
export * from './components/VideoView';
|
|
78
78
|
export * from './useParticipant';
|
|
79
79
|
export * from './useRoom';
|
|
80
|
-
export
|
|
80
|
+
export * from './logger';
|
|
81
|
+
export * from './audio/AudioManager';
|
|
82
|
+
export { AudioSession, AndroidAudioTypeOptions, AndroidAudioTypePresets, AppleAudioCategory, AppleAudioCategoryOption, AppleAudioConfiguration, AppleAudioMode, AudioTrackState, getDefaultAppleAudioConfigurationForMode };
|
|
81
83
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["index.tsx"],"names":["registerGlobals","webrtcRegisterGlobals","setupURLPolyfill","AudioSession","AndroidAudioTypePresets","AndroidAudioTypeOptions","PixelRatio","Platform","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","shimAsyncIterator","shimIterator","lkGlobal","platform","OS","devicePixelRatio","get","global","LiveKitReactNativeGlobal","window","navigator","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at"],"mappings":"AAAA,SAASA,eAAe,IAAIC,qBAA5B,QAAyD,8BAAzD;AACA,SAASC,gBAAT,QAAiC,2BAAjC;AACA,OAAO,mCAAP;AACA,OAAOC,YAAP,IACEC,uBADF,EAEEC,uBAFF,
|
|
1
|
+
{"version":3,"sources":["index.tsx"],"names":["registerGlobals","webrtcRegisterGlobals","setupURLPolyfill","AudioSession","AndroidAudioTypePresets","AndroidAudioTypeOptions","AppleAudioCategory","AppleAudioCategoryOption","AppleAudioConfiguration","AppleAudioMode","AudioTrackState","getDefaultAppleAudioConfigurationForMode","PixelRatio","Platform","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","shimAsyncIterator","shimIterator","lkGlobal","platform","OS","devicePixelRatio","get","global","LiveKitReactNativeGlobal","window","navigator","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at"],"mappings":"AAAA,SAASA,eAAe,IAAIC,qBAA5B,QAAyD,8BAAzD;AACA,SAASC,gBAAT,QAAiC,2BAAjC;AACA,OAAO,mCAAP;AACA,OAAOC,YAAP,IACEC,uBADF,EAEEC,uBAFF,EAGEC,kBAHF,EAIEC,wBAJF,EAKEC,uBALF,EAMEC,cANF,EAOEC,eAPF,EAQEC,wCARF,QASO,sBATP;AAWA,SAASC,UAAT,EAAqBC,QAArB,QAAqC,cAArC;;AAIA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASb,eAAT,GAA2B;AAChCC,EAAAA,qBAAqB;AACrBa,EAAAA,sBAAsB;AACtBZ,EAAAA,gBAAgB;AAChBa,EAAAA,gBAAgB;AAChBC,EAAAA,qBAAqB;AACrBC,EAAAA,WAAW;AACXC,EAAAA,iBAAiB;AACjBC,EAAAA,YAAY;AACb;;AACD,SAASL,sBAAT,GAAkC;AAChC,MAAIM,QAAgC,GAAG;AACrCC,IAAAA,QAAQ,EAAER,QAAQ,CAACS,EADkB;AAErCC,IAAAA,gBAAgB,EAAEX,UAAU,CAACY,GAAX;AAFmB,GAAvC,CADgC,CAMhC;;AACAC,EAAAA,MAAM,CAACC,wBAAP,GAAkCN,QAAlC;AACD;;AAED,SAASL,gBAAT,GAA4B;AAAA;;AAC1B;AACA,MAAI,YAAAY,MAAM,UAAN,0CAAQC,SAAR,MAAsBC,SAA1B,EAAqC;AACnC;AACA,UAAM;AAAED,MAAAA;AAAF,QAAgBD,MAAtB;;AACA,QAAIC,SAAS,CAACE,SAAV,KAAwBD,SAA5B,EAAuC;AAAA;;AACrCD,MAAAA,SAAS,CAACE,SAAV,yBAAsBF,SAAS,CAACG,OAAhC,mEAA2C,SAA3C;AACD;AACF;AACF;;AAED,SAASf,qBAAT,GAAiC;AAC/B,MAAIgB,UAAU,GAAGC,OAAO,CAAC,oBAAD,CAAxB;;AACAD,EAAAA,UAAU,CAACE,IAAX;AACD;;AAED,SAASjB,WAAT,GAAuB;AACrB;AACA,MAAI,CAACkB,KAAK,CAACC,SAAN,CAAgBC,EAArB,EAAyB;AACvB,QAAIA,EAAE,GAAGJ,OAAO,CAAC,oBAAD,CAAhB;;AACAI,IAAAA,EAAE,CAACH,IAAH;AACD;AACF;;AAED,SAAShB,iBAAT,GAA6B;AAC3B,MAAIgB,IAAI,GAAGD,OAAO,CAAC,8CAAD,CAAlB;;AACAC,EAAAA,IAAI;AACL;;AAED,SAASf,YAAT,GAAwB;AACtB,MAAIe,IAAI,GAAGD,OAAO,CAAC,yCAAD,CAAlB;;AACAC,EAAAA,IAAI;AACL;;AAED,cAAc,wBAAd;AACA,cAAc,kBAAd;AACA,cAAc,WAAd;AACA,cAAc,UAAd;AACA,cAAc,sBAAd;AAEA,SACE/B,YADF,EAGEE,uBAHF,EAIED,uBAJF,EAKEE,kBALF,EAMEC,wBANF,EAOEC,uBAPF,EAQEC,cARF,EASEC,eATF,EAUEC,wCAVF","sourcesContent":["import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport 'fastestsmallesttextencoderdecoder';\nimport AudioSession, {\n AndroidAudioTypePresets,\n AndroidAudioTypeOptions,\n AppleAudioCategory,\n AppleAudioCategoryOption,\n AppleAudioConfiguration,\n AppleAudioMode,\n AudioTrackState,\n getDefaultAppleAudioConfigurationForMode,\n} from './audio/AudioSession';\nimport type { AudioConfiguration } from './audio/AudioSession';\nimport { PixelRatio, Platform } from 'react-native';\nimport type { LiveKitReactNativeInfo } from 'livekit-client';\nimport type { LogLevel, SetLogLevelOptions } from './logger';\n\n/**\n * Registers the required globals needed for LiveKit to work.\n *\n * Must be called before using LiveKit.\n */\nexport function registerGlobals() {\n webrtcRegisterGlobals();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n shimAsyncIterator();\n shimIterator();\n}\nfunction livekitRegisterGlobals() {\n let lkGlobal: LiveKitReactNativeInfo = {\n platform: Platform.OS,\n devicePixelRatio: PixelRatio.get(),\n };\n\n // @ts-ignore\n global.LiveKitReactNativeGlobal = lkGlobal;\n}\n\nfunction fixWebrtcAdapter() {\n // @ts-ignore\n if (window?.navigator !== undefined) {\n // @ts-ignore\n const { navigator } = window;\n if (navigator.userAgent === undefined) {\n navigator.userAgent = navigator.product ?? 'Unknown';\n }\n }\n}\n\nfunction shimPromiseAllSettled() {\n var allSettled = require('promise.allsettled');\n allSettled.shim();\n}\n\nfunction shimArrayAt() {\n // Some versions of RN don't have Array.prototype.at, which is used by sdp-transform\n if (!Array.prototype.at) {\n var at = require('array.prototype.at');\n at.shim();\n }\n}\n\nfunction shimAsyncIterator() {\n var shim = require('well-known-symbols/Symbol.asyncIterator/shim');\n shim();\n}\n\nfunction shimIterator() {\n var shim = require('well-known-symbols/Symbol.iterator/shim');\n shim();\n}\n\nexport * from './components/VideoView';\nexport * from './useParticipant';\nexport * from './useRoom';\nexport * from './logger';\nexport * from './audio/AudioManager';\n\nexport {\n AudioSession,\n AudioConfiguration,\n AndroidAudioTypeOptions,\n AndroidAudioTypePresets,\n AppleAudioCategory,\n AppleAudioCategoryOption,\n AppleAudioConfiguration,\n AppleAudioMode,\n AudioTrackState,\n getDefaultAppleAudioConfigurationForMode,\n LogLevel,\n SetLogLevelOptions,\n};\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { setLogLevel as setClientSdkLogLevel } from 'livekit-client';
|
|
2
|
+
import loglevel from 'loglevel';
|
|
3
|
+
export const log = loglevel.getLogger('lk-react-native');
|
|
4
|
+
log.setDefaultLevel('WARN');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set the log level for both the `@livekit/react-native` package and the `@livekit-client` package.
|
|
8
|
+
* To set the `@livekit-client` log independently, use the `liveKitClientLogLevel` prop on the `options` object.
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export function setLogLevel(level) {
|
|
12
|
+
var _options$liveKitClien;
|
|
13
|
+
|
|
14
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
15
|
+
log.setLevel(level);
|
|
16
|
+
setClientSdkLogLevel((_options$liveKitClien = options.liveKitClientLogLevel) !== null && _options$liveKitClien !== void 0 ? _options$liveKitClien : level);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["logger.ts"],"names":["setLogLevel","setClientSdkLogLevel","loglevel","log","getLogger","setDefaultLevel","level","options","setLevel","liveKitClientLogLevel"],"mappings":"AAAA,SAASA,WAAW,IAAIC,oBAAxB,QAAoD,gBAApD;AACA,OAAOC,QAAP,MAAqB,UAArB;AAEA,OAAO,MAAMC,GAAG,GAAGD,QAAQ,CAACE,SAAT,CAAmB,iBAAnB,CAAZ;AACPD,GAAG,CAACE,eAAJ,CAAoB,MAApB;;AAOA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASL,WAAT,CACLM,KADK,EAGC;AAAA;;AAAA,MADNC,OACM,uEADwB,EACxB;AACNJ,EAAAA,GAAG,CAACK,QAAJ,CAAaF,KAAb;AACAL,EAAAA,oBAAoB,0BAACM,OAAO,CAACE,qBAAT,yEAAkCH,KAAlC,CAApB;AACD","sourcesContent":["import { setLogLevel as setClientSdkLogLevel } from 'livekit-client';\nimport loglevel from 'loglevel';\n\nexport const log = loglevel.getLogger('lk-react-native');\nlog.setDefaultLevel('WARN');\n\nexport type LogLevel = Parameters<typeof setClientSdkLogLevel>[0];\nexport type SetLogLevelOptions = {\n liveKitClientLogLevel?: LogLevel;\n};\n\n/**\n * Set the log level for both the `@livekit/react-native` package and the `@livekit-client` package.\n * To set the `@livekit-client` log independently, use the `liveKitClientLogLevel` prop on the `options` object.\n * @public\n */\nexport function setLogLevel(\n level: LogLevel,\n options: SetLogLevelOptions = {}\n): void {\n log.setLevel(level);\n setClientSdkLogLevel(options.liveKitClientLogLevel ?? level);\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Room } from 'livekit-client';
|
|
2
|
+
import { type AppleAudioConfiguration, type AudioTrackState } from './AudioSession';
|
|
3
|
+
/**
|
|
4
|
+
* Handles setting the appropriate AVAudioSession options automatically
|
|
5
|
+
* depending on the audio track states of the Room.
|
|
6
|
+
*
|
|
7
|
+
* @param room
|
|
8
|
+
* @param preferSpeakerOutput
|
|
9
|
+
* @param onConfigureNativeAudio A custom method for determining options used.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useIOSAudioManagement(room: Room, preferSpeakerOutput?: boolean, onConfigureNativeAudio?: (trackState: AudioTrackState, preferSpeakerOutput: boolean) => AppleAudioConfiguration): void;
|
|
@@ -100,11 +100,23 @@ export declare const AndroidAudioTypePresets: {
|
|
|
100
100
|
*/
|
|
101
101
|
media: AndroidAudioTypeOptions;
|
|
102
102
|
};
|
|
103
|
+
export declare type AppleAudioMode = 'default' | 'gameChat' | 'measurement' | 'moviePlayback' | 'spokenAudio' | 'videoChat' | 'videoRecording' | 'voiceChat' | 'voicePrompt';
|
|
104
|
+
export declare type AppleAudioCategory = 'soloAmbient' | 'playback' | 'record' | 'playAndRecord' | 'multiRoute';
|
|
105
|
+
export declare type AppleAudioCategoryOption = 'mixWithOthers' | 'duckOthers' | 'interruptSpokenAudioAndMixWithOthers' | 'allowBluetooth' | 'allowBluetoothA2DP' | 'allowAirPlay' | 'defaultToSpeaker';
|
|
106
|
+
export declare type AppleAudioConfiguration = {
|
|
107
|
+
audioCategory?: AppleAudioCategory;
|
|
108
|
+
audioCategoryOptions?: AppleAudioCategoryOption[];
|
|
109
|
+
audioMode?: AppleAudioMode;
|
|
110
|
+
};
|
|
111
|
+
export declare type AudioTrackState = 'none' | 'remoteOnly' | 'localOnly' | 'localAndRemote';
|
|
112
|
+
export declare function getDefaultAppleAudioConfigurationForMode(mode: AudioTrackState, preferSpeakerOutput?: boolean): AppleAudioConfiguration;
|
|
103
113
|
export default class AudioSession {
|
|
104
114
|
/**
|
|
105
115
|
* Applies the provided audio configuration to the underlying AudioSession.
|
|
106
116
|
*
|
|
107
117
|
* Must be called prior to connecting to a Room for the configuration to apply correctly.
|
|
118
|
+
*
|
|
119
|
+
* See also useIOSAudioManagement for automatic configuration of iOS audio options.
|
|
108
120
|
*/
|
|
109
121
|
static configureAudio: (config: AudioConfiguration) => Promise<void>;
|
|
110
122
|
/**
|
|
@@ -154,4 +166,5 @@ export default class AudioSession {
|
|
|
154
166
|
* Displays an AVRoutePickerView for the user to choose their audio output.
|
|
155
167
|
*/
|
|
156
168
|
static showAudioRoutePicker: () => Promise<void>;
|
|
169
|
+
static setAppleAudioConfiguration: (config: AppleAudioConfiguration) => Promise<void>;
|
|
157
170
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'fastestsmallesttextencoderdecoder';
|
|
2
|
-
import AudioSession, { AndroidAudioTypePresets, AndroidAudioTypeOptions } from './audio/AudioSession';
|
|
2
|
+
import AudioSession, { AndroidAudioTypePresets, AndroidAudioTypeOptions, AppleAudioCategory, AppleAudioCategoryOption, AppleAudioConfiguration, AppleAudioMode, AudioTrackState, getDefaultAppleAudioConfigurationForMode } from './audio/AudioSession';
|
|
3
3
|
import type { AudioConfiguration } from './audio/AudioSession';
|
|
4
|
+
import type { LogLevel, SetLogLevelOptions } from './logger';
|
|
4
5
|
/**
|
|
5
6
|
* Registers the required globals needed for LiveKit to work.
|
|
6
7
|
*
|
|
@@ -10,4 +11,6 @@ export declare function registerGlobals(): void;
|
|
|
10
11
|
export * from './components/VideoView';
|
|
11
12
|
export * from './useParticipant';
|
|
12
13
|
export * from './useRoom';
|
|
13
|
-
export
|
|
14
|
+
export * from './logger';
|
|
15
|
+
export * from './audio/AudioManager';
|
|
16
|
+
export { AudioSession, AudioConfiguration, AndroidAudioTypeOptions, AndroidAudioTypePresets, AppleAudioCategory, AppleAudioCategoryOption, AppleAudioConfiguration, AppleAudioMode, AudioTrackState, getDefaultAppleAudioConfigurationForMode, LogLevel, SetLogLevelOptions, };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { setLogLevel as setClientSdkLogLevel } from 'livekit-client';
|
|
2
|
+
import loglevel from 'loglevel';
|
|
3
|
+
export declare const log: loglevel.Logger;
|
|
4
|
+
export declare type LogLevel = Parameters<typeof setClientSdkLogLevel>[0];
|
|
5
|
+
export declare type SetLogLevelOptions = {
|
|
6
|
+
liveKitClientLogLevel?: LogLevel;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Set the log level for both the `@livekit/react-native` package and the `@livekit-client` package.
|
|
10
|
+
* To set the `@livekit-client` log independently, use the `liveKitClientLogLevel` prop on the `options` object.
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export declare function setLogLevel(level: LogLevel, options?: SetLogLevelOptions): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/react-native",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "LiveKit for React Native",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"array.prototype.at": "^1.1.1",
|
|
46
46
|
"fastestsmallesttextencoderdecoder": "^1.0.22",
|
|
47
|
-
"livekit-client": "^1.
|
|
47
|
+
"livekit-client": "^1.15.0",
|
|
48
|
+
"loglevel": "^1.8.0",
|
|
48
49
|
"promise.allsettled": "^1.0.5",
|
|
49
50
|
"react-native-url-polyfill": "^1.3.0",
|
|
50
51
|
"well-known-symbols": "^4.0.0"
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
"@babel/preset-env": "^7.20.0",
|
|
55
56
|
"@babel/runtime": "^7.20.0",
|
|
56
57
|
"@commitlint/config-conventional": "^16.2.1",
|
|
57
|
-
"@livekit/react-native-webrtc": "^
|
|
58
|
+
"@livekit/react-native-webrtc": "^114.0.0",
|
|
58
59
|
"@react-native-community/eslint-config": "^3.2.0",
|
|
59
60
|
"@release-it/conventional-changelog": "^4.2.0",
|
|
60
61
|
"@tsconfig/react-native": "^2.0.2",
|
|
@@ -72,14 +73,14 @@
|
|
|
72
73
|
"pod-install": "^0.1.0",
|
|
73
74
|
"prettier": "^2.5.1",
|
|
74
75
|
"react": "18.0.0",
|
|
75
|
-
"react-native": "0.
|
|
76
|
+
"react-native": "0.71.13",
|
|
76
77
|
"react-native-builder-bob": "^0.18.2",
|
|
77
78
|
"release-it": "^14.2.2",
|
|
78
79
|
"typedoc": "^0.23.14",
|
|
79
80
|
"typescript": "4.8.4"
|
|
80
81
|
},
|
|
81
82
|
"peerDependencies": {
|
|
82
|
-
"@livekit/react-native-webrtc": "^
|
|
83
|
+
"@livekit/react-native-webrtc": "^114.0.0",
|
|
83
84
|
"react": "*",
|
|
84
85
|
"react-native": "*"
|
|
85
86
|
},
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { RoomEvent, type Room } from 'livekit-client';
|
|
4
|
+
import AudioSession, {
|
|
5
|
+
getDefaultAppleAudioConfigurationForMode,
|
|
6
|
+
type AppleAudioConfiguration,
|
|
7
|
+
type AudioTrackState,
|
|
8
|
+
} from './AudioSession';
|
|
9
|
+
import { log } from '..';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Handles setting the appropriate AVAudioSession options automatically
|
|
13
|
+
* depending on the audio track states of the Room.
|
|
14
|
+
*
|
|
15
|
+
* @param room
|
|
16
|
+
* @param preferSpeakerOutput
|
|
17
|
+
* @param onConfigureNativeAudio A custom method for determining options used.
|
|
18
|
+
*/
|
|
19
|
+
export function useIOSAudioManagement(
|
|
20
|
+
room: Room,
|
|
21
|
+
preferSpeakerOutput: boolean = true,
|
|
22
|
+
onConfigureNativeAudio?: (
|
|
23
|
+
trackState: AudioTrackState,
|
|
24
|
+
preferSpeakerOutput: boolean
|
|
25
|
+
) => AppleAudioConfiguration
|
|
26
|
+
) {
|
|
27
|
+
const [localTrackCount, setLocalTrackCount] = useState(0);
|
|
28
|
+
const [remoteTrackCount, setRemoteTrackCount] = useState(0);
|
|
29
|
+
const trackState = useMemo(
|
|
30
|
+
() => computeAudioTrackState(localTrackCount, remoteTrackCount),
|
|
31
|
+
[localTrackCount, remoteTrackCount]
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (Platform.OS !== 'ios') {
|
|
36
|
+
return () => {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
40
|
+
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
41
|
+
|
|
42
|
+
let onLocalPublished = () => {
|
|
43
|
+
setLocalTrackCount(localTrackCount + 1);
|
|
44
|
+
};
|
|
45
|
+
let onLocalUnpublished = () => {
|
|
46
|
+
if (localTrackCount - 1 < 0) {
|
|
47
|
+
log.warn(
|
|
48
|
+
'mismatched local audio track count! attempted to reduce track count below zero.'
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
setLocalTrackCount(Math.max(localTrackCount - 1, 0));
|
|
52
|
+
};
|
|
53
|
+
let onRemotePublished = () => {
|
|
54
|
+
setRemoteTrackCount(remoteTrackCount + 1);
|
|
55
|
+
};
|
|
56
|
+
let onRemoteUnpublished = () => {
|
|
57
|
+
if (remoteTrackCount - 1 < 0) {
|
|
58
|
+
log.warn(
|
|
59
|
+
'mismatched remote audio track count! attempted to reduce track count below zero.'
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
setRemoteTrackCount(Math.max(remoteTrackCount - 1, 0));
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
room
|
|
66
|
+
.on(RoomEvent.LocalTrackPublished, onLocalPublished)
|
|
67
|
+
.on(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)
|
|
68
|
+
.on(RoomEvent.TrackPublished, onRemotePublished)
|
|
69
|
+
.on(RoomEvent.TrackUnpublished, onRemoteUnpublished);
|
|
70
|
+
|
|
71
|
+
return () => {
|
|
72
|
+
room
|
|
73
|
+
.off(RoomEvent.LocalTrackPublished, onLocalPublished)
|
|
74
|
+
.off(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)
|
|
75
|
+
.off(RoomEvent.TrackPublished, onRemotePublished)
|
|
76
|
+
.off(RoomEvent.TrackUnpublished, onRemoteUnpublished);
|
|
77
|
+
};
|
|
78
|
+
}, [room, localTrackCount, remoteTrackCount]);
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (Platform.OS !== 'ios') {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let configFunc =
|
|
86
|
+
onConfigureNativeAudio ?? getDefaultAppleAudioConfigurationForMode;
|
|
87
|
+
let audioConfig = configFunc(trackState, preferSpeakerOutput);
|
|
88
|
+
|
|
89
|
+
AudioSession.setAppleAudioConfiguration(audioConfig);
|
|
90
|
+
}, [trackState, onConfigureNativeAudio, preferSpeakerOutput]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function computeAudioTrackState(
|
|
94
|
+
localTracks: number,
|
|
95
|
+
remoteTracks: number
|
|
96
|
+
): AudioTrackState {
|
|
97
|
+
if (localTracks > 0 && remoteTracks > 0) {
|
|
98
|
+
return 'localAndRemote';
|
|
99
|
+
} else if (localTracks > 0 && remoteTracks === 0) {
|
|
100
|
+
return 'localOnly';
|
|
101
|
+
} else if (localTracks === 0 && remoteTracks > 0) {
|
|
102
|
+
return 'remoteOnly';
|
|
103
|
+
} else {
|
|
104
|
+
return 'none';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getLocalAudioTrackCount(room: Room): number {
|
|
109
|
+
return room.localParticipant.audioTracks.entries.length;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getRemoteAudioTrackCount(room: Room): number {
|
|
113
|
+
var audioTracks = 0;
|
|
114
|
+
room.participants.forEach((participant) => {
|
|
115
|
+
audioTracks += participant.audioTracks.entries.length;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return audioTracks;
|
|
119
|
+
}
|
|
@@ -179,11 +179,77 @@ export const AndroidAudioTypePresets: {
|
|
|
179
179
|
},
|
|
180
180
|
} as const;
|
|
181
181
|
|
|
182
|
+
export type AppleAudioMode =
|
|
183
|
+
| 'default'
|
|
184
|
+
| 'gameChat'
|
|
185
|
+
| 'measurement'
|
|
186
|
+
| 'moviePlayback'
|
|
187
|
+
| 'spokenAudio'
|
|
188
|
+
| 'videoChat'
|
|
189
|
+
| 'videoRecording'
|
|
190
|
+
| 'voiceChat'
|
|
191
|
+
| 'voicePrompt';
|
|
192
|
+
|
|
193
|
+
export type AppleAudioCategory =
|
|
194
|
+
| 'soloAmbient'
|
|
195
|
+
| 'playback'
|
|
196
|
+
| 'record'
|
|
197
|
+
| 'playAndRecord'
|
|
198
|
+
| 'multiRoute';
|
|
199
|
+
|
|
200
|
+
export type AppleAudioCategoryOption =
|
|
201
|
+
| 'mixWithOthers'
|
|
202
|
+
| 'duckOthers'
|
|
203
|
+
| 'interruptSpokenAudioAndMixWithOthers'
|
|
204
|
+
| 'allowBluetooth'
|
|
205
|
+
| 'allowBluetoothA2DP'
|
|
206
|
+
| 'allowAirPlay'
|
|
207
|
+
| 'defaultToSpeaker';
|
|
208
|
+
|
|
209
|
+
export type AppleAudioConfiguration = {
|
|
210
|
+
audioCategory?: AppleAudioCategory;
|
|
211
|
+
audioCategoryOptions?: AppleAudioCategoryOption[];
|
|
212
|
+
audioMode?: AppleAudioMode;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export type AudioTrackState =
|
|
216
|
+
| 'none'
|
|
217
|
+
| 'remoteOnly'
|
|
218
|
+
| 'localOnly'
|
|
219
|
+
| 'localAndRemote';
|
|
220
|
+
|
|
221
|
+
export function getDefaultAppleAudioConfigurationForMode(
|
|
222
|
+
mode: AudioTrackState,
|
|
223
|
+
preferSpeakerOutput: boolean = true
|
|
224
|
+
): AppleAudioConfiguration {
|
|
225
|
+
if (mode === 'remoteOnly') {
|
|
226
|
+
return {
|
|
227
|
+
audioCategory: 'playback',
|
|
228
|
+
audioCategoryOptions: ['mixWithOthers'],
|
|
229
|
+
audioMode: 'spokenAudio',
|
|
230
|
+
};
|
|
231
|
+
} else if (mode === 'localAndRemote' || mode === 'localOnly') {
|
|
232
|
+
return {
|
|
233
|
+
audioCategory: 'playAndRecord',
|
|
234
|
+
audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],
|
|
235
|
+
audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat',
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
audioCategory: 'soloAmbient',
|
|
241
|
+
audioCategoryOptions: [],
|
|
242
|
+
audioMode: 'default',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
182
246
|
export default class AudioSession {
|
|
183
247
|
/**
|
|
184
248
|
* Applies the provided audio configuration to the underlying AudioSession.
|
|
185
249
|
*
|
|
186
250
|
* Must be called prior to connecting to a Room for the configuration to apply correctly.
|
|
251
|
+
*
|
|
252
|
+
* See also useIOSAudioManagement for automatic configuration of iOS audio options.
|
|
187
253
|
*/
|
|
188
254
|
static configureAudio = async (config: AudioConfiguration) => {
|
|
189
255
|
await LivekitReactNative.configureAudio(config);
|
|
@@ -258,4 +324,12 @@ export default class AudioSession {
|
|
|
258
324
|
await LivekitReactNative.showAudioRoutePicker();
|
|
259
325
|
}
|
|
260
326
|
};
|
|
327
|
+
|
|
328
|
+
static setAppleAudioConfiguration = async (
|
|
329
|
+
config: AppleAudioConfiguration
|
|
330
|
+
) => {
|
|
331
|
+
if (Platform.OS === 'ios') {
|
|
332
|
+
await LivekitReactNative.setAppleAudioConfiguration(config);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
261
335
|
}
|
package/src/index.tsx
CHANGED
|
@@ -4,10 +4,17 @@ import 'fastestsmallesttextencoderdecoder';
|
|
|
4
4
|
import AudioSession, {
|
|
5
5
|
AndroidAudioTypePresets,
|
|
6
6
|
AndroidAudioTypeOptions,
|
|
7
|
+
AppleAudioCategory,
|
|
8
|
+
AppleAudioCategoryOption,
|
|
9
|
+
AppleAudioConfiguration,
|
|
10
|
+
AppleAudioMode,
|
|
11
|
+
AudioTrackState,
|
|
12
|
+
getDefaultAppleAudioConfigurationForMode,
|
|
7
13
|
} from './audio/AudioSession';
|
|
8
14
|
import type { AudioConfiguration } from './audio/AudioSession';
|
|
9
15
|
import { PixelRatio, Platform } from 'react-native';
|
|
10
16
|
import type { LiveKitReactNativeInfo } from 'livekit-client';
|
|
17
|
+
import type { LogLevel, SetLogLevelOptions } from './logger';
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Registers the required globals needed for LiveKit to work.
|
|
@@ -71,9 +78,20 @@ function shimIterator() {
|
|
|
71
78
|
export * from './components/VideoView';
|
|
72
79
|
export * from './useParticipant';
|
|
73
80
|
export * from './useRoom';
|
|
81
|
+
export * from './logger';
|
|
82
|
+
export * from './audio/AudioManager';
|
|
83
|
+
|
|
74
84
|
export {
|
|
75
85
|
AudioSession,
|
|
76
86
|
AudioConfiguration,
|
|
77
87
|
AndroidAudioTypeOptions,
|
|
78
88
|
AndroidAudioTypePresets,
|
|
89
|
+
AppleAudioCategory,
|
|
90
|
+
AppleAudioCategoryOption,
|
|
91
|
+
AppleAudioConfiguration,
|
|
92
|
+
AppleAudioMode,
|
|
93
|
+
AudioTrackState,
|
|
94
|
+
getDefaultAppleAudioConfigurationForMode,
|
|
95
|
+
LogLevel,
|
|
96
|
+
SetLogLevelOptions,
|
|
79
97
|
};
|