Convert the printf-style MOZ_LOG calls in this area to the type-safe MOZ_LOG_FMT macro, which validates the format string against its arguments at compile time. This is a mechanical refactor with no behavior change. Differential Revision: https://phabricator.services.mozilla.com/D304271
160 lines
5.3 KiB
C++
160 lines
5.3 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "AudioStreamTrack.h"
|
|
|
|
#include "MediaTrackGraph.h"
|
|
#include "nsContentUtils.h"
|
|
|
|
extern mozilla::LazyLogModule gMediaStreamTrackLog;
|
|
#define LOG(type, ...) \
|
|
MOZ_LOG_FMT(gMediaStreamTrackLog, type, MOZ_LOG_EXPAND_ARGS __VA_ARGS__)
|
|
|
|
namespace mozilla::dom {
|
|
|
|
RefPtr<GenericPromise> AudioStreamTrack::AddAudioOutput(
|
|
void* aKey, AudioDeviceInfo* aSink) {
|
|
if (Ended()) {
|
|
return GenericPromise::CreateAndResolve(true, __func__);
|
|
}
|
|
|
|
mTrack->AddAudioOutput(aKey, aSink);
|
|
return mTrack->Graph()->NotifyWhenDeviceStarted(aSink);
|
|
}
|
|
|
|
void AudioStreamTrack::RemoveAudioOutput(void* aKey) {
|
|
if (Ended()) {
|
|
return;
|
|
}
|
|
|
|
mTrack->RemoveAudioOutput(aKey);
|
|
}
|
|
|
|
void AudioStreamTrack::SetAudioOutputVolume(void* aKey, float aVolume) {
|
|
if (Ended()) {
|
|
return;
|
|
}
|
|
|
|
mTrack->SetAudioOutputVolume(aKey, aVolume);
|
|
}
|
|
|
|
already_AddRefed<MediaInputPort> AudioStreamTrack::AddConsumerPort(
|
|
ProcessedMediaTrack* aTrack) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(!mTrack == Ended());
|
|
|
|
if (!mTrack || !aTrack || aTrack->IsDestroyed()) {
|
|
LOG(LogLevel::Warning,
|
|
("AudioStreamTrack {} cannot forward contents: track ended or "
|
|
"data/destination track ended/destroyed",
|
|
fmt::ptr(this)));
|
|
return nullptr;
|
|
}
|
|
|
|
MOZ_ASSERT(!mTrack->IsDestroyed());
|
|
if (mTrack->Graph() == aTrack->Graph()) {
|
|
return ForwardTrackContentsTo(aTrack);
|
|
}
|
|
|
|
LOG(LogLevel::Verbose,
|
|
("AudioStreamTrack {} forwarding cross-graph contents from track {} "
|
|
"(graph {}) to track {} (graph {})",
|
|
fmt::ptr(this), fmt::ptr(mTrack.get()), fmt::ptr(mTrack->Graph()),
|
|
fmt::ptr(aTrack), fmt::ptr(aTrack->Graph())));
|
|
|
|
// Route audio from mTrack through a cross-graph transmitter and receiver to
|
|
// aTrack.
|
|
MediaTrackGraph* rcvrGraph = aTrack->Graph();
|
|
|
|
// Find existing connection for this graph
|
|
for (auto& conn : mCrossGraphs) {
|
|
if (conn.mPort->mReceiver->Graph() == rcvrGraph) {
|
|
conn.mRefCount++;
|
|
LOG(LogLevel::Verbose, ("AudioStreamTrack {} reusing cross-graph port "
|
|
"to graph {} (rate {}), refcount now {}",
|
|
fmt::ptr(this), fmt::ptr(rcvrGraph),
|
|
rcvrGraph->GraphRate(), conn.mRefCount));
|
|
return aTrack->AllocateInputPort(conn.mPort->mReceiver);
|
|
}
|
|
}
|
|
|
|
// Create new connection if none exists
|
|
LOG(LogLevel::Verbose,
|
|
("AudioStreamTrack {} creating cross-graph port to graph {} (rate {})",
|
|
fmt::ptr(this), fmt::ptr(rcvrGraph), rcvrGraph->GraphRate()));
|
|
CrossGraphConnection* conn = mCrossGraphs.AppendElement(
|
|
CrossGraphConnection(CrossGraphPort::Connect(RefPtr{this}, rcvrGraph)));
|
|
return aTrack->AllocateInputPort(conn->mPort->mReceiver);
|
|
}
|
|
|
|
void AudioStreamTrack::RemoveConsumerPort(MediaInputPort* aPort) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!aPort) {
|
|
return;
|
|
}
|
|
|
|
MediaTrackGraph* receiverGraph = aPort->Graph();
|
|
|
|
// Decrement refcount for this graph's connection and remove if it reaches 0
|
|
for (size_t i = 0; i < mCrossGraphs.Length(); ++i) {
|
|
auto& conn = mCrossGraphs[i];
|
|
if (conn.mPort->mReceiver->Graph() == receiverGraph) {
|
|
MOZ_ASSERT(conn.mRefCount > 0);
|
|
--conn.mRefCount;
|
|
LOG(LogLevel::Verbose,
|
|
("AudioStreamTrack {} decrementing cross-graph port refcount to "
|
|
"graph {} (rate {}), refcount now {}",
|
|
fmt::ptr(this), fmt::ptr(receiverGraph), receiverGraph->GraphRate(),
|
|
conn.mRefCount));
|
|
if (conn.mRefCount == 0) {
|
|
LOG(LogLevel::Verbose,
|
|
("AudioStreamTrack {} removing cross-graph forwarding to graph {} "
|
|
"(rate {})",
|
|
fmt::ptr(this), fmt::ptr(receiverGraph),
|
|
receiverGraph->GraphRate()));
|
|
mCrossGraphs.UnorderedRemoveElementAt(i);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AudioStreamTrack::GetLabel(nsAString& aLabel, CallerType aCallerType) {
|
|
MediaStreamTrack::GetLabel(aLabel, aCallerType);
|
|
}
|
|
|
|
already_AddRefed<MediaStreamTrack> AudioStreamTrack::Clone() {
|
|
return MediaStreamTrack::CloneInternal<AudioStreamTrack>();
|
|
}
|
|
|
|
void AudioStreamTrack::SetReadyState(MediaStreamTrackState aState) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// When transitioning from Live to Ended, mTrack will be destroyed. Since
|
|
// mTrack is the source for cross-graph data forwarding, keeping cross-graph
|
|
// ports is unnecessary. Clearing them here ensures all related connections
|
|
// are properly disconnected and prevents an assertion failure in
|
|
// CrossGraphTransmitters::ProcessInput due to a missing source.
|
|
//
|
|
// This state transition may occur in various situations, such as when the
|
|
// track is stopped by a user action, or when mTrack is ended during its
|
|
// ProcessInput (because its source has ended), which is then detected by
|
|
// MediaTrackGraph and ultimately notifies the ended-signal via MTGListener,
|
|
// reaching this point.
|
|
if (!mCrossGraphs.IsEmpty() && aState == MediaStreamTrackState::Ended) {
|
|
MOZ_ASSERT(!Ended());
|
|
LOG(LogLevel::Verbose,
|
|
("AudioStreamTrack {} ending, destroying {} cross-graph ports",
|
|
fmt::ptr(this), mCrossGraphs.Length()));
|
|
mCrossGraphs.Clear();
|
|
}
|
|
|
|
MediaStreamTrack::SetReadyState(aState);
|
|
}
|
|
|
|
} // namespace mozilla::dom
|
|
|
|
#undef LOG
|