Files
tdesktop/Telegram/lib_webrtc/webrtc/webrtc_audio_input_tester.cpp
allhaileris afb81b8278
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
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
init
2026-02-16 15:50:16 +03:00

196 lines
5.0 KiB
C++

// 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/webrtc_audio_input_tester.h"
#include "webrtc/webrtc_device_common.h"
#include "webrtc/webrtc_create_adm.h"
#include "crl/crl_object_on_thread.h"
#include "crl/crl_async.h"
#include <api/task_queue/default_task_queue_factory.h>
#include <modules/audio_device/include/audio_device_defines.h>
#include <modules/audio_device/include/audio_device.h>
namespace Webrtc {
class AudioInputTester::Impl : public webrtc::AudioTransport {
public:
explicit Impl(const std::shared_ptr<std::atomic<int>> &maxSample);
~Impl();
void setDeviceId(const DeviceResolvedId &deviceId);
private:
void init();
void restart();
int32_t RecordedDataIsAvailable(
const void* audioSamples,
const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
const uint32_t totalDelayMS,
const int32_t clockDrift,
const uint32_t currentMicLevel,
const bool keyPressed,
uint32_t& newMicLevel) override;
// Implementation has to setup safe values for all specified out parameters.
int32_t NeedMorePlayData(
const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
void* audioSamples,
size_t& nSamplesOut, // NOLINT
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) override;
// Method to pull mixed render audio data from all active VoE channels.
// The data will not be passed as reference for audio processing internally.
void PullRenderData(
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
void* audio_data,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) override;
std::shared_ptr<std::atomic<int>> _maxSample;
std::unique_ptr<webrtc::TaskQueueFactory> _taskQueueFactory;
rtc::scoped_refptr<webrtc::AudioDeviceModule> _adm;
Fn<void(DeviceResolvedId)> _setDeviceIdCallback;
DeviceResolvedId _deviceId;
};
AudioInputTester::Impl::Impl(
const std::shared_ptr<std::atomic<int>> &maxSample)
: _maxSample(std::move(maxSample))
, _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory())
, _deviceId{ .type = DeviceType::Capture } {
const auto saveSetDeviceIdCallback = [=](
Fn<void(DeviceResolvedId)> setDeviceIdCallback) {
_setDeviceIdCallback = std::move(setDeviceIdCallback);
if (!_deviceId.isDefault()) {
_setDeviceIdCallback(_deviceId);
restart();
}
};
_adm = CreateAudioDeviceModule(
_taskQueueFactory.get(),
saveSetDeviceIdCallback);
init();
}
AudioInputTester::Impl::~Impl() {
if (_adm) {
_adm->StopRecording();
_adm->RegisterAudioCallback(nullptr);
_adm->Terminate();
}
}
void AudioInputTester::Impl::init() {
if (!_adm) {
return;
}
_adm->Init();
_adm->RegisterAudioCallback(this);
}
void AudioInputTester::Impl::setDeviceId(const DeviceResolvedId &deviceId) {
_deviceId = deviceId;
if (_setDeviceIdCallback) {
_setDeviceIdCallback(_deviceId);
restart();
}
}
void AudioInputTester::Impl::restart() {
if (!_adm) {
return;
}
_adm->StopRecording();
_adm->SetRecordingDevice(0);
if (_adm->InitRecording() == 0) {
_adm->StartRecording();
}
}
int32_t AudioInputTester::Impl::RecordedDataIsAvailable(
const void* audioSamples,
const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
const uint32_t totalDelayMS,
const int32_t clockDrift,
const uint32_t currentMicLevel,
const bool keyPressed,
uint32_t& newMicLevel) {
const auto channels = nBytesPerSample / sizeof(int16_t);
if (channels > 0 && !(nBytesPerSample % sizeof(int16_t))) {
auto max = 0;
auto values = static_cast<const int16_t*>(audioSamples);
for (auto i = size_t(); i != nSamples * channels; ++i) {
if (max < values[i]) {
max = values[i];
}
}
const auto now = _maxSample->load();
if (max > now) {
_maxSample->store(max);
}
}
newMicLevel = currentMicLevel;
return 0;
}
int32_t AudioInputTester::Impl::NeedMorePlayData(const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
void* audioSamples,
size_t& nSamplesOut,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) {
nSamplesOut = 0;
return 0;
}
void AudioInputTester::Impl::PullRenderData(int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
void* audio_data,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) {
}
AudioInputTester::AudioInputTester(rpl::producer<DeviceResolvedId> deviceId)
: _maxSample(std::make_shared<std::atomic<int>>(0))
, _impl(std::as_const(_maxSample)) {
std::move(
deviceId
) | rpl::on_next([=](const DeviceResolvedId &id) {
_impl.with([=](Impl &impl) {
impl.setDeviceId(id);
});
}, _lifetime);
}
AudioInputTester::~AudioInputTester() = default;
float AudioInputTester::getAndResetLevel() {
return _maxSample->exchange(0) / float(INT16_MAX);
}
} // namespace Webrtc