init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,408 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "webrtc/platform/win/webrtc_environment_win.h"
|
||||
|
||||
#include "base/platform/win/base_windows_co_task_mem.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "webrtc/webrtc_environment.h"
|
||||
|
||||
#include <MMDeviceAPI.h>
|
||||
#include <winrt/base.h>
|
||||
|
||||
#include <functiondiscoverykeys_devpkey.h>
|
||||
#include <propvarutil.h>
|
||||
#include <propkey.h>
|
||||
|
||||
namespace Webrtc::Platform {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxNameLength = 256;
|
||||
|
||||
[[nodiscard]] auto RoleForType(DeviceType type) {
|
||||
return (type == DeviceType::Playback) ? eConsole : eCommunications;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class EnvironmentWin::Client
|
||||
: public winrt::implements<Client, IMMNotificationClient>
|
||||
, public base::has_weak_ptr {
|
||||
public:
|
||||
Client(
|
||||
Fn<void(DeviceType, QString)> defaultChanged,
|
||||
Fn<void(QString, std::optional<DeviceStateChange>)> deviceToggled);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(
|
||||
LPCWSTR deviceId,
|
||||
const PROPERTYKEY key) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR deviceId) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR deviceId) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(
|
||||
LPCWSTR deviceId,
|
||||
DWORD newState) override;
|
||||
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(
|
||||
EDataFlow flow,
|
||||
ERole role,
|
||||
LPCWSTR newDefaultDeviceId) override;
|
||||
|
||||
private:
|
||||
Fn<void(DeviceType, QString)> _defaultChanged;
|
||||
Fn<void(QString, std::optional<DeviceStateChange>)> _deviceToggled;
|
||||
|
||||
};
|
||||
|
||||
EnvironmentWin::Client::Client(
|
||||
Fn<void(DeviceType, QString)> defaultChanged,
|
||||
Fn<void(QString, std::optional<DeviceStateChange>)> deviceToggled)
|
||||
: _defaultChanged(std::move(defaultChanged))
|
||||
, _deviceToggled(std::move(deviceToggled)) {
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnvironmentWin::Client::OnPropertyValueChanged(
|
||||
LPCWSTR deviceId,
|
||||
const PROPERTYKEY key) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnvironmentWin::Client::OnDeviceAdded(
|
||||
LPCWSTR deviceId) {
|
||||
const auto id = QString::fromWCharArray(deviceId);
|
||||
crl::on_main(this, [=] {
|
||||
const auto onstack = _deviceToggled;
|
||||
onstack(id, std::nullopt);
|
||||
});
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnvironmentWin::Client::OnDeviceRemoved(
|
||||
LPCWSTR deviceId) {
|
||||
const auto id = QString::fromWCharArray(deviceId);
|
||||
const auto change = DeviceStateChange::Disconnected;
|
||||
crl::on_main(this, [=] {
|
||||
const auto onstack = _deviceToggled;
|
||||
onstack(id, change);
|
||||
});
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnvironmentWin::Client::OnDeviceStateChanged(
|
||||
LPCWSTR deviceId,
|
||||
DWORD newState) {
|
||||
const auto change = (newState == DEVICE_STATE_ACTIVE)
|
||||
? DeviceStateChange::Active
|
||||
: DeviceStateChange::Inactive;
|
||||
const auto id = QString::fromWCharArray(deviceId);
|
||||
crl::on_main(this, [=] {
|
||||
const auto onstack = _deviceToggled;
|
||||
onstack(id, change);
|
||||
});
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnvironmentWin::Client::OnDefaultDeviceChanged(
|
||||
EDataFlow flow,
|
||||
ERole role,
|
||||
LPCWSTR newDefaultDeviceId) {
|
||||
const auto type = (flow == eRender)
|
||||
? DeviceType::Playback
|
||||
: DeviceType::Capture;
|
||||
if (role == RoleForType(type)) {
|
||||
const auto id = QString::fromWCharArray(newDefaultDeviceId);
|
||||
crl::on_main(this, [=] {
|
||||
const auto onstack = _defaultChanged;
|
||||
onstack(type, id);
|
||||
});
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
EnvironmentWin::EnvironmentWin(not_null<EnvironmentDelegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
, _audioFallback(delegate)
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
, _cameraFallback(delegate) {
|
||||
#ifndef WEBRTC_TESTING_OPENAL
|
||||
using namespace base::WinRT;
|
||||
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
|
||||
_enumerator = TryCreateInstance<IMMDeviceEnumerator>(
|
||||
CLSID_MMDeviceEnumerator);
|
||||
if (!_enumerator) {
|
||||
const auto hr = CoInitialize(nullptr);
|
||||
if (SUCCEEDED(hr)) {
|
||||
_comInitialized = true;
|
||||
_enumerator = TryCreateInstance<IMMDeviceEnumerator>(
|
||||
CLSID_MMDeviceEnumerator);
|
||||
if (!_enumerator) {
|
||||
LOG(("Media Error: Could not create MMDeviceEnumerator."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_client = winrt::make<Client>([=](DeviceType type, QString id) {
|
||||
_delegate->defaultChanged(type, DeviceChangeReason::Manual, id);
|
||||
}, [=](QString id, std::optional<DeviceStateChange> state) {
|
||||
processDeviceStateChange(id, state);
|
||||
});
|
||||
if (!_client) {
|
||||
LOG(("Media Error: Could not create IMMNotificationClient."));
|
||||
return;
|
||||
}
|
||||
const auto hr = _enumerator->RegisterEndpointNotificationCallback(
|
||||
_client.get());
|
||||
if (FAILED(hr)) {
|
||||
LOG(("Media Error: RegisterEndpointNotificationCallback failed."));
|
||||
}
|
||||
#endif // !WEBRTC_TESTING_OPENAL
|
||||
}
|
||||
|
||||
EnvironmentWin::~EnvironmentWin() {
|
||||
if (_client) {
|
||||
Assert(_enumerator != nullptr);
|
||||
_enumerator->UnregisterEndpointNotificationCallback(_client.get());
|
||||
_client = nullptr;
|
||||
}
|
||||
_enumerator = nullptr;
|
||||
if (_comInitialized) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
QString EnvironmentWin::defaultId(DeviceType type) {
|
||||
if (type == DeviceType::Camera) {
|
||||
return _cameraFallback.defaultId(type);
|
||||
} else if (!_enumerator) {
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
return _audioFallback.defaultId(type);
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
return {};
|
||||
}
|
||||
const auto flow = (type == DeviceType::Playback)
|
||||
? eRender
|
||||
: eCapture;
|
||||
const auto role = RoleForType(type);
|
||||
|
||||
auto device = winrt::com_ptr<IMMDevice>();
|
||||
auto hr = _enumerator->GetDefaultAudioEndpoint(flow, role, device.put());
|
||||
if (FAILED(hr) || !device) {
|
||||
return {};
|
||||
}
|
||||
auto id = base::CoTaskMemString();
|
||||
hr = device->GetId(id.put());
|
||||
if (FAILED(hr) || !id || !*id.data()) {
|
||||
return {};
|
||||
}
|
||||
return QString::fromWCharArray(id.data());
|
||||
}
|
||||
|
||||
void EnvironmentWin::processDeviceStateChange(
|
||||
const QString &id,
|
||||
std::optional<DeviceStateChange> change) {
|
||||
const auto wide = id.toStdWString();
|
||||
auto device = winrt::com_ptr<IMMDevice>();
|
||||
auto hr = _enumerator->GetDevice(wide.c_str(), device.put());
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
} else if (const auto endpoint = device.try_as<IMMEndpoint>()) {
|
||||
auto flow = EDataFlow();
|
||||
hr = endpoint->GetDataFlow(&flow);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (!change) {
|
||||
auto state = DWORD();
|
||||
hr = device->GetState(&state);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
return;
|
||||
}
|
||||
change = (state == DEVICE_STATE_ACTIVE)
|
||||
? DeviceStateChange::Active
|
||||
: DeviceStateChange::Inactive;
|
||||
}
|
||||
const auto type = (flow == eRender)
|
||||
? DeviceType::Playback
|
||||
: DeviceType::Capture;
|
||||
_delegate->deviceStateChanged(type, id, *change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeviceInfo EnvironmentWin::device(DeviceType type, const QString &id) {
|
||||
if (type == DeviceType::Camera) {
|
||||
return _cameraFallback.device(type, id);
|
||||
} else if (!_enumerator) {
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
return _audioFallback.device(type, id);
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
return {};
|
||||
}
|
||||
const auto wide = id.toStdWString();
|
||||
auto device = winrt::com_ptr<IMMDevice>();
|
||||
auto hr = _enumerator->GetDevice(wide.c_str(), device.put());
|
||||
if (FAILED(hr) || !device) {
|
||||
return {};
|
||||
}
|
||||
auto store = winrt::com_ptr<IPropertyStore>();
|
||||
hr = device->OpenPropertyStore(STGM_READ, store.put());
|
||||
if (FAILED(hr) || !store) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto name = PROPVARIANT();
|
||||
hr = store->GetValue(PKEY_Device_FriendlyName, &name);
|
||||
if (FAILED(hr)) {
|
||||
return {};
|
||||
}
|
||||
const auto guard = gsl::finally([&] { PropVariantClear(&name); });
|
||||
|
||||
auto already = std::array<WCHAR, kMaxNameLength>();
|
||||
hr = PropVariantToString(name, already.data(), MAX_PATH);
|
||||
if (FAILED(hr) || !already[0]) {
|
||||
return {};
|
||||
}
|
||||
auto state = DWORD();
|
||||
hr = device->GetState(&state);
|
||||
if (FAILED(hr)) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
.id = id,
|
||||
.name = QString::fromWCharArray(already.data()),
|
||||
.type = type,
|
||||
.inactive = (state != DEVICE_STATE_ACTIVE),
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<DeviceInfo> EnvironmentWin::devices(DeviceType type) {
|
||||
if (type == DeviceType::Camera) {
|
||||
return _cameraFallback.devices(type);
|
||||
} else if (!_enumerator) {
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
return _audioFallback.devices(type);
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
return {};
|
||||
}
|
||||
const auto flow = (type == DeviceType::Playback)
|
||||
? eRender
|
||||
: eCapture;
|
||||
auto collection = winrt::com_ptr<IMMDeviceCollection>();
|
||||
auto hr = _enumerator->EnumAudioEndpoints(
|
||||
flow,
|
||||
DEVICE_STATEMASK_ALL,
|
||||
collection.put());
|
||||
if (FAILED(hr) || !collection) {
|
||||
return {};
|
||||
}
|
||||
auto count = UINT();
|
||||
hr = collection->GetCount(&count);
|
||||
if (FAILED(hr)) {
|
||||
return {};
|
||||
}
|
||||
auto result = std::vector<DeviceInfo>();
|
||||
result.reserve(count);
|
||||
for (auto i = UINT(); i != count; ++i) {
|
||||
auto device = winrt::com_ptr<IMMDevice>();
|
||||
hr = collection->Item(i, device.put());
|
||||
if (FAILED(hr)) {
|
||||
continue;
|
||||
}
|
||||
auto endpoint = device.try_as<IMMEndpoint>();
|
||||
if (!endpoint) {
|
||||
continue;
|
||||
}
|
||||
auto flow = EDataFlow();
|
||||
hr = endpoint->GetDataFlow(&flow);
|
||||
auto id = base::CoTaskMemString();
|
||||
hr = device->GetId(id.put());
|
||||
if (FAILED(hr) || !id || !*id.data()) {
|
||||
continue;
|
||||
}
|
||||
auto store = winrt::com_ptr<IPropertyStore>();
|
||||
hr = device->OpenPropertyStore(STGM_READ, store.put());
|
||||
if (FAILED(hr) || !store) {
|
||||
continue;
|
||||
}
|
||||
auto name = PROPVARIANT();
|
||||
hr = store->GetValue(PKEY_Device_FriendlyName, &name);
|
||||
if (FAILED(hr)) {
|
||||
continue;
|
||||
}
|
||||
const auto guard = gsl::finally([&] { PropVariantClear(&name); });
|
||||
|
||||
auto already = std::array<WCHAR, kMaxNameLength>();
|
||||
hr = PropVariantToString(name, already.data(), MAX_PATH);
|
||||
if (FAILED(hr) || !already[0]) {
|
||||
continue;
|
||||
}
|
||||
auto state = DWORD();
|
||||
hr = device->GetState(&state);
|
||||
if (FAILED(hr)) {
|
||||
continue;
|
||||
}
|
||||
result.push_back({
|
||||
.id = QString::fromWCharArray(id.data()),
|
||||
.name = QString::fromWCharArray(already.data()),
|
||||
.type = type,
|
||||
.inactive = (state != DEVICE_STATE_ACTIVE),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EnvironmentWin::refreshFullListOnChange(DeviceType type) {
|
||||
if (type == DeviceType::Camera) {
|
||||
return _cameraFallback.refreshFullListOnChange(type);
|
||||
}
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
return true;
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EnvironmentWin::desktopCaptureAllowed() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<QString> EnvironmentWin::uniqueDesktopCaptureSource() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void EnvironmentWin::defaultIdRequested(DeviceType type) {
|
||||
if (type == DeviceType::Camera) {
|
||||
_cameraFallback.defaultIdRequested(type);
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
} else {
|
||||
_audioFallback.defaultIdRequested(type);
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
}
|
||||
}
|
||||
|
||||
void EnvironmentWin::devicesRequested(DeviceType type) {
|
||||
if (type == DeviceType::Camera) {
|
||||
_cameraFallback.devicesRequested(type);
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
} else {
|
||||
_audioFallback.devicesRequested(type);
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
}
|
||||
}
|
||||
|
||||
DeviceResolvedId EnvironmentWin::threadSafeResolveId(
|
||||
const DeviceResolvedId &lastResolvedId,
|
||||
const QString &savedId) {
|
||||
return (lastResolvedId.type == DeviceType::Camera)
|
||||
? _cameraFallback.threadSafeResolveId(lastResolvedId, savedId)
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
: _audioFallback.threadSafeResolveId(lastResolvedId, savedId);
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
: lastResolvedId;
|
||||
}
|
||||
|
||||
std::unique_ptr<Environment> CreateEnvironment(
|
||||
not_null<EnvironmentDelegate*> delegate) {
|
||||
return std::make_unique<EnvironmentWin>(delegate);
|
||||
}
|
||||
|
||||
} // namespace Webrtc::Platform
|
||||
@@ -0,0 +1,65 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "webrtc/platform/webrtc_platform_environment.h"
|
||||
|
||||
#include "webrtc/details/webrtc_environment_video_capture.h"
|
||||
#include "base/platform/win/base_windows_winrt.h"
|
||||
|
||||
//#define WEBRTC_TESTING_OPENAL
|
||||
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
#include "webrtc/details/webrtc_environment_openal.h"
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
|
||||
struct IMMDeviceEnumerator;
|
||||
struct IMMNotificationClient;
|
||||
|
||||
namespace Webrtc::Platform {
|
||||
|
||||
class EnvironmentWin final : public Environment {
|
||||
public:
|
||||
explicit EnvironmentWin(not_null<EnvironmentDelegate*> delegate);
|
||||
~EnvironmentWin();
|
||||
|
||||
QString defaultId(DeviceType type) override;
|
||||
DeviceInfo device(DeviceType type, const QString &id) override;
|
||||
|
||||
std::vector<DeviceInfo> devices(DeviceType type) override;
|
||||
bool refreshFullListOnChange(DeviceType type) override;
|
||||
|
||||
bool desktopCaptureAllowed() const override;
|
||||
std::optional<QString> uniqueDesktopCaptureSource() const override;
|
||||
|
||||
void defaultIdRequested(DeviceType type) override;
|
||||
void devicesRequested(DeviceType type) override;
|
||||
|
||||
DeviceResolvedId threadSafeResolveId(
|
||||
const DeviceResolvedId &lastResolvedId,
|
||||
const QString &savedId) override;
|
||||
|
||||
private:
|
||||
void processDeviceStateChange(
|
||||
const QString &id,
|
||||
std::optional<DeviceStateChange> change);
|
||||
|
||||
class Client;
|
||||
|
||||
const not_null<EnvironmentDelegate*> _delegate;
|
||||
#ifdef WEBRTC_TESTING_OPENAL
|
||||
details::EnvironmentOpenAL _audioFallback;
|
||||
#endif // WEBRTC_TESTING_OPENAL
|
||||
details::EnvironmentVideoCapture _cameraFallback;
|
||||
|
||||
bool _comInitialized = false;
|
||||
winrt::com_ptr<IMMDeviceEnumerator> _enumerator;
|
||||
winrt::com_ptr<IMMNotificationClient> _client;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Webrtc::Platform
|
||||
1149
Telegram/lib_webrtc/webrtc/platform/win/webrtc_loopback_adm_win.cpp
Normal file
1149
Telegram/lib_webrtc/webrtc/platform/win/webrtc_loopback_adm_win.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <modules/audio_device/include/audio_device.h>
|
||||
#include <modules/audio_device/audio_device_buffer.h>
|
||||
#include <api/scoped_refptr.h>
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <MMDeviceAPI.h>
|
||||
|
||||
#include <winrt/base.h>
|
||||
|
||||
typedef struct SwrContext SwrContext;
|
||||
typedef struct AVChannelLayout AVChannelLayout;
|
||||
|
||||
namespace rtc {
|
||||
class Thread;
|
||||
} // namespace rtc
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessing;
|
||||
class AudioFrame;
|
||||
} // namespace webrtc
|
||||
|
||||
namespace Webrtc::details {
|
||||
|
||||
[[nodiscard]] bool IsLoopbackCaptureActive();
|
||||
|
||||
void LoopbackCapturePushFarEnd(
|
||||
crl::time when,
|
||||
const QByteArray &samples,
|
||||
int frequency,
|
||||
int channels);
|
||||
|
||||
class AudioDeviceLoopbackWin : public webrtc::AudioDeviceModule {
|
||||
public:
|
||||
explicit AudioDeviceLoopbackWin(webrtc::TaskQueueFactory *taskQueueFactory);
|
||||
~AudioDeviceLoopbackWin();
|
||||
|
||||
int32_t ActiveAudioLayer(AudioLayer *audioLayer) const override;
|
||||
int32_t RegisterAudioCallback(
|
||||
webrtc::AudioTransport *audioCallback) override;
|
||||
|
||||
// Main initializaton and termination
|
||||
int32_t Init() override;
|
||||
int32_t Terminate() override;
|
||||
bool Initialized() const override;
|
||||
|
||||
// Device enumeration
|
||||
int16_t PlayoutDevices() override;
|
||||
int16_t RecordingDevices() override;
|
||||
int32_t PlayoutDeviceName(uint16_t index,
|
||||
char name[webrtc::kAdmMaxDeviceNameSize],
|
||||
char guid[webrtc::kAdmMaxGuidSize]) override;
|
||||
int32_t RecordingDeviceName(uint16_t index,
|
||||
char name[webrtc::kAdmMaxDeviceNameSize],
|
||||
char guid[webrtc::kAdmMaxGuidSize]) override;
|
||||
|
||||
// Device selection
|
||||
int32_t SetPlayoutDevice(uint16_t index) override;
|
||||
int32_t SetPlayoutDevice(WindowsDeviceType device) override;
|
||||
int32_t SetRecordingDevice(uint16_t index) override;
|
||||
int32_t SetRecordingDevice(WindowsDeviceType device) override;
|
||||
|
||||
// Audio transport initialization
|
||||
int32_t PlayoutIsAvailable(bool *available) override;
|
||||
int32_t InitPlayout() override;
|
||||
bool PlayoutIsInitialized() const override;
|
||||
int32_t RecordingIsAvailable(bool *available) override;
|
||||
int32_t InitRecording() override;
|
||||
bool RecordingIsInitialized() const override;
|
||||
|
||||
// Audio transport control
|
||||
int32_t StartPlayout() override;
|
||||
int32_t StopPlayout() override;
|
||||
bool Playing() const override;
|
||||
int32_t StartRecording() override;
|
||||
int32_t StopRecording() override;
|
||||
bool Recording() const override;
|
||||
|
||||
// Audio mixer initialization
|
||||
int32_t InitSpeaker() override;
|
||||
bool SpeakerIsInitialized() const override;
|
||||
int32_t InitMicrophone() override;
|
||||
bool MicrophoneIsInitialized() const override;
|
||||
|
||||
// Speaker volume controls
|
||||
int32_t SpeakerVolumeIsAvailable(bool *available) override;
|
||||
int32_t SetSpeakerVolume(uint32_t volume) override;
|
||||
int32_t SpeakerVolume(uint32_t *volume) const override;
|
||||
int32_t MaxSpeakerVolume(uint32_t *maxVolume) const override;
|
||||
int32_t MinSpeakerVolume(uint32_t *minVolume) const override;
|
||||
|
||||
// Microphone volume controls
|
||||
int32_t MicrophoneVolumeIsAvailable(bool *available) override;
|
||||
int32_t SetMicrophoneVolume(uint32_t volume) override;
|
||||
int32_t MicrophoneVolume(uint32_t *volume) const override;
|
||||
int32_t MaxMicrophoneVolume(uint32_t *maxVolume) const override;
|
||||
int32_t MinMicrophoneVolume(uint32_t *minVolume) const override;
|
||||
|
||||
// Microphone mute control
|
||||
int32_t MicrophoneMuteIsAvailable(bool *available) override;
|
||||
int32_t SetMicrophoneMute(bool enable) override;
|
||||
int32_t MicrophoneMute(bool *enabled) const override;
|
||||
|
||||
// Speaker mute control
|
||||
int32_t SpeakerMuteIsAvailable(bool *available) override;
|
||||
int32_t SetSpeakerMute(bool enable) override;
|
||||
int32_t SpeakerMute(bool *enabled) const override;
|
||||
|
||||
// Stereo support
|
||||
int32_t StereoPlayoutIsAvailable(bool *available) const override;
|
||||
int32_t SetStereoPlayout(bool enable) override;
|
||||
int32_t StereoPlayout(bool *enabled) const override;
|
||||
int32_t StereoRecordingIsAvailable(bool *available) const override;
|
||||
int32_t SetStereoRecording(bool enable) override;
|
||||
int32_t StereoRecording(bool *enabled) const override;
|
||||
|
||||
// Delay information and control
|
||||
int32_t PlayoutDelay(uint16_t *delayMS) const override;
|
||||
|
||||
// Only supported on Android.
|
||||
bool BuiltInAECIsAvailable() const override;
|
||||
bool BuiltInAGCIsAvailable() const override;
|
||||
bool BuiltInNSIsAvailable() const override;
|
||||
|
||||
// Enables the built-in audio effects. Only supported on Android.
|
||||
int32_t EnableBuiltInAEC(bool enable) override;
|
||||
int32_t EnableBuiltInAGC(bool enable) override;
|
||||
int32_t EnableBuiltInNS(bool enable) override;
|
||||
|
||||
private:
|
||||
void openPlaybackDeviceForCapture();
|
||||
void openAudioClient();
|
||||
|
||||
void openRecordingDevice();
|
||||
void closeRecordingDevice();
|
||||
|
||||
void captureFailed(const std::string &error);
|
||||
|
||||
void startCaptureOnThread();
|
||||
void stopCaptureOnThread();
|
||||
void processData();
|
||||
|
||||
bool setupResampler(const WAVEFORMATEX &format);
|
||||
bool setupResampler(
|
||||
int channels,
|
||||
AVChannelLayout channelLayout,
|
||||
int inputFormat, // AVSampleFormat
|
||||
int sampleRate,
|
||||
Fn<std::string()> info);
|
||||
void ensureResampleSpaceAvailable(int samples);
|
||||
|
||||
static DWORD WINAPI CaptureThreadMethod(LPVOID context);
|
||||
DWORD runCaptureThread();
|
||||
|
||||
webrtc::AudioDeviceBuffer _audioDeviceBuffer;
|
||||
|
||||
winrt::com_ptr<IMMDevice> _endpointDevice;
|
||||
winrt::com_ptr<IAudioClient> _audioClient;
|
||||
winrt::com_ptr<IAudioClient> _audioRenderClientForLoopback;
|
||||
winrt::com_ptr<IAudioCaptureClient> _audioCaptureClient;
|
||||
|
||||
rtc::scoped_refptr<webrtc::AudioProcessing> _audioProcessing;
|
||||
std::unique_ptr<webrtc::AudioFrame> _capturedFrame;
|
||||
std::unique_ptr<webrtc::AudioFrame> _renderedFrame;
|
||||
|
||||
HANDLE _thread = nullptr;
|
||||
HANDLE _audioSamplesReadyEvent = nullptr;
|
||||
HANDLE _captureThreadShutdownEvent = nullptr;
|
||||
|
||||
UINT32 _bufferSizeFrames = 0;
|
||||
UINT32 _deviceFrameSize = 0;
|
||||
QByteArray _deviceBuffer;
|
||||
QByteArray _resampleBuffer;
|
||||
UINT32 _bufferOffset = 0;
|
||||
|
||||
double _queryPerformanceMultiplier = 0.;
|
||||
double _deviceFrequencyMultiplier = 0.;
|
||||
|
||||
SwrContext *_swrContext = nullptr;
|
||||
int _swrSrcSampleRate = 0;
|
||||
|
||||
bool _microphoneInitialized = false;
|
||||
bool _initialized = false;
|
||||
|
||||
bool _recordingInitialized = false;
|
||||
bool _recordingFailed = false;
|
||||
bool _recording = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Webrtc::details
|
||||
Reference in New Issue
Block a user