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

expo-audio-session

v1.0.1

Published

Expo module to resume the user's background music (Spotify, Apple Music…) after your app plays audio — deactivates the iOS AVAudioSession that expo-video leaves active

Readme

🎧 Expo Audio Session

Resume the user's background music after your app plays audio

An Expo module that deactivates the shared iOS audio session (AVAudioSession) once your app is done playing audio, notifying other audio apps (Spotify, Apple Music…) that they can resume playback. Built to fix the classic expo-video issue where the user's background music stays paused forever after a video played with sound.


🐛 The Problem

expo-video activates the shared AVAudioSession whenever one of its players outputs audio — but it never deactivates it. The consequences for your users:

  • 🎵 They're listening to Spotify / Apple Music
  • 📹 They open a video in your app, with sound → their music pauses (expected)
  • ❌ They close the video → their music never resumes

On iOS, the only way to tell other apps they can resume is to deactivate your audio session with the .notifyOthersOnDeactivation option. That's exactly what this module does.


✨ Features

  • Deactivate the iOS audio session with .notifyOthersOnDeactivation so background music resumes
  • deactivateKeepingPlayback helper for players that keep playing muted (feeds, loops)
  • No config plugin needed — just install and rebuild
  • Safe to call from shared code — no-op on Android

🚀 Quick Start

Installation

# Using npm
npm install expo-audio-session

# Using yarn
yarn add expo-audio-session

# Using pnpm
pnpm add expo-audio-session

# Using Expo CLI
npx expo install expo-audio-session

ℹ️ Note: This module contains native code — rebuild your dev client (npx expo prebuild + build, or eas build) after installing. No config plugin required, autolinking does everything.

📖 Usage

🎯 Basic Example

import ExpoAudioSession from 'expo-audio-session';

// When your app is done outputting audio (video closed, player muted…):
// the user's background music resumes.
await ExpoAudioSession.deactivateAsync();

🎬 With expo-video

import ExpoAudioSession from 'expo-audio-session';
import { useVideoPlayer, VideoView } from 'expo-video';
import { useEffect } from 'react';

export function FullscreenVideo({ uri }: { uri: string }) {
  const player = useVideoPlayer(uri, (player) => {
    player.play();
  });

  useEffect(() => {
    return () => {
      // The screen closes → tell iOS we are done with audio so the user's
      // music resumes. The player is released on unmount, so audio I/O stops
      // and deactivation succeeds.
      ExpoAudioSession.deactivateAsync().catch(() => {
        // Another player still outputs sound or the session is already
        // inactive: the music simply does not resume, never fatal.
      });
    };
  }, []);

  return <VideoView player={player} style={{ flex: 1 }} />;
}

🔇 Video that keeps playing muted

iOS refuses to deactivate the session while audio I/O is running. If your player keeps playing (e.g. a feed video that goes back to muted after fullscreen), use the helper — it briefly pauses the player around the deactivation, invisible in practice on a muted looping video:

import { deactivateKeepingPlayback } from 'expo-audio-session';

player.muted = true;
await deactivateKeepingPlayback(player);

📚 API Reference

🔧 Methods

deactivateAsync(options?: DeactivateOptions): Promise<void>

Deactivate the shared audio session, notifying other audio apps they can resume. Call it once your app is done outputting audio. Rejects if the session could not be deactivated (typically: a player is still outputting sound).

No-op on Android.

| Option | Type | Default | Description | | --- | --- | --- | --- | | notifyOthersOnDeactivation | boolean | true | Tell other audio apps they can resume — the whole point of the module |

deactivateKeepingPlayback(player: PausablePlayer, options?: DeactivateOptions): Promise<void>

Deactivate the session under a player that keeps playing muted: briefly pauses the player around the deactivateAsync call and resumes it afterwards. PausablePlayer is the minimal { playing, pause(), play() } shape — VideoPlayer from expo-video matches it out of the box.


📱 Platform Support

🍎 iOS

  • Full AVAudioSession support
  • .notifyOthersOnDeactivation

🤖 Android

  • No-op for compatibility
  • Audio focus is per-request: whoever plays the audio (ExoPlayer) requests and abandons its own focus — nothing an external module can safely release
  • See What about Android? for the expo-video patch that fixes it

🌐 Web

  • Not supported
  • Will throw errors if used

🤖 What about Android?

Android has the same symptom (music never resumes after a video played with sound), but the cause — and the fix — live inside expo-video itself, which is why this module is a no-op there.

On Android, audio focus is per-request: ExoPlayer requests focus when playback starts and abandons it when playback stops. The problem is the focus type expo-video requests in AudioMixingMode.AUTO (the default): AUDIOFOCUS_GAIN signals a permanent takeover, so music apps (Spotify, YouTube Music…) treat it as "this app owns audio now" and never resume when the focus is abandoned. Requesting AUDIOFOCUS_GAIN_TRANSIENT instead signals a temporary interruption — music apps pause, then resume by themselves once your video stops outputting audio.

Until this is fixed upstream, patch expo-video with yarn patch (or patch-package for npm):

yarn patch expo-video
# edit the file below inside the printed folder, then:
yarn patch-commit -s <printed-folder>

Apply this change in android/src/main/java/expo/modules/video/managers/AudioFocusManager.kt:

     val audioFocusType = when (audioMixingMode) {
       AudioMixingMode.DUCK_OTHERS -> AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
-      AudioMixingMode.AUTO -> AudioManager.AUDIOFOCUS_GAIN
+      // Transient focus so music apps (Spotify…) resume by themselves once
+      // our video stops outputting audio and the focus is abandoned.
+      // A permanent AUDIOFOCUS_GAIN never resumes them.
+      AudioMixingMode.AUTO -> AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
       AudioMixingMode.DO_NOT_MIX -> AudioManager.AUDIOFOCUS_GAIN
       else -> AudioManager.AUDIOFOCUS_GAIN
     }

Then rebuild your dev client. No call to this module is needed on Android — the patch alone makes the music resume.


🛠️ Troubleshooting

🚨 Common Issues

Problem: deactivateAsync() rejects, or resolves but the music stays paused.

Solution: iOS refuses to deactivate the session while audio I/O is running. Make sure every player is paused, released, or muted before calling deactivateAsync(). For a player that must keep playing muted, use deactivateKeepingPlayback(player).

Problem: The native module is not found at runtime.

Solution:

  1. This module contains native code and does not work in Expo Go — use a dev client
  2. Rebuild your dev client after installing (npx expo prebuild + build, or eas build)
  3. Clean and rebuild your project

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


🤝 Contributing

We welcome contributions! Here's how you can help:

  1. 🍴 Fork the repository
  2. 🌿 Create a feature branch (git checkout -b feature/amazing-feature)
  3. 💾 Commit your changes (git commit -m 'Add some amazing feature')
  4. 📤 Push to the branch (git push origin feature/amazing-feature)
  5. 🔄 Open a Pull Request

🐛 Found a Bug?

Please open an issue with:

  • 📱 Device information
  • 📋 Steps to reproduce
  • 📝 Expected vs actual behavior

💡 Have an Idea?

We'd love to hear your suggestions! Open an issue with the enhancement label.


⭐ Star this repo if you found it helpful!