@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.
Files changed (49) hide show
  1. package/README.md +56 -7
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/livekit/reactnative/LivekitReactNativeModule.kt +31 -2
  4. package/android/src/main/java/com/livekit/reactnative/audio/events/Events.kt +1 -0
  5. package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioSinkProcessor.kt +57 -0
  6. package/ios/LiveKitReactNativeModule.swift +21 -1
  7. package/ios/LivekitReactNativeModule.m +6 -0
  8. package/ios/audio/AudioSinkRenderer.swift +51 -0
  9. package/lib/commonjs/audio/MediaRecorder.js +132 -0
  10. package/lib/commonjs/audio/MediaRecorder.js.map +1 -0
  11. package/lib/commonjs/components/BarVisualizer.js +2 -5
  12. package/lib/commonjs/components/BarVisualizer.js.map +1 -1
  13. package/lib/commonjs/components/LiveKitRoom.js.map +1 -1
  14. package/lib/commonjs/components/VideoTrack.js.map +1 -1
  15. package/lib/commonjs/events/EventEmitter.js +1 -1
  16. package/lib/commonjs/events/EventEmitter.js.map +1 -1
  17. package/lib/commonjs/index.js +2 -0
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/commonjs/polyfills/MediaRecorderShim.js +13 -0
  20. package/lib/commonjs/polyfills/MediaRecorderShim.js.map +1 -0
  21. package/lib/module/audio/MediaRecorder.js +125 -0
  22. package/lib/module/audio/MediaRecorder.js.map +1 -0
  23. package/lib/module/components/BarVisualizer.js +2 -5
  24. package/lib/module/components/BarVisualizer.js.map +1 -1
  25. package/lib/module/components/LiveKitRoom.js.map +1 -1
  26. package/lib/module/components/VideoTrack.js.map +1 -1
  27. package/lib/module/events/EventEmitter.js +1 -1
  28. package/lib/module/events/EventEmitter.js.map +1 -1
  29. package/lib/module/index.js +2 -0
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/module/polyfills/MediaRecorderShim.js +11 -0
  32. package/lib/module/polyfills/MediaRecorderShim.js.map +1 -0
  33. package/lib/typescript/lib/commonjs/audio/MediaRecorder.d.ts +24 -0
  34. package/lib/typescript/lib/commonjs/polyfills/MediaRecorderShim.d.ts +1 -0
  35. package/lib/typescript/lib/module/audio/MediaRecorder.d.ts +22 -0
  36. package/lib/typescript/lib/module/polyfills/MediaRecorderShim.d.ts +1 -0
  37. package/lib/typescript/src/audio/MediaRecorder.d.ts +54 -0
  38. package/lib/typescript/src/components/LiveKitRoom.d.ts +1 -1
  39. package/lib/typescript/src/components/VideoTrack.d.ts +1 -1
  40. package/lib/typescript/src/index.d.ts +2 -0
  41. package/lib/typescript/src/polyfills/MediaRecorderShim.d.ts +1 -0
  42. package/package.json +7 -5
  43. package/src/audio/MediaRecorder.ts +158 -0
  44. package/src/components/BarVisualizer.tsx +2 -9
  45. package/src/components/LiveKitRoom.tsx +1 -1
  46. package/src/components/VideoTrack.tsx +3 -2
  47. package/src/events/EventEmitter.ts +5 -1
  48. package/src/index.tsx +2 -0
  49. 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', 'LK_MULTIBAND_PROCESSED'];\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,CAAC,qBAAqB,EAAE,wBAAwB,CAAC;AAEvE,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":[]}
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":[]}
@@ -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';
@@ -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":"AAAA,OAAO,8CAA8C;AACrD,OAAO,yCAAyC;AAChD,OAAO,+BAA+B;AACtC,OAAO,2BAA2B;AAClC,SAASA,eAAe,IAAIC,qBAAqB,QAAQ,8BAA8B;AACvF,SAASC,gBAAgB,QAAQ,2BAA2B;AAC5D,OAAO,2CAA2C;AAClD,OAAOC,YAAY,IACjBC,uBAAuB,EAOvBC,wCAAwC,QACnC,sBAAsB;AAE7B,SAASC,UAAU,EAAEC,QAAQ,QAAQ,cAAc;AAGnD,OAAOC,aAAa,MAAM,sBAAsB;AAChD,OAAOC,aAAa,MAAqC,sBAAsB;AAC/E,SAASC,iBAAiB,QAAQ,uBAAuB;AACzD,SAASC,cAAc,EAAEC,cAAc,QAAQ,sBAAsB;;AAErE;AACA;AACA;AACA;AACA;AACA,OAAO,SAASZ,eAAeA,CAAA,EAAG;EAChCC,qBAAqB,CAAC,CAAC;EACvBY,kBAAkB,CAAC,CAAC;EACpBC,sBAAsB,CAAC,CAAC;EACxBZ,gBAAgB,CAAC,CAAC;EAClBa,gBAAgB,CAAC,CAAC;EAClBC,qBAAqB,CAAC,CAAC;EACvBC,WAAW,CAAC,CAAC;EACbC,cAAc,CAAC,CAAC;EAChBC,cAAc,CAAC,CAAC;EAChBT,iBAAiB,CAAC,CAAC;AACrB;;AAEA;AACA;AACA;AACA,SAASG,kBAAkBA,CAAA,EAAG;EAC5B,IAAIN,QAAQ,CAACa,EAAE,KAAK,KAAK,EAAE;IACzB;IACA,IAAIC,gBAAgB,GAAGC,MAAM,CAACC,SAAS,CAACC,YAAY,CAACC,YAAY;IACjE;IACAH,MAAM,CAACC,SAAS,CAACC,YAAY,CAACC,YAAY,GAAG,MAAOC,WAAgB,IAAK;MACvE,IAAIA,WAAW,CAACC,KAAK,EAAE;QACrB,MAAMxB,YAAY,CAACyB,0BAA0B,CAAC;UAC5CC,aAAa,EAAE;QACjB,CAAC,CAAC;MACJ;MAEA,OAAO,MAAMR,gBAAgB,CAACK,WAAW,CAAC;IAC5C,CAAC;EACH;AACF;AAEA,SAASZ,sBAAsBA,CAAA,EAAG;EAChC,IAAIgB,QAAgC,GAAG;IACrCC,QAAQ,EAAExB,QAAQ,CAACa,EAAE;IACrBY,gBAAgB,EAAE1B,UAAU,CAAC2B,GAAG,CAAC;EACnC,CAAC;;EAED;EACAX,MAAM,CAACY,wBAAwB,GAAGJ,QAAQ;AAC5C;AAEA,SAASf,gBAAgBA,CAAA,EAAG;EAAA,IAAAoB,OAAA;EAC1B;EACA,IAAI,EAAAA,OAAA,GAAAC,MAAM,cAAAD,OAAA,uBAANA,OAAA,CAAQZ,SAAS,MAAKc,SAAS,EAAE;IACnC;IACA,MAAM;MAAEd;IAAU,CAAC,GAAGa,MAAM;IAC5B,IAAIb,SAAS,CAACe,SAAS,KAAKD,SAAS,EAAE;MACrCd,SAAS,CAACe,SAAS,GAAGf,SAAS,CAACgB,OAAO,IAAI,SAAS;IACtD;EACF;AACF;AAEA,SAASvB,qBAAqBA,CAAA,EAAG;EAC/B,IAAIwB,UAAU,GAAGC,OAAO,CAAC,oBAAoB,CAAC;EAC9CD,UAAU,CAACE,IAAI,CAAC,CAAC;AACnB;AAEA,SAASzB,WAAWA,CAAA,EAAG;EACrB;EACA,IAAI,CAAC0B,KAAK,CAACC,SAAS,CAACC,EAAE,EAAE;IACvB,IAAIA,EAAE,GAAGJ,OAAO,CAAC,oBAAoB,CAAC;IACtCI,EAAE,CAACH,IAAI,CAAC,CAAC;EACX;AACF;AAEA,SAASxB,cAAcA,CAAA,EAAG;EAAA,IAAA4B,cAAA;EACxB,IAAIC,MAAM,GAAGzB,MAAM,CAACyB,MAAM;EAC1B,IAAI,SAAAD,cAAA,GAAOxB,MAAM,CAACyB,MAAM,cAAAD,cAAA,uBAAbA,cAAA,CAAeE,UAAU,MAAK,UAAU,EAAE;IACnD,IAAIC,gBAAgB,GAAGA,CAAA,KAAM;MAC3B,OAAO,sCAAsC,CAACC,OAAO,CACnD,OAAO,EACP,UAAUC,CAAC,EAAE;QACX;QACA,MAAMC,CAAC,GAAIC,IAAI,CAACC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAI,CAAC;QAClC,MAAMC,CAAC,GAAGJ,CAAC,KAAK,GAAG,GAAGC,CAAC,GAAIA,CAAC,GAAG,GAAG,GAAI,GAAG;QACzC,OAAOG,CAAC,CAACC,QAAQ,CAAC,EAAE,CAAC;MACvB,CACF,CAAC;IACH,CAAC;IAED,IAAI,CAACT,MAAM,EAAE;MACXA,MAAM,GAAG,CAAC,CAAyB;MACnCzB,MAAM,CAACyB,MAAM,GAAGA,MAAM;IACxB;IACAA,MAAM,CAACC,UAAU,GAAGC,gBAAgB;EACtC;AACF;AAEA,SAAS9B,cAAcA,CAAA,EAAG;EACxB;EACA,IAAI,OAAOG,MAAM,CAACV,cAAc,KAAK,WAAW,EAAE;IAChD;IACAU,MAAM,CAACV,cAAc,GAAGA,cAAc;EACxC;;EAEA;EACA,IAAI,OAAOU,MAAM,CAACX,cAAc,KAAK,WAAW,EAAE;IAChD;IACAW,MAAM,CAACX,cAAc,GAAGA,cAAc;EACxC;AACF;AAEA,cAAc,SAAS;AACvB,cAAc,4BAA4B;AAC1C,cAAc,0BAA0B;AACxC,cAAc,yBAAyB;AACvC,cAAc,wBAAwB,CAAC,CAAC;AACxC,cAAc,kBAAkB,CAAC,CAAC;AAClC,cAAc,WAAW,CAAC,CAAC;AAC3B,cAAc,UAAU;AACxB,cAAc,sBAAsB;AAEpC,SACER,YAAY,EACZK,aAAa,EACbC,aAAa,EACbL,uBAAuB,EACvBC,wCAAwC","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,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,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 {};
@@ -38,7 +38,7 @@ export interface LiveKitRoomProps {
38
38
  screen?: ScreenShareCaptureOptions | boolean;
39
39
  /**
40
40
  * If set to true a connection to LiveKit room is initiated.
41
- * @defaultValue `false`
41
+ * @defaultValue `true`
42
42
  */
43
43
  connect?: boolean;
44
44
  /**
@@ -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<{}, {}, any>>>;
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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livekit/react-native",
3
- "version": "2.7.6",
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": "^125.0.10",
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.9.8",
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": "^125.0.10",
88
- "livekit-client": "^2.9.0",
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 + 5));
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 = (
@@ -50,7 +50,7 @@ export interface LiveKitRoomProps {
50
50
  screen?: ScreenShareCaptureOptions | boolean;
51
51
  /**
52
52
  * If set to true a connection to LiveKit room is initiated.
53
- * @defaultValue `false`
53
+ * @defaultValue `true`
54
54
  */
55
55
  connect?: boolean;
56
56
  /**
@@ -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<Component, VideoTrackProps>(
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 = ['LK_VOLUME_PROCESSED', 'LK_MULTIBAND_PROCESSED'];
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';
@@ -0,0 +1,12 @@
1
+ import { MediaRecorder } from "../audio/MediaRecorder";
2
+
3
+ function shimMediaRecorder() {
4
+ // @ts-expect-error
5
+ if(!global.MediaRecorder) {
6
+ // @ts-expect-error
7
+ global.MediaRecorder = MediaRecorder
8
+ }
9
+ MediaRecorder
10
+ }
11
+
12
+ shimMediaRecorder();