| // Copyright 2012 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_INPUT_SYNC_WRITER_H_ |
| #define SERVICES_AUDIO_INPUT_SYNC_WRITER_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/memory/unsafe_shared_memory_region.h" |
| #include "base/sync_socket.h" |
| #include "base/time/time.h" |
| #include "base/unguessable_token.h" |
| #include "build/build_config.h" |
| #include "input_glitch_counter.h" |
| #include "media/base/audio_bus.h" |
| #include "media/base/audio_glitch_info.h" |
| #include "media/base/audio_parameters.h" |
| #include "services/audio/input_controller.h" |
| |
| namespace audio { |
| |
| // A InputController::SyncWriter implementation using SyncSocket. This |
| // is used by InputController to provide a low latency data source for |
| // transmitting audio packets between the browser process and the renderer |
| // process. |
| class InputSyncWriter final : public InputController::SyncWriter { |
| public: |
| // Maximum fifo size (|overflow_buses_| and |overflow_params_|) in number of |
| // media::AudioBuses. |
| enum { kMaxOverflowBusesSize = 100 }; |
| |
| InputSyncWriter() = delete; |
| |
| // Create() automatically initializes the InputSyncWriter correctly, |
| // and should be strongly preferred over calling the constructor directly! |
| InputSyncWriter( |
| base::RepeatingCallback<void(const std::string&)> log_callback, |
| base::UnsafeSharedMemoryRegion shared_memory, |
| std::unique_ptr<base::CancelableSyncSocket> socket, |
| uint32_t shared_memory_segment_count, |
| const media::AudioParameters& params, |
| std::unique_ptr<InputGlitchCounter> glitch_counter); |
| |
| InputSyncWriter(const InputSyncWriter&) = delete; |
| InputSyncWriter& operator=(const InputSyncWriter&) = delete; |
| |
| ~InputSyncWriter() final; |
| |
| static std::unique_ptr<InputSyncWriter> Create( |
| base::RepeatingCallback<void(const std::string&)> log_callback, |
| uint32_t shared_memory_segment_count, |
| const media::AudioParameters& params, |
| base::CancelableSyncSocket* foreign_socket); |
| |
| // Transfers shared memory region ownership to a caller. It shouldn't be |
| // called more than once. |
| base::UnsafeSharedMemoryRegion TakeSharedMemoryRegion(); |
| |
| size_t shared_memory_segment_count() const { return audio_buses_.size(); } |
| |
| // InputController::SyncWriter implementation. |
| void Write(const media::AudioBus* data, |
| double volume, |
| base::TimeTicks capture_time, |
| const media::AudioGlitchInfo& glitch_info) final; |
| |
| void Close() final; |
| |
| private: |
| friend class InputSyncWriterTest; |
| |
| // Called by Write(). Checks the time since last called and if larger than a |
| // threshold logs info about that. |
| void CheckTimeSinceLastWrite(); |
| |
| // Called by Write(). Checks how much data has been read from shared memory by |
| // the consumer side, and updates how much space is left in shared memory. |
| void ReceiveReadConfirmationsFromConsumer(); |
| |
| // Push |data| and metadata to |audio_buffer_fifo_|. Returns true if |
| // successful. Logs error and returns false if the fifo already reached the |
| // maximum size. |
| bool PushDataToFifo(const media::AudioBus& data, |
| double volume, |
| base::TimeTicks capture_time, |
| const media::AudioGlitchInfo& glitch_info); |
| |
| // Write data and audio parameters to current segment in shared memory. |
| // Returns true if the data was successfully written, returns false if it was |
| // dropped. |
| bool WriteDataToCurrentSegment(const media::AudioBus& data, |
| double volume, |
| base::TimeTicks capture_time, |
| const media::AudioGlitchInfo& glitch_info); |
| |
| // Signals over the socket that data has been written to the current segment. |
| // Updates counters and returns true if successful. Logs error and returns |
| // false if failure. |
| bool SignalDataWrittenAndUpdateCounters(); |
| |
| media::AudioInputBuffer* GetSharedInputBuffer(uint32_t segment_id); |
| |
| // Helper method for creating internal log messages prefixed with "AISW::". |
| PRINTF_FORMAT(2, 3) void SendLogMessage(const char* format, ...); |
| |
| const base::UnguessableToken id_; |
| |
| const base::RepeatingCallback<void(const std::string&)> log_callback_; |
| |
| // Socket used to signal that audio data is ready. |
| const std::unique_ptr<base::CancelableSyncSocket> socket_; |
| |
| // Shared memory for audio data and associated metadata. |
| base::UnsafeSharedMemoryRegion shared_memory_region_; |
| base::WritableSharedMemoryMapping shared_memory_mapping_; |
| |
| // The size in bytes of a single audio segment in the shared memory. |
| const uint32_t shared_memory_segment_size_; |
| |
| // Index of next segment to write. |
| uint32_t current_segment_id_ = 0; |
| |
| // The time of the creation of this object. |
| base::TimeTicks creation_time_; |
| |
| // The time of the last Write call. |
| base::TimeTicks last_write_time_; |
| |
| // Size in bytes of each audio bus. |
| const uint32_t audio_bus_memory_size_; |
| |
| // The id for the next buffer that we will write into shared memory. Starts at |
| // 0 and increases by one for each buffer written into shared memory. |
| uint32_t next_buffer_id_ = 0; |
| |
| // The index of the next audio buffer to be read on the consumer side, as far |
| // as the InputSyncWriter currently knows. Starts at 0 and increases by one |
| // for each buffer that the consumer side has read from the shared memory. |
| // |
| // If `confirm_reads_via_shmem_` is true, this is the index of the next buffer |
| // to be released by the consumer via resetting its `has_unread_data` flag. |
| uint32_t next_read_buffer_index_ = 0; |
| |
| // Keeps track of number of filled buffer segments in the ring buffer to |
| // ensure the we don't overwrite data that hasn't been read yet. |
| size_t number_of_filled_segments_ = 0; |
| |
| // Used for logging. |
| size_t fifo_full_count_ = 0; |
| |
| // Denotes that the most recent socket error has been logged. Used to avoid |
| // log spam. |
| bool had_socket_error_ = false; |
| |
| // Vector of audio buses allocated during construction and deleted in the |
| // destructor. |
| std::vector<std::unique_ptr<media::AudioBus>> audio_buses_; |
| |
| // Vector of pointers to the AudioInputBuffers in the shared memory. |
| std::vector<media::AudioInputBuffer*> input_buffers_; |
| |
| // Fifo for audio that is used in case there isn't room in the shared memory. |
| // This can for example happen under load when the consumer side is starved. |
| // It should ideally be rare, but we need to guarantee that the data arrives |
| // since audio processing such as echo cancelling requires that to perform |
| // properly. |
| struct OverflowData { |
| OverflowData(double volume, |
| base::TimeTicks capture_time, |
| const media::AudioGlitchInfo& glitch_info, |
| std::unique_ptr<media::AudioBus> audio_bus); |
| |
| OverflowData(const OverflowData&) = delete; |
| OverflowData& operator=(const OverflowData&) = delete; |
| |
| OverflowData(OverflowData&&); |
| OverflowData& operator=(OverflowData&& other); |
| |
| ~OverflowData(); |
| |
| double volume_; |
| base::TimeTicks capture_time_; |
| media::AudioGlitchInfo glitch_info_; |
| std::unique_ptr<media::AudioBus> audio_bus_; |
| }; |
| |
| std::vector<OverflowData> overflow_data_; |
| |
| std::unique_ptr<InputGlitchCounter> glitch_counter_; |
| |
| // Glitch info that has yet to be successfully communicated to the renderer. |
| media::AudioGlitchInfo pending_glitch_info_; |
| |
| // Represents the glitch info of one dropped buffer. |
| const media::AudioGlitchInfo dropped_buffer_glitch_; |
| }; |
| |
| } // namespace audio |
| |
| #endif // SERVICES_AUDIO_INPUT_SYNC_WRITER_H_ |