Bug 1860954 name GraphDriver audio streams with document title r=padenot

Differential Revision: https://phabricator.services.mozilla.com/D191837
This commit is contained in:
Karl Tomlinson 2023-10-26 21:51:55 +00:00
Родитель 3dc85f36e6
Коммит 04a0140bc4
7 изменённых файлов: 226 добавлений и 39 удалений

Просмотреть файл

@ -44,10 +44,17 @@ GraphDriver::GraphDriver(GraphInterface* aGraphInterface,
mSampleRate(aSampleRate),
mPreviousDriver(aPreviousDriver) {}
void GraphDriver::SetState(GraphTime aIterationEnd,
void GraphDriver::SetStreamName(const nsACString& aStreamName) {
MOZ_ASSERT(InIteration() || (!ThreadRunning() && NS_IsMainThread()));
mStreamName = aStreamName;
}
void GraphDriver::SetState(const nsACString& aStreamName,
GraphTime aIterationEnd,
GraphTime aStateComputedTime) {
MOZ_ASSERT(InIteration() || !ThreadRunning());
mStreamName = aStreamName;
mIterationEnd = aIterationEnd;
mStateComputedTime = aStateComputedTime;
}
@ -219,7 +226,7 @@ void ThreadedDriver::RunThread() {
if (GraphDriver* nextDriver = result.NextDriver()) {
LOG(LogLevel::Debug, ("%p: Switching to AudioCallbackDriver", Graph()));
result.Switched();
nextDriver->SetState(mIterationEnd, mStateComputedTime);
nextDriver->SetState(mStreamName, mIterationEnd, mStateComputedTime);
nextDriver->Start();
break;
}
@ -288,14 +295,17 @@ MediaTime OfflineClockDriver::GetIntervalForIteration() {
}
AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver,
AsyncCubebOperation aOperation)
AsyncCubebOperation aOperation,
const nsACString& aName)
: Runnable("AsyncCubebTask"),
mDriver(aDriver),
mOperation(aOperation),
mName(aName),
mShutdownGrip(aDriver->Graph()) {
MOZ_ASSERT(mDriver->mAudioStreamState ==
AudioCallbackDriver::AudioStreamState::Pending ||
aOperation == AsyncCubebOperation::SHUTDOWN,
MOZ_ASSERT((aOperation == AsyncCubebOperation::SHUTDOWN) == aName.IsVoid());
MOZ_ASSERT(aOperation != AsyncCubebOperation::INIT ||
mDriver->mAudioStreamState ==
AudioCallbackDriver::AudioStreamState::Pending,
"Replacing active stream!");
}
@ -309,7 +319,13 @@ AsyncCubebTask::Run() {
case AsyncCubebOperation::INIT: {
LOG(LogLevel::Debug, ("%p: AsyncCubebOperation::INIT driver=%p",
mDriver->Graph(), mDriver.get()));
mDriver->Init();
mDriver->Init(mName);
break;
}
case AsyncCubebOperation::NAME_CHANGE: {
LOG(LogLevel::Debug, ("%p: AsyncCubebOperation::NAME_CHANGE driver=%p",
mDriver->Graph(), mDriver.get()));
mDriver->SetCubebStreamName(mName);
break;
}
case AsyncCubebOperation::SHUTDOWN: {
@ -350,14 +366,15 @@ class AudioCallbackDriver::FallbackWrapper : public GraphInterface {
public:
FallbackWrapper(RefPtr<GraphInterface> aGraph,
RefPtr<AudioCallbackDriver> aOwner, uint32_t aSampleRate,
GraphTime aIterationEnd, GraphTime aStateComputedTime)
const nsACString& aStreamName, GraphTime aIterationEnd,
GraphTime aStateComputedTime)
: mGraph(std::move(aGraph)),
mOwner(std::move(aOwner)),
mFallbackDriver(
MakeRefPtr<SystemClockDriver>(this, nullptr, aSampleRate)),
mIterationEnd(aIterationEnd),
mStateComputedTime(aStateComputedTime) {
mFallbackDriver->SetState(mIterationEnd, mStateComputedTime);
mFallbackDriver->SetState(aStreamName, mIterationEnd, mStateComputedTime);
}
NS_DECL_THREADSAFE_ISUPPORTS
@ -368,6 +385,9 @@ class AudioCallbackDriver::FallbackWrapper : public GraphInterface {
RefPtr<SystemClockDriver> driver = mFallbackDriver;
driver->Shutdown();
}
void SetStreamName(const nsACString& aStreamName) {
mFallbackDriver->SetStreamName(aStreamName);
}
void EnsureNextIteration() { mFallbackDriver->EnsureNextIteration(); }
#ifdef DEBUG
bool InIteration() { return mFallbackDriver->InIteration(); }
@ -446,7 +466,8 @@ class AudioCallbackDriver::FallbackWrapper : public GraphInterface {
("%p: Switching from fallback to other driver.",
mOwner.get()));
result.Switched();
nextDriver->SetState(mIterationEnd, mStateComputedTime);
nextDriver->SetState(mOwner->mStreamName, mIterationEnd,
mStateComputedTime);
nextDriver->Start();
} else if (result.IsStop()) {
LOG(LogLevel::Debug,
@ -546,7 +567,7 @@ bool IsMacbookOrMacbookAir() {
return false;
}
void AudioCallbackDriver::Init() {
void AudioCallbackDriver::Init(const nsCString& aStreamName) {
TRACE("AudioCallbackDriver::Init");
MOZ_ASSERT(OnCubebOperationThread());
MOZ_ASSERT(mAudioStreamState == AudioStreamState::Pending);
@ -645,12 +666,14 @@ void AudioCallbackDriver::Init() {
}
cubeb_stream* stream = nullptr;
const char* streamName =
aStreamName.IsEmpty() ? "AudioCallbackDriver" : aStreamName.get();
bool inputWanted = mInputChannelCount > 0;
CubebUtils::AudioDeviceID outputId = mOutputDeviceID;
CubebUtils::AudioDeviceID inputId = mInputDeviceID;
if (CubebUtils::CubebStreamInit(
cubebContext, &stream, "AudioCallbackDriver", inputId,
cubebContext, &stream, streamName, inputId,
inputWanted ? &input : nullptr,
forcedOutputDeviceId ? forcedOutputDeviceId : outputId, &output,
latencyFrames, DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
@ -698,6 +721,12 @@ void AudioCallbackDriver::Init() {
LOG(LogLevel::Debug, ("%p: AudioCallbackDriver started.", Graph()));
}
void AudioCallbackDriver::SetCubebStreamName(const nsCString& aStreamName) {
MOZ_ASSERT(OnCubebOperationThread());
MOZ_ASSERT(mAudioStream);
cubeb_stream_set_name(mAudioStream, aStreamName.get());
}
void AudioCallbackDriver::Start() {
MOZ_ASSERT(!IsStarted());
MOZ_ASSERT(mAudioStreamState == AudioStreamState::None);
@ -727,8 +756,8 @@ void AudioCallbackDriver::Start() {
LOG(LogLevel::Debug, ("Starting new audio driver off main thread, "
"to ensure it runs after previous shutdown."));
RefPtr<AsyncCubebTask> initEvent =
new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::INIT);
RefPtr<AsyncCubebTask> initEvent = new AsyncCubebTask(
AsAudioCallbackDriver(), AsyncCubebOperation::INIT, mStreamName);
initEvent->Dispatch();
}
@ -782,6 +811,31 @@ void AudioCallbackDriver::Shutdown() {
"AudioCallbackDriver::Shutdown"_ns);
}
void AudioCallbackDriver::SetStreamName(const nsACString& aStreamName) {
MOZ_ASSERT(InIteration() || !ThreadRunning());
if (aStreamName == mStreamName) {
return;
}
// Record the stream name, which will be passed onto the next driver, if
// any, either from this driver or the fallback driver.
GraphDriver::SetStreamName(aStreamName);
{
auto fallbackLock = mFallback.Lock();
FallbackWrapper* fallback = fallbackLock.ref().get();
if (fallback) {
MOZ_ASSERT(fallback->OnThread());
fallback->SetStreamName(aStreamName);
}
}
AudioStreamState streamState = mAudioStreamState;
if (streamState != AudioStreamState::None &&
streamState != AudioStreamState::Stopping) {
RefPtr<AsyncCubebTask> nameChange = new AsyncCubebTask(
AsAudioCallbackDriver(), AsyncCubebOperation::NAME_CHANGE, mStreamName);
nameChange->Dispatch();
}
}
/* static */
long AudioCallbackDriver::DataCallback_s(cubeb_stream* aStream, void* aUser,
const void* aInputBuffer,
@ -994,7 +1048,7 @@ long AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
}
result.Switched();
mAudioStreamState = AudioStreamState::Stopping;
nextDriver->SetState(mIterationEnd, mStateComputedTime);
nextDriver->SetState(mStreamName, mIterationEnd, mStateComputedTime);
nextDriver->Start();
if (!mSandboxed) {
CallbackThreadRegistry::Get()->Unregister(mAudioThreadId);
@ -1212,8 +1266,9 @@ void AudioCallbackDriver::FallbackToSystemClockDriver() {
mNextReInitBackoffStep =
TimeDuration::FromMilliseconds(AUDIO_INITIAL_FALLBACK_BACKOFF_STEP_MS);
mNextReInitAttempt = TimeStamp::Now() + mNextReInitBackoffStep;
auto fallback = MakeRefPtr<FallbackWrapper>(
Graph(), this, mSampleRate, mIterationEnd, mStateComputedTime);
auto fallback =
MakeRefPtr<FallbackWrapper>(Graph(), this, mSampleRate, mStreamName,
mIterationEnd, mStateComputedTime);
{
auto driver = mFallback.Lock();
driver.ref() = fallback;

Просмотреть файл

@ -277,6 +277,9 @@ class GraphDriver {
virtual void Start() = 0;
/* Shutdown GraphDriver */
MOZ_CAN_RUN_SCRIPT virtual void Shutdown() = 0;
/* Set the UTF-8 name for system audio streams.
* Graph thread, or main thread if the graph is not running. */
virtual void SetStreamName(const nsACString& aStreamName);
/* Rate at which the GraphDriver runs, in ms. This can either be user
* controlled (because we are using a {System,Offline}ClockDriver, and decide
* how often we want to wakeup/how much we want to process per iteration), or
@ -315,7 +318,8 @@ class GraphDriver {
* Set the state of the driver so it can start at the right point in time,
* after switching from another driver.
*/
void SetState(GraphTime aIterationEnd, GraphTime aStateComputedTime);
void SetState(const nsACString& aStreamName, GraphTime aIterationEnd,
GraphTime aStateComputedTime);
GraphInterface* Graph() const { return mGraphInterface; }
@ -345,6 +349,8 @@ class GraphDriver {
}
protected:
// The UTF-8 name for system audio streams. Graph thread.
nsCString mStreamName;
// Time of the end of this graph iteration.
GraphTime mIterationEnd = 0;
// Time until which the graph has processed data.
@ -532,7 +538,7 @@ struct TrackAndPromiseForOperation {
MozPromiseHolder<MediaTrackGraph::AudioContextOperationPromise> mHolder;
};
enum class AsyncCubebOperation { INIT, SHUTDOWN };
enum class AsyncCubebOperation { INIT, NAME_CHANGE, SHUTDOWN };
enum class AudioInputType { Unknown, Voice };
/**
@ -573,6 +579,7 @@ class AudioCallbackDriver : public GraphDriver, public MixerCallbackReceiver {
void Start() override;
MOZ_CAN_RUN_SCRIPT void Shutdown() override;
void SetStreamName(const nsACString& aStreamName) override;
/* Static wrapper function cubeb calls back. */
static long DataCallback_s(cubeb_stream* aStream, void* aUser,
@ -663,7 +670,8 @@ class AudioCallbackDriver : public GraphDriver, public MixerCallbackReceiver {
/* Start the cubeb stream */
bool StartStream();
friend class AsyncCubebTask;
void Init();
void Init(const nsCString& aStreamName);
void SetCubebStreamName(const nsCString& aStreamName);
void Stop();
/**
* Fall back to a SystemClockDriver using a normal thread. If needed,
@ -787,7 +795,9 @@ class AudioCallbackDriver : public GraphDriver, public MixerCallbackReceiver {
class AsyncCubebTask : public Runnable {
public:
AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation);
// aName is not required for AsyncCubebOperation::SHUTDOWN
AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation,
const nsACString& aName = VoidCString());
nsresult Dispatch(uint32_t aFlags = NS_DISPATCH_NORMAL) {
return mDriver->mInitShutdownThread->Dispatch(this, aFlags);
@ -807,6 +817,7 @@ class AsyncCubebTask : public Runnable {
RefPtr<AudioCallbackDriver> mDriver;
AsyncCubebOperation mOperation;
nsCString mName;
RefPtr<GraphInterface> mShutdownGrip;
};

Просмотреть файл

@ -11,6 +11,7 @@
#include "CrossGraphPort.h"
#include "VideoSegment.h"
#include "nsContentUtils.h"
#include "nsGlobalWindowInner.h"
#include "nsPrintfCString.h"
#include "nsServiceManagerUtils.h"
#include "prerror.h"
@ -26,6 +27,7 @@
#endif // MOZ_WEBRTC
#include "MediaTrackListener.h"
#include "mozilla/dom/BaseAudioContextBinding.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/WorkletThread.h"
#include "mozilla/media/MediaUtils.h"
#include <algorithm>
@ -1680,6 +1682,40 @@ MediaTrackGraphImpl::Notify(nsITimer* aTimer) {
return NS_OK;
}
static nsCString GetDocumentTitle(uint64_t aWindowID) {
MOZ_ASSERT(NS_IsMainThread());
nsCString title;
auto* win = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
if (!win) {
return title;
}
Document* doc = win->GetExtantDoc();
if (!doc) {
return title;
}
nsAutoString titleUTF16;
doc->GetTitle(titleUTF16);
CopyUTF16toUTF8(titleUTF16, title);
return title;
}
NS_IMETHODIMP
MediaTrackGraphImpl::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(strcmp(aTopic, "document-title-changed") == 0);
nsCString streamName = GetDocumentTitle(mWindowID);
LOG(LogLevel::Debug, ("%p: document title: %s", this, streamName.get()));
if (streamName.IsEmpty()) {
return NS_OK;
}
QueueControlMessageWithNoShutdown(
[self = RefPtr{this}, this, streamName = std::move(streamName)] {
CurrentDriver()->SetStreamName(streamName);
});
return NS_OK;
}
bool MediaTrackGraphImpl::AddShutdownBlocker() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShutdownBlocker);
@ -3254,6 +3290,9 @@ MediaTrackGraphImpl::MediaTrackGraphImpl(
} else {
mDriver = new SystemClockDriver(this, nullptr, mSampleRate);
}
nsCString streamName = GetDocumentTitle(aWindowID);
LOG(LogLevel::Debug, ("%p: document title: %s", this, streamName.get()));
mDriver->SetStreamName(streamName);
} else {
mDriver =
new OfflineClockDriver(this, mSampleRate, MEDIA_GRAPH_TARGET_PERIOD_MS);
@ -3341,6 +3380,12 @@ MediaTrackGraphImpl* MediaTrackGraphImpl::GetInstance(
aOutputDeviceID, aMainThread);
MOZ_ALWAYS_TRUE(graphs->add(addPtr, graph));
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(graph, "document-title-changed", false);
}
LOG(LogLevel::Debug, ("Starting up MediaTrackGraph %p for window 0x%" PRIx64,
graph, aWindowID));
@ -3385,8 +3430,8 @@ void MediaTrackGraph::ForceShutDown() {
graph->ForceShutDown();
}
NS_IMPL_ISUPPORTS(MediaTrackGraphImpl, nsIMemoryReporter, nsIThreadObserver,
nsITimerCallback, nsINamed)
NS_IMPL_ISUPPORTS(MediaTrackGraphImpl, nsIMemoryReporter, nsIObserver,
nsIThreadObserver, nsITimerCallback, nsINamed)
NS_IMETHODIMP
MediaTrackGraphImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
@ -3580,6 +3625,12 @@ void MediaTrackGraphImpl::RemoveTrack(MediaTrack* aTrack) {
graphs->lookup({mWindowID, mSampleRate, mOutputDeviceID});
MOZ_ASSERT(*p == this);
graphs->remove(p);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "document-title-changed");
}
}
// The graph thread will shut itself down soon, but won't be able to do
// that if JS continues to run.

Просмотреть файл

@ -107,6 +107,7 @@ class MessageBlock {
class MediaTrackGraphImpl : public MediaTrackGraph,
public GraphInterface,
public nsIMemoryReporter,
public nsIObserver,
public nsIThreadObserver,
public nsITimerCallback,
public nsINamed {
@ -115,6 +116,7 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
NS_DECL_NSIOBSERVER
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSINAMED
@ -186,6 +188,17 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
* during RunInStableState; the messages will run on the graph thread.
*/
virtual void AppendMessage(UniquePtr<ControlMessageInterface> aMessage);
/**
* Append to the message queue a control message to execute a given lambda
* function with no parameters. The lambda will be executed on the graph
* thread. The lambda will not be executed if the graph has been forced to
* shut down.
**/
template <typename Function>
void QueueControlMessageWithNoShutdown(Function&& aFunction) {
AppendMessage(WrapUnique(new MediaTrack::ControlMessageWithNoShutdown(
std::forward<Function>(aFunction))));
}
/**
* Dispatches a runnable from any thread to the correct main thread for this

Просмотреть файл

@ -141,14 +141,12 @@ void cubeb_mock_destroy(cubeb* context) {
MockCubeb::AsMock(context)->Destroy();
}
MockCubebStream::MockCubebStream(cubeb* aContext, cubeb_devid aInputDevice,
cubeb_stream_params* aInputStreamParams,
cubeb_devid aOutputDevice,
cubeb_stream_params* aOutputStreamParams,
cubeb_data_callback aDataCallback,
cubeb_state_callback aStateCallback,
void* aUserPtr, SmartMockCubebStream* aSelf,
RunningMode aRunningMode, bool aFrozenStart)
MockCubebStream::MockCubebStream(
cubeb* aContext, char const* aStreamName, cubeb_devid aInputDevice,
cubeb_stream_params* aInputStreamParams, cubeb_devid aOutputDevice,
cubeb_stream_params* aOutputStreamParams, cubeb_data_callback aDataCallback,
cubeb_state_callback aStateCallback, void* aUserPtr,
SmartMockCubebStream* aSelf, RunningMode aRunningMode, bool aFrozenStart)
: context(aContext),
mUserPtr(aUserPtr),
mRunningMode(aRunningMode),
@ -159,6 +157,7 @@ MockCubebStream::MockCubebStream(cubeb* aContext, cubeb_devid aInputDevice,
mFrozenStart(aFrozenStart),
mDataCallback(aDataCallback),
mStateCallback(aStateCallback),
mName(aStreamName),
mInputDeviceID(aInputDevice),
mOutputDeviceID(aOutputDevice),
mAudioGenerator(aInputStreamParams ? aInputStreamParams->channels
@ -252,6 +251,12 @@ void MockCubebStream::Destroy() {
MockCubeb::AsMock(context)->StreamDestroy(this);
}
int MockCubebStream::SetName(char const* aName) {
mName = aName;
mNameSetEvent.Notify(mName);
return CUBEB_OK;
}
int MockCubebStream::RegisterDeviceChangedCallback(
cubeb_device_changed_callback aDeviceChangedCallback) {
if (mDeviceChangedCallback && aDeviceChangedCallback) {
@ -326,6 +331,10 @@ void MockCubebStream::SetInputRecordingEnabled(bool aEnabled) {
mInputRecordingEnabled = aEnabled;
}
MediaEventSource<nsCString>& MockCubebStream::NameSetEvent() {
return mNameSetEvent;
}
MediaEventSource<cubeb_state>& MockCubebStream::StateEvent() {
return mStateEvent;
}
@ -612,7 +621,7 @@ void MockCubeb::UnforceAudioThread() {
}
int MockCubeb::StreamInit(cubeb* aContext, cubeb_stream** aStream,
cubeb_devid aInputDevice,
char const* aStreamName, cubeb_devid aInputDevice,
cubeb_stream_params* aInputStreamParams,
cubeb_devid aOutputDevice,
cubeb_stream_params* aOutputStreamParams,
@ -624,7 +633,7 @@ int MockCubeb::StreamInit(cubeb* aContext, cubeb_stream** aStream,
}
auto mockStream = MakeRefPtr<SmartMockCubebStream>(
aContext, aInputDevice, aInputStreamParams, aOutputDevice,
aContext, aStreamName, aInputDevice, aInputStreamParams, aOutputDevice,
aOutputStreamParams, aDataCallback, aStateCallback, aUserPtr,
mRunningMode, mStreamStartFreezeEnabled);
*aStream = mockStream->AsCubebStream();

Просмотреть файл

@ -152,7 +152,8 @@ class MockCubebStream {
enum class KeepProcessing { No, Yes };
enum class RunningMode { Automatic, Manual };
MockCubebStream(cubeb* aContext, cubeb_devid aInputDevice,
MockCubebStream(cubeb* aContext, char const* aStreamName,
cubeb_devid aInputDevice,
cubeb_stream_params* aInputStreamParams,
cubeb_devid aOutputDevice,
cubeb_stream_params* aOutputStreamParams,
@ -167,12 +168,14 @@ class MockCubebStream {
int Stop();
uint64_t Position();
void Destroy();
int SetName(char const* aName);
int RegisterDeviceChangedCallback(
cubeb_device_changed_callback aDeviceChangedCallback);
cubeb_stream* AsCubebStream();
static MockCubebStream* AsMock(cubeb_stream* aStream);
char const* StreamName() const { return mName.get(); }
cubeb_devid GetInputDeviceID() const;
cubeb_devid GetOutputDeviceID() const;
@ -202,6 +205,7 @@ class MockCubebStream {
// only works once.
nsTArray<AudioDataValue>&& TakeRecordedInput();
MediaEventSource<nsCString>& NameSetEvent();
MediaEventSource<cubeb_state>& StateEvent();
MediaEventSource<uint32_t>& FramesProcessedEvent();
MediaEventSource<uint32_t>& FramesVerifiedEvent();
@ -249,6 +253,8 @@ class MockCubebStream {
cubeb_state_callback mStateCallback = nullptr;
// The device changed callback
cubeb_device_changed_callback mDeviceChangedCallback = nullptr;
// A name for this stream
nsCString mName;
// The stream params
cubeb_stream_params mOutputParams = {};
cubeb_stream_params mInputParams = {};
@ -265,6 +271,7 @@ class MockCubebStream {
AudioGenerator<AudioDataValue> mAudioGenerator;
AudioVerifier<AudioDataValue> mAudioVerifier;
MediaEventProducer<nsCString> mNameSetEvent;
MediaEventProducer<cubeb_state> mStateEvent;
MediaEventProducer<uint32_t> mFramesProcessedEvent;
MediaEventProducer<uint32_t> mFramesVerifiedEvent;
@ -285,14 +292,15 @@ class SmartMockCubebStream
public SupportsThreadSafeWeakPtr<SmartMockCubebStream> {
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(SmartMockCubebStream)
SmartMockCubebStream(cubeb* aContext, cubeb_devid aInputDevice,
SmartMockCubebStream(cubeb* aContext, char const* aStreamName,
cubeb_devid aInputDevice,
cubeb_stream_params* aInputStreamParams,
cubeb_devid aOutputDevice,
cubeb_stream_params* aOutputStreamParams,
cubeb_data_callback aDataCallback,
cubeb_state_callback aStateCallback, void* aUserPtr,
RunningMode aRunningMode, bool aFrozenStart)
: MockCubebStream(aContext, aInputDevice, aInputStreamParams,
: MockCubebStream(aContext, aStreamName, aInputDevice, aInputStreamParams,
aOutputDevice, aOutputStreamParams, aDataCallback,
aStateCallback, aUserPtr, this, aRunningMode,
aFrozenStart) {}
@ -387,7 +395,7 @@ class MockCubeb {
void UnforceAudioThread();
int StreamInit(cubeb* aContext, cubeb_stream** aStream,
cubeb_devid aInputDevice,
char const* aStreamName, cubeb_devid aInputDevice,
cubeb_stream_params* aInputStreamParams,
cubeb_devid aOutputDevice,
cubeb_stream_params* aOutputStreamParams,
@ -483,8 +491,9 @@ int cubeb_mock_stream_init(
unsigned int latency, cubeb_data_callback data_callback,
cubeb_state_callback state_callback, void* user_ptr) {
return MockCubeb::AsMock(context)->StreamInit(
context, stream, input_device, input_stream_params, output_device,
output_stream_params, data_callback, state_callback, user_ptr);
context, stream, stream_name, input_device, input_stream_params,
output_device, output_stream_params, data_callback, state_callback,
user_ptr);
}
int cubeb_mock_stream_start(cubeb_stream* stream) {
@ -524,6 +533,7 @@ static int cubeb_mock_stream_set_volume(cubeb_stream* stream, float volume) {
static int cubeb_mock_stream_set_name(cubeb_stream* stream,
char const* stream_name) {
return MockCubebStream::AsMock(stream)->SetName(stream_name);
return CUBEB_OK;
}

Просмотреть файл

@ -219,6 +219,44 @@ TEST(TestAudioTrackGraph, SetOutputDeviceID)
WaitFor(cubeb->StreamDestroyEvent());
}
TEST(TestAudioTrackGraph, StreamName)
{
MockCubeb* cubeb = new MockCubeb();
CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
// Initialize a graph with a system thread driver to check that the stream
// name survives the driver switch.
MediaTrackGraphImpl* graph = MediaTrackGraphImpl::GetInstance(
MediaTrackGraph::SYSTEM_THREAD_DRIVER, /*Window ID*/ 1,
CubebUtils::PreferredSampleRate(/* aShouldResistFingerprinting */ false),
/*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(1),
GetMainThreadSerialEventTarget());
nsLiteralCString name1("name1");
graph->CurrentDriver()->SetStreamName(name1);
// Dummy track to start the graph rolling and switch to an
// AudioCallbackDriver.
RefPtr<SourceMediaTrack> dummySource;
DispatchFunction(
[&] { dummySource = graph->CreateSourceTrack(MediaSegment::AUDIO); });
RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
EXPECT_STREQ(stream->StreamName(), name1.get());
// Test a name change on an existing stream.
nsLiteralCString name2("name2");
DispatchFunction([&] {
graph->QueueControlMessageWithNoShutdown(
[&] { graph->CurrentDriver()->SetStreamName(name2); });
});
nsCString name = WaitFor(stream->NameSetEvent());
EXPECT_EQ(name, name2);
// Test has finished. Destroy the track to shutdown the MTG.
DispatchMethod(dummySource, &SourceMediaTrack::Destroy);
WaitFor(cubeb->StreamDestroyEvent());
}
TEST(TestAudioTrackGraph, NotifyDeviceStarted)
{
MockCubeb* cubeb = new MockCubeb();