зеркало из https://github.com/mozilla/gecko-dev.git
173 строки
6.1 KiB
C++
173 строки
6.1 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "CubebInputStream.h"
|
|
|
|
#include "AudioSampleFormat.h"
|
|
#include "mozilla/Logging.h"
|
|
|
|
namespace mozilla {
|
|
|
|
extern mozilla::LazyLogModule gMediaTrackGraphLog;
|
|
|
|
#ifdef LOG_INTERNAL
|
|
# undef LOG_INTERNAL
|
|
#endif // LOG_INTERNAL
|
|
#define LOG_INTERNAL(level, msg, ...) \
|
|
MOZ_LOG(gMediaTrackGraphLog, LogLevel::level, (msg, ##__VA_ARGS__))
|
|
|
|
#ifdef LOG
|
|
# undef LOG
|
|
#endif // LOG
|
|
#define LOG(msg, ...) LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)
|
|
|
|
#ifdef LOGE
|
|
# undef LOGE
|
|
#endif // LOGE
|
|
#define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
|
|
|
|
#define InvokeCubebWithLog(func, ...) \
|
|
({ \
|
|
int _retval; \
|
|
_retval = InvokeCubeb(func, ##__VA_ARGS__); \
|
|
if (_retval == CUBEB_OK) { \
|
|
LOG("CubebInputStream %p: %s for stream %p was successful", this, #func, \
|
|
mStream.get()); \
|
|
} else { \
|
|
LOGE("CubebInputStream %p: %s for stream %p was failed. Error %d", this, \
|
|
#func, mStream.get(), _retval); \
|
|
} \
|
|
_retval; \
|
|
})
|
|
|
|
static cubeb_stream_params CreateStreamInitParams(uint32_t aChannels,
|
|
uint32_t aRate,
|
|
bool aIsVoice) {
|
|
cubeb_stream_params params;
|
|
params.format = CubebUtils::ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
|
|
params.rate = aRate;
|
|
params.channels = aChannels;
|
|
params.layout = CUBEB_LAYOUT_UNDEFINED;
|
|
params.prefs = CubebUtils::GetDefaultStreamPrefs(CUBEB_DEVICE_TYPE_INPUT);
|
|
|
|
if (aIsVoice) {
|
|
params.prefs |= static_cast<cubeb_stream_prefs>(CUBEB_STREAM_PREF_VOICE);
|
|
}
|
|
|
|
return params;
|
|
}
|
|
|
|
void CubebInputStream::CubebDestroyPolicy::operator()(
|
|
cubeb_stream* aStream) const {
|
|
int r = cubeb_stream_register_device_changed_callback(aStream, nullptr);
|
|
if (r == CUBEB_OK) {
|
|
LOG("Unregister device changed callback for %p successfully", aStream);
|
|
} else {
|
|
LOGE("Fail to unregister device changed callback for %p. Error %d", aStream,
|
|
r);
|
|
}
|
|
cubeb_stream_destroy(aStream);
|
|
}
|
|
|
|
/* static */
|
|
UniquePtr<CubebInputStream> CubebInputStream::Create(cubeb_devid aDeviceId,
|
|
uint32_t aChannels,
|
|
uint32_t aRate,
|
|
bool aIsVoice,
|
|
Listener* aListener) {
|
|
if (!aListener) {
|
|
LOGE("No available listener");
|
|
return nullptr;
|
|
}
|
|
|
|
cubeb* context = CubebUtils::GetCubebContext();
|
|
if (!context) {
|
|
LOGE("No valid cubeb context");
|
|
CubebUtils::ReportCubebStreamInitFailure(CubebUtils::GetFirstStream());
|
|
return nullptr;
|
|
}
|
|
|
|
cubeb_stream_params params =
|
|
CreateStreamInitParams(aChannels, aRate, aIsVoice);
|
|
uint32_t latencyFrames = CubebUtils::GetCubebMTGLatencyInFrames(¶ms);
|
|
|
|
cubeb_stream* cubebStream = nullptr;
|
|
|
|
RefPtr<Listener> listener(aListener);
|
|
if (int r =
|
|
cubeb_stream_init(context, &cubebStream, "input-only stream",
|
|
aDeviceId, ¶ms, nullptr, nullptr, latencyFrames,
|
|
DataCallback_s, StateCallback_s, listener.get());
|
|
r != CUBEB_OK) {
|
|
CubebUtils::ReportCubebStreamInitFailure(CubebUtils::GetFirstStream());
|
|
LOGE("Fail to create a cubeb stream. Error %d", r);
|
|
return nullptr;
|
|
}
|
|
|
|
UniquePtr<cubeb_stream, CubebDestroyPolicy> inputStream(cubebStream);
|
|
|
|
LOG("Create a cubeb stream %p successfully", inputStream.get());
|
|
|
|
UniquePtr<CubebInputStream> stream(
|
|
new CubebInputStream(listener.forget(), std::move(inputStream)));
|
|
stream->Init();
|
|
return stream;
|
|
}
|
|
|
|
CubebInputStream::CubebInputStream(
|
|
already_AddRefed<Listener>&& aListener,
|
|
UniquePtr<cubeb_stream, CubebDestroyPolicy>&& aStream)
|
|
: mListener(aListener), mStream(std::move(aStream)) {
|
|
MOZ_ASSERT(mListener);
|
|
MOZ_ASSERT(mStream);
|
|
}
|
|
|
|
void CubebInputStream::Init() {
|
|
// cubeb_stream_register_device_changed_callback is only supported on macOS
|
|
// platform and MockCubebfor now.
|
|
InvokeCubebWithLog(cubeb_stream_register_device_changed_callback,
|
|
CubebInputStream::DeviceChangedCallback_s);
|
|
}
|
|
|
|
int CubebInputStream::Start() { return InvokeCubebWithLog(cubeb_stream_start); }
|
|
|
|
int CubebInputStream::Stop() { return InvokeCubebWithLog(cubeb_stream_stop); }
|
|
|
|
template <typename Function, typename... Args>
|
|
int CubebInputStream::InvokeCubeb(Function aFunction, Args&&... aArgs) {
|
|
MOZ_ASSERT(mStream);
|
|
return aFunction(mStream.get(), std::forward<Args>(aArgs)...);
|
|
}
|
|
|
|
/* static */
|
|
long CubebInputStream::DataCallback_s(cubeb_stream* aStream, void* aUser,
|
|
const void* aInputBuffer,
|
|
void* aOutputBuffer, long aFrames) {
|
|
MOZ_ASSERT(aUser);
|
|
MOZ_ASSERT(aInputBuffer);
|
|
MOZ_ASSERT(!aOutputBuffer);
|
|
return static_cast<Listener*>(aUser)->DataCallback(aInputBuffer, aFrames);
|
|
}
|
|
|
|
/* static */
|
|
void CubebInputStream::StateCallback_s(cubeb_stream* aStream, void* aUser,
|
|
cubeb_state aState) {
|
|
MOZ_ASSERT(aUser);
|
|
static_cast<Listener*>(aUser)->StateCallback(aState);
|
|
}
|
|
|
|
/* static */
|
|
void CubebInputStream::DeviceChangedCallback_s(void* aUser) {
|
|
MOZ_ASSERT(aUser);
|
|
static_cast<Listener*>(aUser)->DeviceChangedCallback();
|
|
}
|
|
|
|
#undef LOG_INTERNAL
|
|
#undef LOG
|
|
#undef LOGE
|
|
|
|
} // namespace mozilla
|