npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-call-audio

v0.2.0

Published

In-call audio session ownership + output routing (earpiece/speaker/bluetooth/wired) and proximity-to-screen-off for React Native (Expo Modules, New Architecture). Works with LiveKit, react-native-webrtc, or any call stack.

Readme

react-native-call-audio

In-call audio session ownership and output routing (earpiece / speaker / bluetooth / wired) plus proximity-to-screen-off, for React Native (Expo Modules API, New Architecture). One JS API, native implementations per platform:

  • AndroidAudioManager.setCommunicationDevice (API 31+), AudioDeviceCallback for real device-change events, PROXIMITY_SCREEN_OFF_WAKE_LOCK.
  • iOSAVAudioSession routing + speaker override, routeChangeNotification, isProximityMonitoringEnabled.

It depends on no calling SDK. It works with LiveKit, react-native-webrtc, Twilio, Agora, Daily, SIP, or no WebRTC at all.

Install

npm install react-native-call-audio
npx expo prebuild

Peer deps: expo, react, react-native. No LiveKit / WebRTC dependency.

Usage

import {
  startCallAudio,
  stopCallAudio,
  setRoute,
  getDevices,
  setProximityEnabled,
  hasBluetoothPermission,
  addDevicesChangedListener,
} from "react-native-call-audio";

// On call connect:
startCallAudio();              // owns the session, starts on earpiece
setProximityEnabled(true);     // ear-to-phone blanks the screen

const sub = addDevicesChangedListener(({ available, selected }) => {
  // available: ("earpiece" | "speaker" | "bluetooth" | "wired")[]
  // selected:  the current output
});

setRoute("speaker");           // returns the route applied

// On call end:
sub.remove();
setProximityEnabled(false);
stopCallAudio();

startCallAudio() / stopCallAudio() are idempotent — calling start twice (or stop twice) is a no-op, so they're safe to wire to call lifecycle events that may fire more than once.

API

| Function | Returns | Notes | | --- | --- | --- | | startCallAudio() | void | Own the session (MODE_IN_COMMUNICATION / playAndRecord), start on earpiece. Idempotent. | | stopCallAudio() | void | Release the session, restore prior mode. Idempotent. | | setRoute(route) | CallAudioRoute | Force output; returns the route actually applied. | | getDevices() | { available, selected } | Current routes (same shape as onAudioDevicesChanged). | | setProximityEnabled(enabled) | void | Proximity-to-screen-off, held only during a call. | | hasBluetoothPermission() | boolean | See Bluetooth note below. Always true on iOS / Android ≤11. | | addDevicesChangedListener(cb) | EventSubscription | Fires on headset/BT connect & drop and on route changes. | | addProximityListener(cb) | EventSubscription | { near: boolean }. |

route is "earpiece" | "speaker" | "bluetooth" | "wired". "wired" covers wired headsets/headphones, USB-C audio, and CarPlay.

⚠️ Using with a WebRTC SDK (LiveKit, react-native-webrtc, etc.)

This module owns the call audio session. If your WebRTC SDK also manages the audio session (most do by default), the two will fight — last writer wins, routing becomes non-deterministic, and on Android the device list comes back empty. You MUST tell the WebRTC SDK to NOT manage audio so this module is the sole owner.

LiveKit (@livekit/react-native) — before any LiveKit usage (e.g. index.ts):

import { registerGlobals } from "@livekit/react-native";

// Let react-native-call-audio own the session; LiveKit must not also manage it.
registerGlobals({ autoConfigureAudioSession: false });

Do not call setupIOSAudioManagement or AudioSession.startAudioSession() / configureAudio() — those hand the session back to LiveKit and reintroduce the conflict.

Other WebRTC stacks — disable their built-in audio-session/route management (the equivalent of the flag above) and drive routing only through this module.

Platform support

  • Android 12+ (API 31+): modern setCommunicationDevice + AudioDeviceCallback.
  • Android 5–11 (API 21–30): legacy setSpeakerphoneOn + Bluetooth SCO, with a BroadcastReceiver for device-change events. Floor is API 21.
  • iOS 15.1+ (the APIs used go back further; the floor just matches typical apps).

Platform notes

  • iOS: BT/wired auto-route when connected; setRoute("bluetooth"/"wired") clears the speaker override and lets the OS route to the connected device. No per-app permission is needed for output routing, so hasBluetoothPermission() is always true on iOS.

  • Android Bluetooth (API 31+): the module declares BLUETOOTH_CONNECT via manifest merge, but on Android 12+ that permission is runtime — the manifest entry alone is not enough. Until the user grants it, setCommunicationDevice can't see BT devices and setRoute("bluetooth") silently falls back to the current route.

    The library does not request the permission for you — requesting it is the app's responsibility. Request BLUETOOTH_CONNECT yourself (the module already declares it, so no manifest edits are needed), then use hasBluetoothPermission() to gate your Bluetooth control:

    import { PermissionsAndroid, Platform } from "react-native";
    import { hasBluetoothPermission, setRoute } from "react-native-call-audio";
    
    async function enableBluetooth() {
      if (Platform.OS === "android" && !hasBluetoothPermission()) {
        const result = await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
        );
        if (result !== PermissionsAndroid.RESULTS.GRANTED) return; // user denied
      }
      setRoute("bluetooth");
    }

    On Android ≤11 the install-time BLUETOOTH permission applies and hasBluetoothPermission() returns true, so no runtime request is required.

Changelog

0.2.0

  • Add hasBluetoothPermission() — on Android 12+ the BLUETOOTH_CONNECT grant is required at runtime for BT routing; use this to gate your Bluetooth control.
  • "wired" routing now also covers USB-C audio and CarPlay (iOS usbAudio/carAudio, Android TYPE_USB_HEADSET).
  • startCallAudio() / stopCallAudio() are now idempotent (a duplicate start no longer corrupts the saved audio mode restored on stop).

0.1.0

  • Initial release: session ownership, earpiece/speaker/bluetooth/wired routing, device-change events, proximity-to-screen-off.