// Copyright 2018 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef SERVICES_AUDIO_SNOOPER_NODE_H_ #define SERVICES_AUDIO_SNOOPER_NODE_H_ #include <limits> #include <memory> #include <optional> #include "base/synchronization/lock.h" #include "base/time/time.h" #include "media/base/audio_parameters.h" #include "media/base/channel_mixer.h" #include "media/base/multi_channel_resampler.h" #include "services/audio/delay_buffer.h" #include "services/audio/loopback_group_member.h" namespace media { class AudioBus; } // namespace media namespace audio { // Thread-safe implementation of Snooper that records the audio from a // GroupMember on one thread, and re-renders it to the desired output format on // another thread. Since the data flow rates are known to be driven by different // clocks (audio hardware clock versus system clock), the base::TimeTicks // reference clock is used to detect drift and automatically correct for it to // maintain proper synchronization. // // Throughout this class, there are sample counters (in terms of the input // audio's sample rate) that are tracked/computed. They refer to the media // timestamp of the audio flowing through specific parts of the processing // pipeline: inbound from OnData() calls → through the delay buffer → through // the resampler → and outbound via Render() calls: // // write position: The position of audio about to be written into the delay // buffer. This is managed by OnData(). // read position: The position of audio about to be read from the delay // buffer and pushed into the resampler. This is managed by // ReadFromDelayBuffer(). // output position: The position of the audio about to come out of the // resampler. This is computed within Render(). Note that // this is a "virtual" position since it is in terms of the // input audio's sample count, but refers to audio about to // be generated in the output format (with a possibly // different sample rate). // // Note that the media timestamps represented by the "positions," as well as the // surrounding math operations, might seem backwards; but they are not. This is // because the inbound audio is from a source that pre-renders audio for playout // in the near future, while the outbound audio is audio that would have been // played-out in the recent past. class SnooperNode final : public LoopbackGroupMember::Snooper { … }; } // namespace audio #endif // SERVICES_AUDIO_SNOOPER_NODE_H_