Skip to content

fix: Web safari audio context reuse#1972

Merged
Gustl22 merged 1 commit into
bluefireteam:mainfrom
Szymon-Gesicki:fix/web-safari-audio-context-reuse
Feb 22, 2026
Merged

fix: Web safari audio context reuse#1972
Gustl22 merged 1 commit into
bluefireteam:mainfrom
Szymon-Gesicki:fix/web-safari-audio-context-reuse

Conversation

@Szymon-Gesicki

@Szymon-Gesicki Szymon-Gesicki commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

Description

Fix audio playback on Safari (web) by reusing a single AudioContext per player instance and explicitly resuming it before playback.

Closes #1759

Existing behavior:
recreateNode() created a new web.AudioContext() on every call and stored it only as a local variable. This caused three problems:

  1. Safari starts new AudioContexts in suspended state and requires an explicit resume() within a user gesture — this call was missing entirely, so audio never played.
  2. The AudioContext reference was lost after recreateNode() returned, making it impossible to resume or close later.
  3. Old AudioContexts were never closed, leaking resources. Safari enforces a limit of ~4–6 AudioContexts per page, so after a few play/release cycles the limit was exhausted and no new context could be created.

Chrome auto-resumes AudioContexts, which is why the issue only manifested on Safari.

Changes:

  • Store AudioContext and MediaElementAudioSourceNode as class-level fields on WrappedPlayer.
  • Reuse the existing AudioContext across recreateNode() calls (_audioContext ??= web.AudioContext()).
  • Call audioContext.resume() in start() when the context is suspended (required by Safari).
  • Disconnect _sourceNode in release() for proper cleanup without closing the shared context.
  • Close and null the AudioContext in dispose() to prevent resource leaks.

All changes are in a single file: packages/audioplayers_web/lib/wrapped_player.dart.

Checklist

  • The title of my PR starts with a Conventional Commit prefix (fix:, feat:, refactor:,
    docs:, chore:, test:, ci: etc).
  • I have read the Contributor Guide and followed the process outlined for submitting PRs.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation and added dartdoc comments with ///, where necessary.
  • I have updated/added relevant examples in example.

Breaking Change

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

Related Issues

@Szymon-Gesicki Szymon-Gesicki mentioned this pull request Feb 15, 2026
2 tasks

@spydon spydon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

@Gustl22 Gustl22 changed the title fix: web safari audio context reuse fix: Web safari audio context reuse Feb 22, 2026
@Gustl22

Gustl22 commented Feb 22, 2026

Copy link
Copy Markdown
Collaborator

Thank you for your contribution!

@Gustl22 Gustl22 enabled auto-merge (squash) February 22, 2026 22:13
@Gustl22 Gustl22 merged commit bd698bb into bluefireteam:main Feb 22, 2026
75 of 78 checks passed
@Gustl22

Gustl22 commented Feb 22, 2026

Copy link
Copy Markdown
Collaborator

@Szymon-Gesicki Actually I wanted to reproduce your error. I tested online via https://bluefireteam.github.io/audioplayers/ which still has a build without your fix and also tested locally.

I could not reproduce your issue: The audio played multiple times in "release" mode, even after 10 times.

  • Can you provide more clear reproduction steps? (The exact steps you do to hit this problem incl. resources)
  • Does it only affect Safari on mac or also on iOS?
  • Can you give sources for the assumption of the amount of AudioContexts in a session a mac does provide?
  • Which OS and Safari Version do you use?

@Szymon-Gesicki

Szymon-Gesicki commented Feb 23, 2026

Copy link
Copy Markdown
Contributor Author

Hi, thanks for testing, let me clarify:

Can you provide more clear reproduction steps? (The exact steps you do to hit this problem incl. resources)

The third print("play 3") call produces no audio on Safari, on chrome everything works perfect.

final player = AudioPlayer();                                                                                                        
                                                                                                                                     
String audioUrl1 = "https://cdn.pixabay.com/audio/2021/08/04/audio_12b0c7443c.mp3";
String audioUrl2 = "https://actions.google.com/sounds/v1/cartoon/wood_plank_flicks.ogg";
String audioUrl3 =  "https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg";

print("play 1");
await player.play(UrlSource(audioUrl3));
await Future.delayed(const Duration(seconds: 3));
await player.stop();

print("play 2");
await player.play(UrlSource(audioUrl2));
await Future.delayed(const Duration(seconds: 3));
await player.stop();

print("play 3");
await player.play(UrlSource(audioUrl1));
await Future.delayed(const Duration(seconds: 3));
await player.stop();

Does it only affect Safari on mac or also on iOS?
Which OS and Safari Version do you use?

I initially only tested on macOS 15.7.3, Safari 18.6. I tested on iOS today and unfortunately the problem still occurs there. I will work on a fix for that. I'm also preparing a separate fix for a volume setting issue on Safari. When I do that, I will also test macOS 26.

Can you give sources for the assumption of the amount of AudioContexts in a session a mac does provide?

https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/AudioContext:

"The specification doesn't indicate a maximum or minimum number of audio contexts that must be able to be open at the same time, so this is left up to the browser implementations to decide."

https://github.com/WebKit/WebKit/blob/main/Source/WebCore/Modules/webaudio/AudioContext.cpp#L75:

#if OS(WINDOWS) // Don't allow more than this number of simultaneous AudioContexts talking to hardware. constexpr unsigned maxHardwareContexts = 4; if (hardwareContextCount >= maxHardwareContexts) return Exception { ExceptionCode::QuotaExceededError, "Reached maximum number of hardware contexts on this platform"_s };

I don't have anything black on white confirming the same limit on macOS Safari specifically.

Gustl22 added a commit that referenced this pull request Feb 27, 2026
Gustl22 added a commit that referenced this pull request Feb 27, 2026
@Gustl22

Gustl22 commented Feb 27, 2026

Copy link
Copy Markdown
Collaborator

I think your other problem is not releated to Safari, it didn't work on Chrome either:
I fixed it in: #1973

Gustl22 added a commit that referenced this pull request Feb 27, 2026
# Description

If playing multiple sources one after one in the same player, the
sources sometimes would not play in `release` mode.

```dart
final player = AudioPlayer();

String audioUrl1 = "https://cdn.pixabay.com/audio/2021/08/04/audio_12b0c7443c.mp3";

print("play 1");
await player.play(UrlSource(audioUrl1));
await Future.delayed(const Duration(seconds: 3));
await player.stop();

print("play 2");
await player.play(UrlSource(audioUrl1));
await Future.delayed(const Duration(seconds: 3));
await player.stop();

print("play 3");
await player.play(UrlSource(audioUrl1));
await Future.delayed(const Duration(seconds: 3));
await player.stop();
```

The `pausedAt` property is now reset, when calling `release` which
allows playing the next source at 0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No Sound on Safari macOS

3 participants