Skip to content

Expose WebRTC's audio_mixer#806

Merged
xianshijing-lk merged 4 commits intolivekit:mainfrom
Be-ing:audio_mixer
Dec 12, 2025
Merged

Expose WebRTC's audio_mixer#806
xianshijing-lk merged 4 commits intolivekit:mainfrom
Be-ing:audio_mixer

Conversation

@Be-ing
Copy link
Copy Markdown
Contributor

@Be-ing Be-ing commented Dec 4, 2025

This allows one to use the apm to cancel echo in multiway calls.

This is a rebase of #613 with merge conflicts fixed.

@Be-ing
Copy link
Copy Markdown
Contributor Author

Be-ing commented Dec 4, 2025

@xianshijing-lk This is an older PR that Zed has been using downstream for a while. I rebased it and ran clang-format on the C++ code. It would be great to get this merged.

}
}

pub trait AudioMixerSource {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How is the thread safety for the audio mixer ?

I feel like they are not safe but my limited rust knowledge is not enough to get deep into it.

@ladvoc, could you please help review the code and look at the thread safety ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Great question. I merely rebased this code and did not write it, so I was not very familiar before you asked. The thread safety of livekit::AudioMixer on the C++ side is not good. livekit::AudioMixer stores its own std::vector<std::shared_ptr<AudioMixerSource>> sources_ member. I don't see the reason for this. libwebrtc's webrtc::AudioMixerImpl stores its own list of sources internally which are guarded by a mutex. So livekit::AudioMixer seems to add a redundant list on top of that but without the thread safety, despite the manual impl's for Send + Sync traits.

This seems to not have been a practical issue for Zed because Zed wraps its AudioMixer with Arc<Mutex> on the Rust side. However, just looking at the Rust API exposed by the libwebrtc crate here, there is no reason for anyone who didn't write this code to suspect that Arc<Mutex> is necessary without documentation. There are also no SAFETY comments in the higher level Rust wrappers in the libwebrtc crate for the unsafe blocks documenting why it is safe to call the unsafe lower level functions.

From a quick look, I think there are several other parts of these new APIs that are redundant or overcomplicated.

I will talk with @ConradIrwin about how to proceed here. We have a pair coding call scheduled for Friday.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think I did it that way to make it easier to implement remove, but there are probably other approaches we could take.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, my previous replies were lost.

I think std::vector<std::shared_ptr> sources_ is needed, livekit::AudioMixer AddSouce / RemoveSouce does call into webrtc::AudioMixerImpl, but they just pass the raw pointers there, thus WebRTC lib does not own the object. That is the reason that std::vector<std::shared_ptr> sources_ solve the problem as we need a owner to the AudioMixerSource.
And we need to keep them.

I think Zed solved the racing issue by using Arc.

My suggestion is to make the C++ livekit::AudioMixer thread safe, something like

std::mutex sources_mutex_;

void AudioMixer::add_source(rust::Box<AudioMixerSourceWrapper> source) {
  auto native_source = std::make_shared<AudioMixerSource>(std::move(source));
  {
    std::lock_guard<std::mutex> lock(sources_mutex_);
    audio_mixer_->AddSource(native_source.get());
    sources_.push_back(native_source);
  }
}

void AudioMixer::remove_source(int source_ssrc) {
  std::lock_guard<std::mutex> lock(sources_mutex_);
  auto it = std::find_if(
      sources_.begin(), sources_.end(),
      [source_ssrc](const auto& s) { return s->Ssrc() == source_ssrc; });

  if (it != sources_.end()) {
    audio_mixer_->RemoveSource(it->get());
    sources_.erase(it);
  }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point about the lifetime; AudioMixerImpl in libwebrtc does keep its own vector of sources internally, but those are AudioMixerImpl::SourceStatus structs which have a plain pointer Source* member. So it is helpful to have this vector of std::shared_pointers above it.

We added a mutex guarding add/remove_source to resolve the thread safety issue with that. Unless you see any more thread safety issues, I think it's okay now.

@xianshijing-lk xianshijing-lk requested a review from ladvoc December 8, 2025 17:22
@xianshijing-lk
Copy link
Copy Markdown
Contributor

Hi @ladvoc , could you please help review the Rust code ? especially on the thread safety.

The c++ code is not thread safe but I wonder if that is covered by the Rust somehow

ConradIrwin and others added 4 commits December 12, 2025 14:06
This allows one to use the apm to cancel echo in multiway calls.

Co-Authored-By: Mikayla <mikayla@zed.dev> Co-Authored-By: Zed AI
<ai+claude-3.5@zed.dev>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Copy link
Copy Markdown
Contributor

@xianshijing-lk xianshijing-lk left a comment

Choose a reason for hiding this comment

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

Thanks for addressing the comments, it looks good to me now

@Be-ing
Copy link
Copy Markdown
Contributor Author

Be-ing commented Dec 12, 2025

Ready for merge or are we waiting for another review?

@xianshijing-lk
Copy link
Copy Markdown
Contributor

I think you can merge it now

@xianshijing-lk
Copy link
Copy Markdown
Contributor

For @ladvoc or @cloudwebrtc , if you have some pending comments, lets make some follow-up PRs to address them

@Be-ing
Copy link
Copy Markdown
Contributor Author

Be-ing commented Dec 12, 2025

I think you can merge it now

Well, I can't merge it, that's up to you or someone else at Livekit 😃

@xianshijing-lk xianshijing-lk merged commit 8b69e08 into livekit:main Dec 12, 2025
17 checks passed
@xianshijing-lk
Copy link
Copy Markdown
Contributor

I see. Sorry, I missed that. And just pressed the button here.

@xianshijing-lk
Copy link
Copy Markdown
Contributor

Thanks for the great work, and please ping me if you have more PRs to review.

@github-actions github-actions bot mentioned this pull request Dec 12, 2025
@Be-ing Be-ing deleted the audio_mixer branch December 12, 2025 22:24
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.

3 participants