@livekit/react-native 2.7.6 → 2.9.0
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 +56 -7
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/livekit/reactnative/LivekitReactNativeModule.kt +31 -2
- package/android/src/main/java/com/livekit/reactnative/audio/events/Events.kt +1 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioSinkProcessor.kt +57 -0
- package/ios/LiveKitReactNativeModule.swift +21 -1
- package/ios/LivekitReactNativeModule.m +6 -0
- package/ios/audio/AudioSinkRenderer.swift +51 -0
- package/lib/commonjs/audio/MediaRecorder.js +132 -0
- package/lib/commonjs/audio/MediaRecorder.js.map +1 -0
- package/lib/commonjs/components/BarVisualizer.js +2 -5
- package/lib/commonjs/components/BarVisualizer.js.map +1 -1
- package/lib/commonjs/components/LiveKitRoom.js.map +1 -1
- package/lib/commonjs/components/VideoTrack.js.map +1 -1
- package/lib/commonjs/events/EventEmitter.js +1 -1
- package/lib/commonjs/events/EventEmitter.js.map +1 -1
- package/lib/commonjs/index.js +2 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/polyfills/MediaRecorderShim.js +13 -0
- package/lib/commonjs/polyfills/MediaRecorderShim.js.map +1 -0
- package/lib/module/audio/MediaRecorder.js +125 -0
- package/lib/module/audio/MediaRecorder.js.map +1 -0
- package/lib/module/components/BarVisualizer.js +2 -5
- package/lib/module/components/BarVisualizer.js.map +1 -1
- package/lib/module/components/LiveKitRoom.js.map +1 -1
- package/lib/module/components/VideoTrack.js.map +1 -1
- package/lib/module/events/EventEmitter.js +1 -1
- package/lib/module/events/EventEmitter.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/polyfills/MediaRecorderShim.js +11 -0
- package/lib/module/polyfills/MediaRecorderShim.js.map +1 -0
- package/lib/typescript/lib/commonjs/audio/MediaRecorder.d.ts +24 -0
- package/lib/typescript/lib/commonjs/polyfills/MediaRecorderShim.d.ts +1 -0
- package/lib/typescript/lib/module/audio/MediaRecorder.d.ts +22 -0
- package/lib/typescript/lib/module/polyfills/MediaRecorderShim.d.ts +1 -0
- package/lib/typescript/src/audio/MediaRecorder.d.ts +54 -0
- package/lib/typescript/src/components/LiveKitRoom.d.ts +1 -1
- package/lib/typescript/src/components/VideoTrack.d.ts +1 -1
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/polyfills/MediaRecorderShim.d.ts +1 -0
- package/package.json +7 -5
- package/src/audio/MediaRecorder.ts +158 -0
- package/src/components/BarVisualizer.tsx +2 -9
- package/src/components/LiveKitRoom.tsx +1 -1
- package/src/components/VideoTrack.tsx +3 -2
- package/src/events/EventEmitter.ts +5 -1
- package/src/index.tsx +2 -0
- package/src/polyfills/MediaRecorderShim.ts +12 -0
|
@@ -6,7 +6,7 @@ import LiveKitModule from '../LKNativeModule';
|
|
|
6
6
|
// This emitter is going to be used to listen to all the native events (once) and then
|
|
7
7
|
// re-emit them on a JS-only emitter.
|
|
8
8
|
const nativeEmitter = new NativeEventEmitter(LiveKitModule);
|
|
9
|
-
const NATIVE_EVENTS = ['LK_VOLUME_PROCESSED', 'LK_MULTIBAND_PROCESSED'];
|
|
9
|
+
const NATIVE_EVENTS = ['LK_VOLUME_PROCESSED', 'LK_MULTIBAND_PROCESSED', 'LK_AUDIO_DATA'];
|
|
10
10
|
const eventEmitter = new EventEmitter();
|
|
11
11
|
export function setupNativeEvents() {
|
|
12
12
|
for (const eventName of NATIVE_EVENTS) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","EventEmitter","LiveKitModule","nativeEmitter","NATIVE_EVENTS","eventEmitter","setupNativeEvents","eventName","addListener","args","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeEventEmitter, type EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(LiveKitModule);\n\nconst NATIVE_EVENTS = ['LK_VOLUME_PROCESSED'
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","EventEmitter","LiveKitModule","nativeEmitter","NATIVE_EVENTS","eventEmitter","setupNativeEvents","eventName","addListener","args","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeEventEmitter, type EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(LiveKitModule);\n\nconst NATIVE_EVENTS = [\n 'LK_VOLUME_PROCESSED',\n 'LK_MULTIBAND_PROCESSED',\n 'LK_AUDIO_DATA',\n];\n\nconst eventEmitter = new EventEmitter();\n\nexport function setupNativeEvents() {\n for (const eventName of NATIVE_EVENTS) {\n nativeEmitter.addListener(eventName, (...args) => {\n eventEmitter.emit(eventName, ...args);\n });\n }\n}\n\ntype EventHandler = (event: unknown) => void;\ntype Listener = unknown;\n\nconst _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();\n\nexport function addListener(\n listener: Listener,\n eventName: string,\n eventHandler: EventHandler\n): void {\n if (!NATIVE_EVENTS.includes(eventName)) {\n throw new Error(`Invalid event: ${eventName}`);\n }\n\n if (!_subscriptions.has(listener)) {\n _subscriptions.set(listener, []);\n }\n\n _subscriptions\n .get(listener)\n ?.push(eventEmitter.addListener(eventName, eventHandler));\n}\n\nexport function removeListener(listener: Listener): void {\n _subscriptions.get(listener)?.forEach((sub) => {\n sub.remove();\n });\n\n _subscriptions.delete(listener);\n}\n"],"mappings":"AAAA,SAASA,kBAAkB,QAAkC,cAAc;AAC3E;AACA,OAAOC,YAAY,MAAM,oDAAoD;AAC7E,OAAOC,aAAa,MAAM,mBAAmB;;AAE7C;AACA;AACA,MAAMC,aAAa,GAAG,IAAIH,kBAAkB,CAACE,aAAa,CAAC;AAE3D,MAAME,aAAa,GAAG,CACpB,qBAAqB,EACrB,wBAAwB,EACxB,eAAe,CAChB;AAED,MAAMC,YAAY,GAAG,IAAIJ,YAAY,CAAC,CAAC;AAEvC,OAAO,SAASK,iBAAiBA,CAAA,EAAG;EAClC,KAAK,MAAMC,SAAS,IAAIH,aAAa,EAAE;IACrCD,aAAa,CAACK,WAAW,CAACD,SAAS,EAAE,CAAC,GAAGE,IAAI,KAAK;MAChDJ,YAAY,CAACK,IAAI,CAACH,SAAS,EAAE,GAAGE,IAAI,CAAC;IACvC,CAAC,CAAC;EACJ;AACF;AAKA,MAAME,cAAoD,GAAG,IAAIC,GAAG,CAAC,CAAC;AAEtE,OAAO,SAASJ,WAAWA,CACzBK,QAAkB,EAClBN,SAAiB,EACjBO,YAA0B,EACpB;EAAA,IAAAC,kBAAA;EACN,IAAI,CAACX,aAAa,CAACY,QAAQ,CAACT,SAAS,CAAC,EAAE;IACtC,MAAM,IAAIU,KAAK,CAAC,kBAAkBV,SAAS,EAAE,CAAC;EAChD;EAEA,IAAI,CAACI,cAAc,CAACO,GAAG,CAACL,QAAQ,CAAC,EAAE;IACjCF,cAAc,CAACQ,GAAG,CAACN,QAAQ,EAAE,EAAE,CAAC;EAClC;EAEA,CAAAE,kBAAA,GAAAJ,cAAc,CACXS,GAAG,CAACP,QAAQ,CAAC,cAAAE,kBAAA,eADhBA,kBAAA,CAEIM,IAAI,CAAChB,YAAY,CAACG,WAAW,CAACD,SAAS,EAAEO,YAAY,CAAC,CAAC;AAC7D;AAEA,OAAO,SAASQ,cAAcA,CAACT,QAAkB,EAAQ;EAAA,IAAAU,mBAAA;EACvD,CAAAA,mBAAA,GAAAZ,cAAc,CAACS,GAAG,CAACP,QAAQ,CAAC,cAAAU,mBAAA,eAA5BA,mBAAA,CAA8BC,OAAO,CAAEC,GAAG,IAAK;IAC7CA,GAAG,CAACC,MAAM,CAAC,CAAC;EACd,CAAC,CAAC;EAEFf,cAAc,CAACgB,MAAM,CAACd,QAAQ,CAAC;AACjC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import 'well-known-symbols/Symbol.asyncIterator/auto';
|
|
2
2
|
import 'well-known-symbols/Symbol.iterator/auto';
|
|
3
|
+
import './polyfills/MediaRecorderShim';
|
|
4
|
+
import 'react-native-quick-base64';
|
|
3
5
|
import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';
|
|
4
6
|
import { setupURLPolyfill } from 'react-native-url-polyfill';
|
|
5
7
|
import './polyfills/EncoderDecoderTogether.min.js';
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["registerGlobals","webrtcRegisterGlobals","setupURLPolyfill","AudioSession","AndroidAudioTypePresets","getDefaultAppleAudioConfigurationForMode","PixelRatio","Platform","RNE2EEManager","RNKeyProvider","setupNativeEvents","ReadableStream","WritableStream","iosCategoryEnforce","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","shimCryptoUuid","shimWebstreams","OS","getUserMediaFunc","global","navigator","mediaDevices","getUserMedia","constraints","audio","setAppleAudioConfiguration","audioCategory","lkGlobal","platform","devicePixelRatio","get","LiveKitReactNativeGlobal","_window","window","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at","_global$crypto","crypto","randomUUID","createRandomUUID","replace","c","r","Math","random","v","toString"],"sources":["index.tsx"],"sourcesContent":["import 'well-known-symbols/Symbol.asyncIterator/auto';\nimport 'well-known-symbols/Symbol.iterator/auto';\nimport { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport './polyfills/EncoderDecoderTogether.min.js';\nimport AudioSession, {\n AndroidAudioTypePresets,\n type AndroidAudioTypeOptions,\n type AppleAudioCategory,\n type AppleAudioCategoryOption,\n type AppleAudioConfiguration,\n type AppleAudioMode,\n type 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';\nimport RNE2EEManager from './e2ee/RNE2EEManager';\nimport RNKeyProvider, { type RNKeyProviderOptions } from './e2ee/RNKeyProvider';\nimport { setupNativeEvents } from './events/EventEmitter';\nimport { ReadableStream, WritableStream } from 'web-streams-polyfill';\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 iosCategoryEnforce();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n shimCryptoUuid();\n shimWebstreams();\n setupNativeEvents();\n}\n\n/**\n * Enforces changing to playAndRecord category prior to obtaining microphone.\n */\nfunction iosCategoryEnforce() {\n if (Platform.OS === 'ios') {\n // @ts-ignore\n let getUserMediaFunc = global.navigator.mediaDevices.getUserMedia;\n // @ts-ignore\n global.navigator.mediaDevices.getUserMedia = async (constraints: any) => {\n if (constraints.audio) {\n await AudioSession.setAppleAudioConfiguration({\n audioCategory: 'playAndRecord',\n });\n }\n\n return await getUserMediaFunc(constraints);\n };\n }\n}\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 shimCryptoUuid() {\n let crypto = global.crypto;\n if (typeof global.crypto?.randomUUID !== 'function') {\n let createRandomUUID = () => {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n /[xy]/g,\n function (c) {\n /* eslint-disable no-bitwise */\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n }\n ) as `${string}-${string}-${string}-${string}-${string}`;\n };\n\n if (!crypto) {\n crypto = {} as typeof global.crypto;\n global.crypto = crypto;\n }\n crypto.randomUUID = createRandomUUID;\n }\n}\n\nfunction shimWebstreams() {\n // @ts-expect-error: global.WritableStream isn't typed here.\n if (typeof global.WritableStream === 'undefined') {\n // @ts-expect-error\n global.WritableStream = WritableStream;\n }\n\n // @ts-expect-error: global.ReadableStream isn't typed here.\n if (typeof global.ReadableStream === 'undefined') {\n // @ts-expect-error\n global.ReadableStream = ReadableStream;\n }\n}\n\nexport * from './hooks';\nexport * from './components/BarVisualizer';\nexport * from './components/LiveKitRoom';\nexport * from './components/VideoTrack';\nexport * from './components/VideoView'; // deprecated\nexport * from './useParticipant'; // deprecated\nexport * from './useRoom'; // deprecated\nexport * from './logger';\nexport * from './audio/AudioManager';\n\nexport {\n AudioSession,\n RNE2EEManager,\n RNKeyProvider,\n AndroidAudioTypePresets,\n getDefaultAppleAudioConfigurationForMode,\n};\nexport type {\n AudioConfiguration,\n AndroidAudioTypeOptions,\n AppleAudioCategory,\n AppleAudioCategoryOption,\n AppleAudioConfiguration,\n AppleAudioMode,\n AudioTrackState,\n LogLevel,\n SetLogLevelOptions,\n RNKeyProviderOptions,\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["registerGlobals","webrtcRegisterGlobals","setupURLPolyfill","AudioSession","AndroidAudioTypePresets","getDefaultAppleAudioConfigurationForMode","PixelRatio","Platform","RNE2EEManager","RNKeyProvider","setupNativeEvents","ReadableStream","WritableStream","iosCategoryEnforce","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","shimCryptoUuid","shimWebstreams","OS","getUserMediaFunc","global","navigator","mediaDevices","getUserMedia","constraints","audio","setAppleAudioConfiguration","audioCategory","lkGlobal","platform","devicePixelRatio","get","LiveKitReactNativeGlobal","_window","window","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at","_global$crypto","crypto","randomUUID","createRandomUUID","replace","c","r","Math","random","v","toString"],"sources":["index.tsx"],"sourcesContent":["import 'well-known-symbols/Symbol.asyncIterator/auto';\nimport 'well-known-symbols/Symbol.iterator/auto';\nimport './polyfills/MediaRecorderShim';\nimport 'react-native-quick-base64';\nimport { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport './polyfills/EncoderDecoderTogether.min.js';\nimport AudioSession, {\n AndroidAudioTypePresets,\n type AndroidAudioTypeOptions,\n type AppleAudioCategory,\n type AppleAudioCategoryOption,\n type AppleAudioConfiguration,\n type AppleAudioMode,\n type 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';\nimport RNE2EEManager from './e2ee/RNE2EEManager';\nimport RNKeyProvider, { type RNKeyProviderOptions } from './e2ee/RNKeyProvider';\nimport { setupNativeEvents } from './events/EventEmitter';\nimport { ReadableStream, WritableStream } from 'web-streams-polyfill';\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 iosCategoryEnforce();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n shimCryptoUuid();\n shimWebstreams();\n setupNativeEvents();\n}\n\n/**\n * Enforces changing to playAndRecord category prior to obtaining microphone.\n */\nfunction iosCategoryEnforce() {\n if (Platform.OS === 'ios') {\n // @ts-ignore\n let getUserMediaFunc = global.navigator.mediaDevices.getUserMedia;\n // @ts-ignore\n global.navigator.mediaDevices.getUserMedia = async (constraints: any) => {\n if (constraints.audio) {\n await AudioSession.setAppleAudioConfiguration({\n audioCategory: 'playAndRecord',\n });\n }\n\n return await getUserMediaFunc(constraints);\n };\n }\n}\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 shimCryptoUuid() {\n let crypto = global.crypto;\n if (typeof global.crypto?.randomUUID !== 'function') {\n let createRandomUUID = () => {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n /[xy]/g,\n function (c) {\n /* eslint-disable no-bitwise */\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n }\n ) as `${string}-${string}-${string}-${string}-${string}`;\n };\n\n if (!crypto) {\n crypto = {} as typeof global.crypto;\n global.crypto = crypto;\n }\n crypto.randomUUID = createRandomUUID;\n }\n}\n\nfunction shimWebstreams() {\n // @ts-expect-error: global.WritableStream isn't typed here.\n if (typeof global.WritableStream === 'undefined') {\n // @ts-expect-error\n global.WritableStream = WritableStream;\n }\n\n // @ts-expect-error: global.ReadableStream isn't typed here.\n if (typeof global.ReadableStream === 'undefined') {\n // @ts-expect-error\n global.ReadableStream = ReadableStream;\n }\n}\n\nexport * from './hooks';\nexport * from './components/BarVisualizer';\nexport * from './components/LiveKitRoom';\nexport * from './components/VideoTrack';\nexport * from './components/VideoView'; // deprecated\nexport * from './useParticipant'; // deprecated\nexport * from './useRoom'; // deprecated\nexport * from './logger';\nexport * from './audio/AudioManager';\n\nexport {\n AudioSession,\n RNE2EEManager,\n RNKeyProvider,\n AndroidAudioTypePresets,\n getDefaultAppleAudioConfigurationForMode,\n};\nexport type {\n AudioConfiguration,\n AndroidAudioTypeOptions,\n AppleAudioCategory,\n AppleAudioCategoryOption,\n AppleAudioConfiguration,\n AppleAudioMode,\n AudioTrackState,\n LogLevel,\n SetLogLevelOptions,\n RNKeyProviderOptions,\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MediaRecorder } from "../audio/MediaRecorder";
|
|
2
|
+
function shimMediaRecorder() {
|
|
3
|
+
// @ts-expect-error
|
|
4
|
+
if (!global.MediaRecorder) {
|
|
5
|
+
// @ts-expect-error
|
|
6
|
+
global.MediaRecorder = MediaRecorder;
|
|
7
|
+
}
|
|
8
|
+
MediaRecorder;
|
|
9
|
+
}
|
|
10
|
+
shimMediaRecorder();
|
|
11
|
+
//# sourceMappingURL=MediaRecorderShim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["MediaRecorder","shimMediaRecorder","global"],"sources":["MediaRecorderShim.ts"],"sourcesContent":["import { MediaRecorder } from \"../audio/MediaRecorder\";\n\nfunction shimMediaRecorder() {\n // @ts-expect-error\n if(!global.MediaRecorder) {\n // @ts-expect-error\n global.MediaRecorder = MediaRecorder\n }\n MediaRecorder\n}\n\nshimMediaRecorder();"],"mappings":"AAAA,SAASA,aAAa,QAAQ,wBAAwB;AAEtD,SAASC,iBAAiBA,CAAA,EAAG;EAC3B;EACA,IAAG,CAACC,MAAM,CAACF,aAAa,EAAE;IACxB;IACAE,MAAM,CAACF,aAAa,GAAGA,aAAa;EACtC;EACAA,aAAa;AACf;AAEAC,iBAAiB,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const __esModule: boolean;
|
|
2
|
+
declare const MediaRecorder_base: any;
|
|
3
|
+
/**
|
|
4
|
+
* A MediaRecord implementation only meant for recording audio streams.
|
|
5
|
+
*
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
export class MediaRecorder extends MediaRecorder_base {
|
|
9
|
+
[x: string]: any;
|
|
10
|
+
constructor(stream: any);
|
|
11
|
+
stream: any;
|
|
12
|
+
registerListener(): void;
|
|
13
|
+
_reactTag: any;
|
|
14
|
+
unregisterListener(): void;
|
|
15
|
+
pause(): void;
|
|
16
|
+
state: string | undefined;
|
|
17
|
+
resume(): void;
|
|
18
|
+
start(): void;
|
|
19
|
+
stop(): void;
|
|
20
|
+
requestData(): void;
|
|
21
|
+
dispatchData(): void;
|
|
22
|
+
_parts: any[] | undefined;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A MediaRecord implementation only meant for recording audio streams.
|
|
3
|
+
*
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
export class MediaRecorder extends EventTarget<Record<string, Event<string>>, "standard"> {
|
|
7
|
+
constructor(stream: any);
|
|
8
|
+
stream: any;
|
|
9
|
+
registerListener(): void;
|
|
10
|
+
_reactTag: any;
|
|
11
|
+
unregisterListener(): void;
|
|
12
|
+
pause(): void;
|
|
13
|
+
state: string | undefined;
|
|
14
|
+
resume(): void;
|
|
15
|
+
start(): void;
|
|
16
|
+
stop(): void;
|
|
17
|
+
requestData(): void;
|
|
18
|
+
dispatchData(): void;
|
|
19
|
+
_parts: any[] | undefined;
|
|
20
|
+
}
|
|
21
|
+
import { Event } from 'event-target-shim/index';
|
|
22
|
+
import { EventTarget } from 'event-target-shim/index';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { MediaStream } from '@livekit/react-native-webrtc';
|
|
2
|
+
import { EventTarget, Event } from 'event-target-shim/index';
|
|
3
|
+
type MediaRecorderState = 'inactive' | 'recording' | 'paused';
|
|
4
|
+
type MediaRecorderEventMap = {
|
|
5
|
+
dataavailable: BlobEvent<'dataavailable'>;
|
|
6
|
+
error: Event<'error'>;
|
|
7
|
+
pause: Event<'pause'>;
|
|
8
|
+
resume: Event<'resume'>;
|
|
9
|
+
start: Event<'start'>;
|
|
10
|
+
stop: Event<'stop'>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A MediaRecord implementation only meant for recording audio streams.
|
|
14
|
+
*
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
export declare class MediaRecorder extends EventTarget<MediaRecorderEventMap> {
|
|
18
|
+
mimeType: String;
|
|
19
|
+
audioBitsPerSecond: number;
|
|
20
|
+
state: MediaRecorderState;
|
|
21
|
+
stream: MediaStream;
|
|
22
|
+
videoBitsPerSecond: number;
|
|
23
|
+
audioBitrateMode: string;
|
|
24
|
+
_reactTag: string | undefined;
|
|
25
|
+
_parts: string[];
|
|
26
|
+
constructor(stream: MediaStream);
|
|
27
|
+
registerListener(): void;
|
|
28
|
+
unregisterListener(): void;
|
|
29
|
+
pause(): void;
|
|
30
|
+
resume(): void;
|
|
31
|
+
start(): void;
|
|
32
|
+
stop(): void;
|
|
33
|
+
requestData(): void;
|
|
34
|
+
dispatchData(): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @eventClass
|
|
38
|
+
* This event is fired whenever the Track is changed in PeerConnection.
|
|
39
|
+
* @param {TRACK_EVENTS} type - The type of event.
|
|
40
|
+
* @param {IRTCTrackEventInitDict} eventInitDict - The event init properties.
|
|
41
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/track_event MDN} for details.
|
|
42
|
+
*/
|
|
43
|
+
declare class BlobEvent<TEventType extends string> extends Event<TEventType> {
|
|
44
|
+
/** @eventProperty */
|
|
45
|
+
readonly data: {
|
|
46
|
+
byteArray: Uint8Array;
|
|
47
|
+
};
|
|
48
|
+
constructor(type: TEventType, eventInitDict: {
|
|
49
|
+
data: {
|
|
50
|
+
byteArray: Uint8Array;
|
|
51
|
+
};
|
|
52
|
+
} & Event.EventInit);
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -103,4 +103,4 @@ export type VideoTrackProps = {
|
|
|
103
103
|
* @returns A React component that renders the given video track.
|
|
104
104
|
* @public
|
|
105
105
|
*/
|
|
106
|
-
export declare const VideoTrack: React.ForwardRefExoticComponent<VideoTrackProps & React.RefAttributes<React.Component<
|
|
106
|
+
export declare const VideoTrack: React.ForwardRefExoticComponent<VideoTrackProps & React.RefAttributes<React.Component<import("@livekit/react-native-webrtc").RTCVideoViewProps, {}, any> & Readonly<import("react-native").NativeMethods>>>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import 'well-known-symbols/Symbol.asyncIterator/auto';
|
|
2
2
|
import 'well-known-symbols/Symbol.iterator/auto';
|
|
3
|
+
import './polyfills/MediaRecorderShim';
|
|
4
|
+
import 'react-native-quick-base64';
|
|
3
5
|
import './polyfills/EncoderDecoderTogether.min.js';
|
|
4
6
|
import AudioSession, { AndroidAudioTypePresets, type AndroidAudioTypeOptions, type AppleAudioCategory, type AppleAudioCategoryOption, type AppleAudioConfiguration, type AppleAudioMode, type AudioTrackState, getDefaultAppleAudioConfigurationForMode } from './audio/AudioSession';
|
|
5
7
|
import type { AudioConfiguration } from './audio/AudioSession';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/react-native",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "LiveKit for React Native",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -44,9 +44,11 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@livekit/components-react": "^2.8.1",
|
|
46
46
|
"array.prototype.at": "^1.1.1",
|
|
47
|
+
"event-target-shim": "6.0.2",
|
|
47
48
|
"events": "^3.3.0",
|
|
48
49
|
"loglevel": "^1.8.0",
|
|
49
50
|
"promise.allsettled": "^1.0.5",
|
|
51
|
+
"react-native-quick-base64": "2.1.1",
|
|
50
52
|
"react-native-url-polyfill": "^1.3.0",
|
|
51
53
|
"typed-emitter": "^2.1.0",
|
|
52
54
|
"web-streams-polyfill": "^4.1.0",
|
|
@@ -57,7 +59,7 @@
|
|
|
57
59
|
"@babel/preset-env": "^7.20.0",
|
|
58
60
|
"@babel/runtime": "^7.20.0",
|
|
59
61
|
"@commitlint/config-conventional": "^16.2.1",
|
|
60
|
-
"@livekit/react-native-webrtc": "^
|
|
62
|
+
"@livekit/react-native-webrtc": "^137.0.0",
|
|
61
63
|
"@react-native/babel-preset": "0.74.84",
|
|
62
64
|
"@react-native/eslint-config": "0.74.84",
|
|
63
65
|
"@react-native/metro-config": "0.74.84",
|
|
@@ -73,7 +75,7 @@
|
|
|
73
75
|
"eslint-plugin-prettier": "^4.2.1",
|
|
74
76
|
"husky": "^7.0.4",
|
|
75
77
|
"jest": "^29.6.3",
|
|
76
|
-
"livekit-client": "^2.
|
|
78
|
+
"livekit-client": "^2.15.4",
|
|
77
79
|
"pod-install": "^0.2.2",
|
|
78
80
|
"prettier": "2.8.8",
|
|
79
81
|
"react": "18.2.0",
|
|
@@ -84,8 +86,8 @@
|
|
|
84
86
|
"typescript": "5.0.4"
|
|
85
87
|
},
|
|
86
88
|
"peerDependencies": {
|
|
87
|
-
"@livekit/react-native-webrtc": "^
|
|
88
|
-
"livekit-client": "^2.
|
|
89
|
+
"@livekit/react-native-webrtc": "^137.0.0",
|
|
90
|
+
"livekit-client": "^2.15.4",
|
|
89
91
|
"react": "*",
|
|
90
92
|
"react-native": "*"
|
|
91
93
|
},
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { MediaStream } from '@livekit/react-native-webrtc';
|
|
2
|
+
import { addListener } from '../events/EventEmitter';
|
|
3
|
+
import {
|
|
4
|
+
EventTarget,
|
|
5
|
+
Event,
|
|
6
|
+
defineEventAttribute,
|
|
7
|
+
} from 'event-target-shim/index';
|
|
8
|
+
import { toByteArray } from 'react-native-quick-base64';
|
|
9
|
+
import LiveKitModule from '../LKNativeModule';
|
|
10
|
+
import { log } from '../logger';
|
|
11
|
+
|
|
12
|
+
// typeof MediaRecorder
|
|
13
|
+
// const Tester = (stream: MediaStream) => {
|
|
14
|
+
// return new AudioRecorder(stream) satisfies MediaRecorder;
|
|
15
|
+
// };
|
|
16
|
+
|
|
17
|
+
type MediaRecorderState = 'inactive' | 'recording' | 'paused';
|
|
18
|
+
type MediaRecorderEventMap = {
|
|
19
|
+
dataavailable: BlobEvent<'dataavailable'>;
|
|
20
|
+
error: Event<'error'>;
|
|
21
|
+
pause: Event<'pause'>;
|
|
22
|
+
resume: Event<'resume'>;
|
|
23
|
+
start: Event<'start'>;
|
|
24
|
+
stop: Event<'stop'>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A MediaRecord implementation only meant for recording audio streams.
|
|
29
|
+
*
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
export class MediaRecorder extends EventTarget<MediaRecorderEventMap> {
|
|
33
|
+
mimeType: String = 'audio/pcm';
|
|
34
|
+
audioBitsPerSecond: number = 0; // TODO?
|
|
35
|
+
state: MediaRecorderState = 'inactive';
|
|
36
|
+
stream: MediaStream;
|
|
37
|
+
videoBitsPerSecond: number = 0; // TODO?
|
|
38
|
+
audioBitrateMode = 'constant';
|
|
39
|
+
|
|
40
|
+
_reactTag: string | undefined = undefined;
|
|
41
|
+
_parts: string[] = [];
|
|
42
|
+
constructor(stream: MediaStream) {
|
|
43
|
+
super();
|
|
44
|
+
this.stream = stream;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
registerListener() {
|
|
48
|
+
let audioTracks = this.stream.getAudioTracks();
|
|
49
|
+
if (audioTracks.length !== 1) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const mediaStreamTrack = audioTracks[0];
|
|
53
|
+
const peerConnectionId = mediaStreamTrack._peerConnectionId ?? -1;
|
|
54
|
+
const mediaStreamTrackId = mediaStreamTrack?.id;
|
|
55
|
+
this._reactTag = LiveKitModule.createAudioSinkListener(
|
|
56
|
+
peerConnectionId,
|
|
57
|
+
mediaStreamTrackId
|
|
58
|
+
);
|
|
59
|
+
addListener(this, 'LK_AUDIO_DATA', (event: any) => {
|
|
60
|
+
if (
|
|
61
|
+
this._reactTag &&
|
|
62
|
+
event.id === this._reactTag &&
|
|
63
|
+
this.state === 'recording'
|
|
64
|
+
) {
|
|
65
|
+
let str = event.data as string;
|
|
66
|
+
this._parts.push(str);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
unregisterListener() {
|
|
72
|
+
if (this._reactTag) {
|
|
73
|
+
let audioTracks = this.stream.getAudioTracks();
|
|
74
|
+
if (audioTracks.length !== 1) {
|
|
75
|
+
log.error("couldn't find any audio tracks to record from!");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const mediaStreamTrack = audioTracks[0];
|
|
79
|
+
const peerConnectionId = mediaStreamTrack._peerConnectionId ?? -1;
|
|
80
|
+
const mediaStreamTrackId = mediaStreamTrack?.id;
|
|
81
|
+
|
|
82
|
+
LiveKitModule.deleteAudioSinkListener(
|
|
83
|
+
this._reactTag,
|
|
84
|
+
peerConnectionId,
|
|
85
|
+
mediaStreamTrackId
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
pause() {
|
|
91
|
+
this.state = 'paused';
|
|
92
|
+
this.dispatchEvent(new Event('pause'));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
resume() {
|
|
96
|
+
this.state = 'recording';
|
|
97
|
+
this.dispatchEvent(new Event('resume'));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
start() {
|
|
101
|
+
this.registerListener();
|
|
102
|
+
this.state = 'recording';
|
|
103
|
+
this.dispatchEvent(new Event('start'));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
stop() {
|
|
107
|
+
// dispatch data must come before stopping.
|
|
108
|
+
this.dispatchData();
|
|
109
|
+
|
|
110
|
+
this.unregisterListener();
|
|
111
|
+
this.state = 'inactive';
|
|
112
|
+
this.dispatchEvent(new Event('stop'));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
requestData() {
|
|
116
|
+
this.dispatchData();
|
|
117
|
+
}
|
|
118
|
+
dispatchData() {
|
|
119
|
+
let combinedStr = this._parts.reduce((sum, cur) => sum + cur, '');
|
|
120
|
+
let data = toByteArray(combinedStr);
|
|
121
|
+
this._parts = [];
|
|
122
|
+
this.dispatchEvent(
|
|
123
|
+
new BlobEvent('dataavailable', { data: { byteArray: data } })
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @eventClass
|
|
130
|
+
* This event is fired whenever the Track is changed in PeerConnection.
|
|
131
|
+
* @param {TRACK_EVENTS} type - The type of event.
|
|
132
|
+
* @param {IRTCTrackEventInitDict} eventInitDict - The event init properties.
|
|
133
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/track_event MDN} for details.
|
|
134
|
+
*/
|
|
135
|
+
class BlobEvent<TEventType extends string> extends Event<TEventType> {
|
|
136
|
+
/** @eventProperty */
|
|
137
|
+
readonly data: { byteArray: Uint8Array };
|
|
138
|
+
|
|
139
|
+
constructor(
|
|
140
|
+
type: TEventType,
|
|
141
|
+
eventInitDict: { data: { byteArray: Uint8Array } } & Event.EventInit
|
|
142
|
+
) {
|
|
143
|
+
super(type, eventInitDict);
|
|
144
|
+
this.data = eventInitDict.data;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Define the `onxxx` event handlers.
|
|
150
|
+
*/
|
|
151
|
+
const proto = MediaRecorder.prototype;
|
|
152
|
+
|
|
153
|
+
defineEventAttribute(proto, 'dataavailable');
|
|
154
|
+
defineEventAttribute(proto, 'error');
|
|
155
|
+
defineEventAttribute(proto, 'pause');
|
|
156
|
+
defineEventAttribute(proto, 'resume');
|
|
157
|
+
defineEventAttribute(proto, 'start');
|
|
158
|
+
defineEventAttribute(proto, 'stop');
|
|
@@ -149,7 +149,7 @@ export const BarVisualizer = ({
|
|
|
149
149
|
let bars: React.ReactNode[] = [];
|
|
150
150
|
magnitudes.forEach((value, index) => {
|
|
151
151
|
let coerced = Math.min(opts.maxHeight, Math.max(opts.minHeight, value));
|
|
152
|
-
let coercedPercent = Math.min(100, Math.max(0, coerced * 100
|
|
152
|
+
let coercedPercent = Math.min(100, Math.max(0, coerced * 100));
|
|
153
153
|
let opacity = opacityAnimations[index] ?? new Animated.Value(0.3);
|
|
154
154
|
let barStyle = {
|
|
155
155
|
opacity: opacity,
|
|
@@ -160,11 +160,7 @@ export const BarVisualizer = ({
|
|
|
160
160
|
bars.push(
|
|
161
161
|
<Animated.View
|
|
162
162
|
key={index}
|
|
163
|
-
style={[
|
|
164
|
-
{ height: `${coercedPercent}%` },
|
|
165
|
-
barStyle,
|
|
166
|
-
styles.volumeIndicator,
|
|
167
|
-
]}
|
|
163
|
+
style={[{ height: `${coercedPercent}%` }, barStyle]}
|
|
168
164
|
/>
|
|
169
165
|
);
|
|
170
166
|
});
|
|
@@ -177,9 +173,6 @@ const styles = StyleSheet.create({
|
|
|
177
173
|
alignItems: 'center',
|
|
178
174
|
justifyContent: 'space-evenly',
|
|
179
175
|
},
|
|
180
|
-
volumeIndicator: {
|
|
181
|
-
borderRadius: 12,
|
|
182
|
-
},
|
|
183
176
|
});
|
|
184
177
|
|
|
185
178
|
export const useBarAnimator = (
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
type RTCIOSPIPOptions,
|
|
20
20
|
} from '@livekit/react-native-webrtc';
|
|
21
21
|
import {
|
|
22
|
-
Component,
|
|
23
22
|
forwardRef,
|
|
24
23
|
useCallback,
|
|
25
24
|
useEffect,
|
|
@@ -125,6 +124,8 @@ export type VideoTrackProps = {
|
|
|
125
124
|
};
|
|
126
125
|
};
|
|
127
126
|
|
|
127
|
+
type RTCViewInstance = InstanceType<typeof RTCView>;
|
|
128
|
+
|
|
128
129
|
/**
|
|
129
130
|
* VideoTrack component for displaying video tracks in a React Native application.
|
|
130
131
|
* It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.
|
|
@@ -133,7 +134,7 @@ export type VideoTrackProps = {
|
|
|
133
134
|
* @returns A React component that renders the given video track.
|
|
134
135
|
* @public
|
|
135
136
|
*/
|
|
136
|
-
export const VideoTrack = forwardRef<
|
|
137
|
+
export const VideoTrack = forwardRef<RTCViewInstance, VideoTrackProps>(
|
|
137
138
|
(
|
|
138
139
|
{
|
|
139
140
|
style = {},
|
|
@@ -7,7 +7,11 @@ import LiveKitModule from '../LKNativeModule';
|
|
|
7
7
|
// re-emit them on a JS-only emitter.
|
|
8
8
|
const nativeEmitter = new NativeEventEmitter(LiveKitModule);
|
|
9
9
|
|
|
10
|
-
const NATIVE_EVENTS = [
|
|
10
|
+
const NATIVE_EVENTS = [
|
|
11
|
+
'LK_VOLUME_PROCESSED',
|
|
12
|
+
'LK_MULTIBAND_PROCESSED',
|
|
13
|
+
'LK_AUDIO_DATA',
|
|
14
|
+
];
|
|
11
15
|
|
|
12
16
|
const eventEmitter = new EventEmitter();
|
|
13
17
|
|
package/src/index.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import 'well-known-symbols/Symbol.asyncIterator/auto';
|
|
2
2
|
import 'well-known-symbols/Symbol.iterator/auto';
|
|
3
|
+
import './polyfills/MediaRecorderShim';
|
|
4
|
+
import 'react-native-quick-base64';
|
|
3
5
|
import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';
|
|
4
6
|
import { setupURLPolyfill } from 'react-native-url-polyfill';
|
|
5
7
|
import './polyfills/EncoderDecoderTogether.min.js';
|