| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROMECAST_MEDIA_CMA_BACKEND_PROXY_MEDIA_PIPELINE_BUFFER_EXTENSION_H_ |
| #define CHROMECAST_MEDIA_CMA_BACKEND_PROXY_MEDIA_PIPELINE_BUFFER_EXTENSION_H_ |
| |
| #include <memory> |
| #include <queue> |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/threading/thread_checker.h" |
| #include "chromecast/media/api/cma_backend.h" |
| #include "chromecast/media/cma/backend/proxy/audio_decoder_pipeline_node.h" |
| #include "chromecast/public/media/cast_key_status.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace chromecast { |
| |
| class TaskRunner; |
| |
| namespace media { |
| |
| // This class is intended to act as a layer on top of another CmaBackend, |
| // increasing the number of PushBuffer frames that may be queued up with |
| // PushBuffer() calls, while delegating all other functionality directly to the |
| // CmaBackend on top of which it sits. |
| class MediaPipelineBufferExtension : public AudioDecoderPipelineNode { |
| public: |
| // |task_runner| and |delegated_decoder| must persist for the duration of this |
| // class's lifetime. |
| MediaPipelineBufferExtension(TaskRunner* task_runner, |
| CmaBackend::AudioDecoder* delegated_decoder); |
| // Takes ownership of |owned_delegated_decoder|. |
| MediaPipelineBufferExtension( |
| TaskRunner* task_runner, |
| std::unique_ptr<AudioDecoderPipelineNode> owned_delegated_decoder); |
| |
| ~MediaPipelineBufferExtension() override; |
| |
| bool IsBufferFull() const; |
| bool IsBufferEmpty() const; |
| |
| // AudioDecoderPipelineNode overrides. |
| RenderingDelay GetRenderingDelay() override; |
| BufferStatus PushBuffer(scoped_refptr<DecoderBufferBase> buffer) override; |
| bool SetConfig(const AudioConfig& config) override; |
| |
| private: |
| struct PendingCommand { |
| // NOTE: Ctors needed to support emplace calls. |
| explicit PendingCommand(scoped_refptr<DecoderBufferBase> buf); |
| explicit PendingCommand(const AudioConfig& cfg); |
| PendingCommand(const PendingCommand& other); |
| PendingCommand(PendingCommand&& other); |
| |
| ~PendingCommand(); |
| |
| PendingCommand& operator=(const PendingCommand& other); |
| PendingCommand& operator=(PendingCommand&& other); |
| |
| absl::optional<scoped_refptr<DecoderBufferBase>> buffer; |
| absl::optional<AudioConfig> config; |
| }; |
| |
| // AudioDecoderPipelineNode overrides. |
| void OnPushBufferComplete(BufferStatus status) override; |
| |
| // Pushes the provided |buffer| to |delegated_decoder_|. |
| BufferStatus PushBufferToDelegatedDecoder( |
| scoped_refptr<DecoderBufferBase> buffer); |
| |
| // Returns the total amount of playback time stored in this instance. |
| int64_t GetBufferDuration() const; |
| |
| // Returns whether the last call to either PushBuffer() or SetConfig() on the |
| // delegated decoder returned an unhealthy response code. |
| bool IsDelegatedDecoderHealthy() const; |
| |
| // Helper method to try to push the top item in the |command_queue_| to |
| // |delegated_decoder_|. Returns false if the underlying decoder's operation |
| // both was called and that call failed, and true in all other cases. |
| // |
| // If either there is no data to process or no work that can be done at this |
| // time, this operation is a no op which returns true. |
| bool TryPushToDecoder(); |
| |
| // Pushes the |command| to |command_queue_| and tries to process it, returning |
| // whether or not the delegated decoder is in a healthy state following this |
| // process. |
| bool TryProcessCommand(PendingCommand command); |
| |
| // Schedules the TryPushToDecoder() method to run at a later time on |
| // |task_runner_|. |
| void SchedulePushToDecoder(); |
| |
| // PushBuffer and SetConfig data which has been queued locally but has not yet |
| // been processed by the delegated decoder. |
| std::queue<PendingCommand> command_queue_; |
| |
| // The playback timestamp (PTS) of the last buffer pushed to the underlying |
| // decoder. |
| int64_t last_buffer_pts_ = 0; |
| |
| // The playback timestamp (PTS) of the most recently supplied by the caller. |
| int64_t most_recent_buffer_pts_ = 0; |
| |
| // Holds the result of the last call to delegated decoder's PushBuffer |
| // queue for which additional calls are not queued up (as is done by |
| // PushToDecoderAfterPushBufferComplete()). |
| BufferStatus delegated_decoder_buffer_status_ = BufferStatus::kBufferSuccess; |
| |
| // Holds the result of the last call to delegated decoder's SetConfig method. |
| bool delegated_decoder_set_config_status_ = true; |
| |
| TaskRunner* const task_runner_; |
| |
| base::WeakPtrFactory<MediaPipelineBufferExtension> weak_factory_; |
| }; |
| |
| } // namespace media |
| } // namespace chromecast |
| |
| #endif // CHROMECAST_MEDIA_CMA_BACKEND_PROXY_MEDIA_PIPELINE_BUFFER_EXTENSION_H_ |