123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "media/fuchsia/audio/fake_audio_consumer.h"
- #include <lib/vfs/cpp/pseudo_dir.h>
- #include <lib/vfs/cpp/service.h>
- #include "base/fuchsia/fuchsia_logging.h"
- namespace media {
- const base::TimeDelta FakeAudioConsumer::kMinLeadTime = base::Milliseconds(100);
- const base::TimeDelta FakeAudioConsumer::kMaxLeadTime = base::Milliseconds(500);
- FakeAudioConsumer::FakeAudioConsumer(
- uint64_t session_id,
- fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request)
- : session_id_(session_id),
- audio_consumer_binding_(this),
- stream_sink_binding_(this),
- volume_control_binding_(this) {
- audio_consumer_binding_.Bind(std::move(request));
- }
- FakeAudioConsumer::~FakeAudioConsumer() = default;
- base::TimeDelta FakeAudioConsumer::GetMediaPosition() {
- base::TimeDelta result = media_pos_;
- if (state_ == State::kPlaying) {
- result += (base::TimeTicks::Now() - reference_time_) * media_delta_ /
- reference_delta_;
- }
- return result;
- }
- void FakeAudioConsumer::CreateStreamSink(
- std::vector<zx::vmo> buffers,
- fuchsia::media::AudioStreamType stream_type,
- std::unique_ptr<fuchsia::media::Compression> compression,
- fidl::InterfaceRequest<fuchsia::media::StreamSink> stream_sink_request) {
- num_buffers_ = buffers.size();
- CHECK_GT(num_buffers_, 0U);
- stream_sink_binding_.Bind(std::move(stream_sink_request));
- }
- void FakeAudioConsumer::Start(fuchsia::media::AudioConsumerStartFlags flags,
- int64_t reference_time,
- int64_t media_time) {
- CHECK(state_ == State::kStopped);
- if (reference_time != fuchsia::media::NO_TIMESTAMP) {
- reference_time_ = base::TimeTicks::FromZxTime(reference_time);
- } else {
- reference_time_ = base::TimeTicks::Now() + kMinLeadTime;
- }
- if (media_time != fuchsia::media::NO_TIMESTAMP) {
- media_pos_ = base::TimeDelta::FromZxDuration(media_time);
- } else {
- if (media_pos_.is_min()) {
- media_pos_ = base::TimeDelta();
- }
- }
- state_ = State::kPlaying;
- OnStatusUpdate();
- ScheduleNextStreamPosUpdate();
- }
- void FakeAudioConsumer::Stop() {
- CHECK(state_ != State::kStopped);
- state_ = State::kStopped;
- OnStatusUpdate();
- }
- void FakeAudioConsumer::WatchStatus(WatchStatusCallback callback) {
- status_callback_ = std::move(callback);
- if (have_status_update_) {
- CallStatusCallback();
- }
- }
- void FakeAudioConsumer::SetRate(float rate) {
- // Playback rate must not be negative.
- CHECK_GE(rate, 0.0);
- // Update reference position.
- auto now = base::TimeTicks::Now();
- media_pos_ =
- media_pos_ + (now - reference_time_) * media_delta_ / reference_delta_;
- reference_time_ = now;
- // Approximate the rate as n/1000;
- reference_delta_ = 1000;
- media_delta_ = static_cast<int>(rate * 1000.0);
- OnStatusUpdate();
- if (update_timer_.IsRunning())
- update_timer_.Reset();
- ScheduleNextStreamPosUpdate();
- }
- void FakeAudioConsumer::BindVolumeControl(
- fidl::InterfaceRequest<fuchsia::media::audio::VolumeControl>
- volume_control_request) {
- volume_control_binding_.Bind(std::move(volume_control_request));
- }
- void FakeAudioConsumer::SendPacket(fuchsia::media::StreamPacket stream_packet,
- SendPacketCallback callback) {
- CHECK_LT(stream_packet.payload_buffer_id, num_buffers_);
- Packet packet;
- if (stream_packet.pts == fuchsia::media::NO_TIMESTAMP) {
- if (media_pos_.is_min()) {
- packet.pts = base::TimeDelta();
- } else {
- packet.pts = media_pos_;
- }
- } else {
- packet.pts = base::TimeDelta::FromZxDuration(stream_packet.pts);
- }
- pending_packets_.push_back(std::move(packet));
- callback();
- ScheduleNextStreamPosUpdate();
- }
- void FakeAudioConsumer::SendPacketNoReply(fuchsia::media::StreamPacket packet) {
- NOTREACHED();
- }
- void FakeAudioConsumer::EndOfStream() {
- Packet packet;
- packet.is_eos = true;
- pending_packets_.push_back(std::move(packet));
- }
- void FakeAudioConsumer::DiscardAllPackets(DiscardAllPacketsCallback callback) {
- DiscardAllPacketsNoReply();
- std::move(callback)();
- }
- void FakeAudioConsumer::DiscardAllPacketsNoReply() {
- pending_packets_.clear();
- }
- void FakeAudioConsumer::SetVolume(float volume) {
- volume_ = volume;
- }
- void FakeAudioConsumer::SetMute(bool mute) {
- is_muted_ = mute;
- }
- void FakeAudioConsumer::NotImplemented_(const std::string& name) {
- LOG(FATAL) << "Reached non-implemented " << name;
- }
- void FakeAudioConsumer::ScheduleNextStreamPosUpdate() {
- if (pending_packets_.empty() || update_timer_.IsRunning() ||
- media_delta_ == 0 || state_ != State::kPlaying) {
- return;
- }
- base::TimeDelta delay;
- if (!pending_packets_.front().is_eos) {
- auto next_packet_time =
- reference_time_ + (pending_packets_.front().pts - media_pos_) *
- reference_delta_ / media_delta_;
- delay = (next_packet_time - base::TimeTicks::Now());
- }
- update_timer_.Start(FROM_HERE, delay,
- base::BindOnce(&FakeAudioConsumer::UpdateStreamPos,
- base::Unretained(this)));
- }
- void FakeAudioConsumer::UpdateStreamPos() {
- if (state_ != State::kPlaying)
- return;
- auto now = base::TimeTicks::Now();
- auto new_media_pos =
- media_pos_ + (now - reference_time_) * media_delta_ / reference_delta_;
- // Drop all packets with PTS before the current position.
- while (!pending_packets_.empty()) {
- if (!pending_packets_.front().is_eos &&
- pending_packets_.front().pts > new_media_pos) {
- break;
- }
- Packet packet = pending_packets_.front();
- pending_packets_.pop_front();
- if (packet.is_eos) {
- // No data should be submitted after EOS.
- CHECK(pending_packets_.empty());
- audio_consumer_binding_.events().OnEndOfStream();
- state_ = State::kEndOfStream;
- media_pos_ = new_media_pos;
- reference_time_ = now;
- }
- }
- ScheduleNextStreamPosUpdate();
- }
- void FakeAudioConsumer::OnStatusUpdate() {
- have_status_update_ = true;
- if (status_callback_) {
- CallStatusCallback();
- }
- }
- void FakeAudioConsumer::CallStatusCallback() {
- DCHECK(status_callback_);
- DCHECK(have_status_update_);
- fuchsia::media::AudioConsumerStatus status;
- if (state_ == State::kPlaying) {
- fuchsia::media::TimelineFunction timeline;
- timeline.reference_time = reference_time_.ToZxTime();
- timeline.subject_time = media_pos_.ToZxDuration();
- timeline.reference_delta = reference_delta_;
- timeline.subject_delta = media_delta_;
- status.set_presentation_timeline(std::move(timeline));
- }
- status.set_min_lead_time(kMinLeadTime.ToZxDuration());
- status.set_max_lead_time(kMaxLeadTime.ToZxDuration());
- have_status_update_ = false;
- std::move(status_callback_)(std::move(status));
- status_callback_ = {};
- }
- FakeAudioConsumerService::FakeAudioConsumerService(vfs::PseudoDir* pseudo_dir)
- : binding_(pseudo_dir, this) {}
- FakeAudioConsumerService::~FakeAudioConsumerService() {}
- void FakeAudioConsumerService::CreateAudioConsumer(
- uint64_t session_id,
- fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) {
- audio_consumers_.push_back(
- std::make_unique<FakeAudioConsumer>(session_id, std::move(request)));
- }
- void FakeAudioConsumerService::NotImplemented_(const std::string& name) {
- LOG(FATAL) << "Reached non-implemented " << name;
- }
- } // namespace media
|