fake_audio_consumer.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/fuchsia/audio/fake_audio_consumer.h"
  5. #include <lib/vfs/cpp/pseudo_dir.h>
  6. #include <lib/vfs/cpp/service.h>
  7. #include "base/fuchsia/fuchsia_logging.h"
  8. namespace media {
  9. const base::TimeDelta FakeAudioConsumer::kMinLeadTime = base::Milliseconds(100);
  10. const base::TimeDelta FakeAudioConsumer::kMaxLeadTime = base::Milliseconds(500);
  11. FakeAudioConsumer::FakeAudioConsumer(
  12. uint64_t session_id,
  13. fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request)
  14. : session_id_(session_id),
  15. audio_consumer_binding_(this),
  16. stream_sink_binding_(this),
  17. volume_control_binding_(this) {
  18. audio_consumer_binding_.Bind(std::move(request));
  19. }
  20. FakeAudioConsumer::~FakeAudioConsumer() = default;
  21. base::TimeDelta FakeAudioConsumer::GetMediaPosition() {
  22. base::TimeDelta result = media_pos_;
  23. if (state_ == State::kPlaying) {
  24. result += (base::TimeTicks::Now() - reference_time_) * media_delta_ /
  25. reference_delta_;
  26. }
  27. return result;
  28. }
  29. void FakeAudioConsumer::CreateStreamSink(
  30. std::vector<zx::vmo> buffers,
  31. fuchsia::media::AudioStreamType stream_type,
  32. std::unique_ptr<fuchsia::media::Compression> compression,
  33. fidl::InterfaceRequest<fuchsia::media::StreamSink> stream_sink_request) {
  34. num_buffers_ = buffers.size();
  35. CHECK_GT(num_buffers_, 0U);
  36. stream_sink_binding_.Bind(std::move(stream_sink_request));
  37. }
  38. void FakeAudioConsumer::Start(fuchsia::media::AudioConsumerStartFlags flags,
  39. int64_t reference_time,
  40. int64_t media_time) {
  41. CHECK(state_ == State::kStopped);
  42. if (reference_time != fuchsia::media::NO_TIMESTAMP) {
  43. reference_time_ = base::TimeTicks::FromZxTime(reference_time);
  44. } else {
  45. reference_time_ = base::TimeTicks::Now() + kMinLeadTime;
  46. }
  47. if (media_time != fuchsia::media::NO_TIMESTAMP) {
  48. media_pos_ = base::TimeDelta::FromZxDuration(media_time);
  49. } else {
  50. if (media_pos_.is_min()) {
  51. media_pos_ = base::TimeDelta();
  52. }
  53. }
  54. state_ = State::kPlaying;
  55. OnStatusUpdate();
  56. ScheduleNextStreamPosUpdate();
  57. }
  58. void FakeAudioConsumer::Stop() {
  59. CHECK(state_ != State::kStopped);
  60. state_ = State::kStopped;
  61. OnStatusUpdate();
  62. }
  63. void FakeAudioConsumer::WatchStatus(WatchStatusCallback callback) {
  64. status_callback_ = std::move(callback);
  65. if (have_status_update_) {
  66. CallStatusCallback();
  67. }
  68. }
  69. void FakeAudioConsumer::SetRate(float rate) {
  70. // Playback rate must not be negative.
  71. CHECK_GE(rate, 0.0);
  72. // Update reference position.
  73. auto now = base::TimeTicks::Now();
  74. media_pos_ =
  75. media_pos_ + (now - reference_time_) * media_delta_ / reference_delta_;
  76. reference_time_ = now;
  77. // Approximate the rate as n/1000;
  78. reference_delta_ = 1000;
  79. media_delta_ = static_cast<int>(rate * 1000.0);
  80. OnStatusUpdate();
  81. if (update_timer_.IsRunning())
  82. update_timer_.Reset();
  83. ScheduleNextStreamPosUpdate();
  84. }
  85. void FakeAudioConsumer::BindVolumeControl(
  86. fidl::InterfaceRequest<fuchsia::media::audio::VolumeControl>
  87. volume_control_request) {
  88. volume_control_binding_.Bind(std::move(volume_control_request));
  89. }
  90. void FakeAudioConsumer::SendPacket(fuchsia::media::StreamPacket stream_packet,
  91. SendPacketCallback callback) {
  92. CHECK_LT(stream_packet.payload_buffer_id, num_buffers_);
  93. Packet packet;
  94. if (stream_packet.pts == fuchsia::media::NO_TIMESTAMP) {
  95. if (media_pos_.is_min()) {
  96. packet.pts = base::TimeDelta();
  97. } else {
  98. packet.pts = media_pos_;
  99. }
  100. } else {
  101. packet.pts = base::TimeDelta::FromZxDuration(stream_packet.pts);
  102. }
  103. pending_packets_.push_back(std::move(packet));
  104. callback();
  105. ScheduleNextStreamPosUpdate();
  106. }
  107. void FakeAudioConsumer::SendPacketNoReply(fuchsia::media::StreamPacket packet) {
  108. NOTREACHED();
  109. }
  110. void FakeAudioConsumer::EndOfStream() {
  111. Packet packet;
  112. packet.is_eos = true;
  113. pending_packets_.push_back(std::move(packet));
  114. }
  115. void FakeAudioConsumer::DiscardAllPackets(DiscardAllPacketsCallback callback) {
  116. DiscardAllPacketsNoReply();
  117. std::move(callback)();
  118. }
  119. void FakeAudioConsumer::DiscardAllPacketsNoReply() {
  120. pending_packets_.clear();
  121. }
  122. void FakeAudioConsumer::SetVolume(float volume) {
  123. volume_ = volume;
  124. }
  125. void FakeAudioConsumer::SetMute(bool mute) {
  126. is_muted_ = mute;
  127. }
  128. void FakeAudioConsumer::NotImplemented_(const std::string& name) {
  129. LOG(FATAL) << "Reached non-implemented " << name;
  130. }
  131. void FakeAudioConsumer::ScheduleNextStreamPosUpdate() {
  132. if (pending_packets_.empty() || update_timer_.IsRunning() ||
  133. media_delta_ == 0 || state_ != State::kPlaying) {
  134. return;
  135. }
  136. base::TimeDelta delay;
  137. if (!pending_packets_.front().is_eos) {
  138. auto next_packet_time =
  139. reference_time_ + (pending_packets_.front().pts - media_pos_) *
  140. reference_delta_ / media_delta_;
  141. delay = (next_packet_time - base::TimeTicks::Now());
  142. }
  143. update_timer_.Start(FROM_HERE, delay,
  144. base::BindOnce(&FakeAudioConsumer::UpdateStreamPos,
  145. base::Unretained(this)));
  146. }
  147. void FakeAudioConsumer::UpdateStreamPos() {
  148. if (state_ != State::kPlaying)
  149. return;
  150. auto now = base::TimeTicks::Now();
  151. auto new_media_pos =
  152. media_pos_ + (now - reference_time_) * media_delta_ / reference_delta_;
  153. // Drop all packets with PTS before the current position.
  154. while (!pending_packets_.empty()) {
  155. if (!pending_packets_.front().is_eos &&
  156. pending_packets_.front().pts > new_media_pos) {
  157. break;
  158. }
  159. Packet packet = pending_packets_.front();
  160. pending_packets_.pop_front();
  161. if (packet.is_eos) {
  162. // No data should be submitted after EOS.
  163. CHECK(pending_packets_.empty());
  164. audio_consumer_binding_.events().OnEndOfStream();
  165. state_ = State::kEndOfStream;
  166. media_pos_ = new_media_pos;
  167. reference_time_ = now;
  168. }
  169. }
  170. ScheduleNextStreamPosUpdate();
  171. }
  172. void FakeAudioConsumer::OnStatusUpdate() {
  173. have_status_update_ = true;
  174. if (status_callback_) {
  175. CallStatusCallback();
  176. }
  177. }
  178. void FakeAudioConsumer::CallStatusCallback() {
  179. DCHECK(status_callback_);
  180. DCHECK(have_status_update_);
  181. fuchsia::media::AudioConsumerStatus status;
  182. if (state_ == State::kPlaying) {
  183. fuchsia::media::TimelineFunction timeline;
  184. timeline.reference_time = reference_time_.ToZxTime();
  185. timeline.subject_time = media_pos_.ToZxDuration();
  186. timeline.reference_delta = reference_delta_;
  187. timeline.subject_delta = media_delta_;
  188. status.set_presentation_timeline(std::move(timeline));
  189. }
  190. status.set_min_lead_time(kMinLeadTime.ToZxDuration());
  191. status.set_max_lead_time(kMaxLeadTime.ToZxDuration());
  192. have_status_update_ = false;
  193. std::move(status_callback_)(std::move(status));
  194. status_callback_ = {};
  195. }
  196. FakeAudioConsumerService::FakeAudioConsumerService(vfs::PseudoDir* pseudo_dir)
  197. : binding_(pseudo_dir, this) {}
  198. FakeAudioConsumerService::~FakeAudioConsumerService() {}
  199. void FakeAudioConsumerService::CreateAudioConsumer(
  200. uint64_t session_id,
  201. fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) {
  202. audio_consumers_.push_back(
  203. std::make_unique<FakeAudioConsumer>(session_id, std::move(request)));
  204. }
  205. void FakeAudioConsumerService::NotImplemented_(const std::string& name) {
  206. LOG(FATAL) << "Reached non-implemented " << name;
  207. }
  208. } // namespace media