UNPKG

react-native-realtime-audio

Version:
61 lines (43 loc) 5.86 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Overview `react-native-realtime-audio` is an Expo Module (not a plain RN library) that provides real-time audio playback, recording, VAD-gated recording, and waveform visualization on iOS, Android, and web. It is consumed by an Expo app via autolinking and exposes both imperative classes (e.g. `RealtimeAudioPlayer`) and native views (e.g. `RealtimeAudioPlayerView`). ## Common commands Library (run from repo root): - `bun run build``expo-module build` (compiles `src/``build/`, the published JS). - `bun run build:plugin``expo-module build plugin` (compiles `plugin/src/``plugin/build/`, the config plugin loaded via `app.plugin.js`). - `bun run lint``expo-module lint` (uses `.eslintrc.js` extending `universe/native` + `universe/web`). - `bun run test``expo-module test`. - `bun run clean``expo-module clean`. - `bun run open:ios` / `bun run open:android` — open the example app's native projects in Xcode / Android Studio. Example app (`cd example`): - `bun install`, then `bun run ios` or `bun run android` (these run `expo run:*`, which prebuilds and compiles native code — needed after any iOS/Android source change). - `bun run start` for Metro only; `bun run web` for web. - The example uses `expo.autolinking.nativeModulesDir = ".."` so it picks up the parent module without publishing. - **`example/ios` and `example/android` are not checked in** — they are regenerated by `expo prebuild` (which `expo run:*` invokes automatically when missing). All native config for the example app comes from `example/app.json` plus the library's own config plugin (`../app.plugin.js`). If you need a project-specific native edit, add it to a config plugin rather than hand-editing the generated dirs. Requirements: Node 22 (for bun via corepack), Expo SDK 50+, iOS 15.1+, Android API 26+. ## Architecture ### Three parallel module families The library ships four Expo modules with the same shape repeated three times: **Player**, **Recorder**, **VADRecorder** (plus a top-level `RealtimeAudioModule` that just exposes `checkAndRequestAudioPermissions`). For each family there is: - TS: `src/RealtimeAudio{Player,Recorder,VADRecorder}Module.ts` (thin `requireNativeModule` wrapper) + `src/RealtimeAudio{...}View.tsx` (`requireNativeView` wrapper) + a `src/RealtimeAudio{...}.ts` class type. - iOS (Swift, in `ios/`): `RealtimeAudio{...}Module.swift` (Expo `Module` definition with both a `Class(...)` and a `View(...)` registration) backed by `RealtimeAudio{...}.swift` (the engine) and `RealtimeAudio{...}View.swift` (the native view). - Android (Kotlin, `android/src/main/java/com/paulingalls/realtimeaudio/`): same triple — `Module.kt`, engine `.kt`, `View.kt`. Each module's `Class(...)` block exposes the imperative API (`addBuffer`, `pause`, `resume`, `stop` / `startRecording`, `stopRecording` / `startListening`, `stopListening`). The matching `View(...)` block re-exposes those same functions plus the visualization `Prop`s (`waveformColor`, `visualizer`, `audioFormat`). Keep the JS, iOS, and Android surfaces in sync when changing any of them — names of events, props, and async functions must match across all three. Module names registered in `expo-module.config.json` are `RealtimeAudioModule`, `RealtimeAudioPlayerModule`, `RealtimeAudioRecorderModule`, `RealtimeAudioVADRecorderModule`. The TS `requireNativeModule` / `requireNativeView` calls reference the *Expo module name* (e.g. `"RealtimeAudioPlayer"`), not the class name. ### Visualizations Both platforms have a `BaseAudioView` that owns a swappable `AudioVisualization` (default `BarGraphVisualizer`). The four visualizer types — `barGraph`, `linearWaveform`, `circularWaveform`, `tripleCircle` (see `Visualizers` enum in `src/RealtimeAudio.types.ts`) — are mapped from the `visualizer` string prop inside each Module's `Prop("visualizer")` block. Adding a visualizer requires: a new file on each platform (e.g. `ios/FooVisualizer.swift`, `android/.../FooVisualizer.kt`), a new enum entry in `RealtimeAudio.types.ts`, and a new `else if` branch in **every** view-bearing module on both platforms. Views stop playback / drawing when offscreen (see `BaseAudioView` lifecycle hooks — `didMoveToWindow` on iOS, `onAttached/DetachedFromWindow` on Android). Recent commits show this pattern was added specifically to fix Android crashes; preserve it. ### VAD Voice Activity Detection uses Silero VAD via ONNX Runtime. The model file `silero_vad_16k_op15.onnx` is bundled into both platforms (iOS via `s.resource_bundles` in the podspec; Android via `src/main/assets/`) and loaded by `VadIterator.{swift,kt}`. Native deps: - iOS: `onnxruntime-objc` (CocoaPods, declared in `ios/RealtimeAudio.podspec`). - Android: `com.microsoft.onnxruntime:onnxruntime-android` and `com.tagtraum:pcmsampledsp` (the latter requires the **beatunes.com** Maven repo — see below). ### Config plugin `plugin/src/index.ts` is an Expo config plugin (re-exported by `app.plugin.js` from the built output) that: 1. Adds `NSMicrophoneUsageDescription` on iOS. 2. Appends the `https://www.beatunes.com/repo/maven2` repository to the consumer app's `app/build.gradle` (idempotent: it greps for `beatunes.com` first). This is required for the `pcmsampledsp` dependency. 3. Adds `RECORD_AUDIO` and `MODIFY_AUDIO_SETTINGS` Android permissions. Anything that changes the plugin must be rebuilt with `bun run build:plugin` before it takes effect for consumers. ### Build outputs - `build/` — published JS (referenced by `package.json` `main`/`types`). - `plugin/build/` — compiled config plugin (referenced by `app.plugin.js`). Both are checked-in artifacts of `expo-module build` / `expo-module build plugin`; rebuild before publishing.