blob: b8390900c5a8032386d5de382c5fd0ccae65b3c8 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIARECORDER_AUDIO_TRACK_MOJO_ENCODER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIARECORDER_AUDIO_TRACK_MOJO_ENCODER_H_
#include <memory>
#include <optional>
#include "base/containers/queue.h"
#include "base/memory/weak_ptr.h"
#include "media/base/audio_encoder.h"
#include "media/base/encoder_status.h"
#include "third_party/blink/renderer/modules/mediarecorder/audio_track_encoder.h"
#include "third_party/blink/renderer/modules/mediarecorder/audio_track_recorder.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace base {
class TimeTicks;
}
namespace media {
class AudioBus;
class AudioParameters;
class MojoAudioEncoder;
} // namespace media
namespace blink {
// A thin wrapper for platform audio encoders which run in the GPU process.
// Currently, the only available encoder implementation is AAC, and only on
// Windows and Mac.
//
// This class uses a MojoAudioEncoder, which requires us to be async, so input
// may be buffered in this class, and will be asynchronously delivered via
// `on_encoded_audio_cb_`.
//
// Some encoders may buffer input frames, and MediaRecorder's abrupt stop design
// does not allow us to Flush. So, we may never receive the output for them,
// losing some audio at the end of the recording.
class MODULES_EXPORT AudioTrackMojoEncoder : public AudioTrackEncoder {
public:
AudioTrackMojoEncoder(
scoped_refptr<base::SequencedTaskRunner> encoder_task_runner,
AudioTrackRecorder::CodecId codec,
OnEncodedAudioCB on_encoded_audio_cb,
uint32_t bits_per_second = 0);
AudioTrackMojoEncoder(const AudioTrackMojoEncoder&) = delete;
AudioTrackMojoEncoder& operator=(const AudioTrackMojoEncoder&) = delete;
// Destroys the existing `mojo_encoder_` and recreates it with the new params.
// No-op if new params are identical to the current `input_params_` and no
// errors have been encountered.
void OnSetFormat(const media::AudioParameters& params) override;
// May buffer or immediately deliver `input_bus` to `mojo_encoder_`. If we
// encounter an error or are `paused_`, input will be ignored. This will
// return before `on_encoded_audio_cb_` is run.
void EncodeAudio(std::unique_ptr<media::AudioBus> input_bus,
base::TimeTicks capture_time) override;
private:
// Run when the platform encoder finishes initializing, will flush
// `input_queue_`.
void OnInitializeDone(media::EncoderStatus status);
void DoEncodeAudio(std::unique_ptr<media::AudioBus> input_bus,
base::TimeTicks capture_time);
// Run when input is delivered to the platform encoder, or when an error is
// encountered.
void OnEncodeDone(media::EncoderStatus status);
void OnEncodeOutput(
media::EncodedAudioBuffer encoded_buffer,
std::optional<media::AudioEncoder::CodecDescription> codec_desc);
// The `media::AudioEncoder` interface requires the callback provided to
// `Initialize` to be run before any further calls are made. So, we store any
// input we get while waiting for the callback in `input_queue_` and will
// deliver it in `OnInitializeDone`.
struct PendingData {
std::unique_ptr<media::AudioBus> audio_bus;
const base::TimeTicks capture_time;
};
const scoped_refptr<base::SequencedTaskRunner> encoder_task_runner_;
AudioTrackRecorder::CodecId codec_;
// Target bitrate. An optional parameter for the `mojo_encoder_`;
const uint32_t bits_per_second_;
media::EncoderStatus current_status_;
std::unique_ptr<media::AudioEncoder> mojo_encoder_;
base::queue<PendingData> input_queue_;
base::WeakPtrFactory<AudioTrackMojoEncoder> weak_factory_{this};
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIARECORDER_AUDIO_TRACK_MOJO_ENCODER_H_