Index: services/media/audio/audio_pipe.cc |
diff --git a/services/media/audio/audio_pipe.cc b/services/media/audio/audio_pipe.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9c3702cb035e0640292d33fe4e8a3bb1960052aa |
--- /dev/null |
+++ b/services/media/audio/audio_pipe.cc |
@@ -0,0 +1,131 @@ |
+// Copyright 2015 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 <limits> |
+#include <vector> |
+ |
+#include "services/media/audio/audio_pipe.h" |
+#include "services/media/audio/audio_server_impl.h" |
+#include "services/media/audio/audio_track_impl.h" |
+ |
+namespace mojo { |
+namespace media { |
+namespace audio { |
+ |
+AudioPipe::AudioPacketRef::AudioPacketRef( |
+ MediaPacketStatePtr state, |
+ AudioServerImpl* server, |
+ std::vector<Region>&& regions, // NOLINT(build/c++11) |
+ int64_t start_pts, |
+ int64_t end_pts) |
+ : state_(std::move(state)), |
+ server_(server), |
+ regions_(std::move(regions)), |
+ start_pts_(start_pts), |
+ end_pts_(end_pts) { |
+ DCHECK(state_); |
+ DCHECK(server_); |
+} |
+ |
+AudioPipe::AudioPacketRef::~AudioPacketRef() { |
+ DCHECK(server_); |
+ server_->SchedulePacketCleanup(std::move(state_)); |
+} |
+ |
+AudioPipe::AudioPipe(AudioTrackImpl* owner, |
+ AudioServerImpl* server) |
+ : owner_(owner), |
+ server_(server) { |
+ DCHECK(owner_); |
+ DCHECK(server_); |
+} |
+ |
+AudioPipe::~AudioPipe() {} |
+ |
+void AudioPipe::OnPacketReceived(MediaPacketStatePtr state) { |
+ const MediaPacketPtr& packet = state->GetPacket(); |
+ DCHECK(packet); |
+ DCHECK(packet->payload); |
+ DCHECK(owner_); |
+ |
+ // Start by making sure that we are regions we are receiving are made from an |
+ // integral number of audio frames. Count the total number of frames in the |
+ // process. |
+ // |
+ // TODO(johngro): Someday, automatically enforce this using |
+ // alignment/allocation restrictions at the MediaPipe level of things. |
+ uint32_t frame_count = 0; |
+ uint32_t frame_size = owner_->BytesPerFrame(); |
+ const MediaPacketRegionPtr* region = &packet->payload; |
+ size_t ndx = 0; |
+ std::vector<AudioPacketRef::Region> regions; |
+ |
+ regions.reserve(packet->extra_payload.size() + 1); |
+ |
+ DCHECK(frame_size); |
+ while (true) { |
+ if ((frame_size > 1) && ((*region)->length % frame_size)) { |
+ state->SetResult(MediaResult::INVALID_ARGUMENT); |
+ return; |
+ } |
+ |
+ frame_count += ((*region)->length / frame_size); |
+ if (frame_count > (std::numeric_limits<uint32_t>::max() >> |
+ AudioTrackImpl::PTS_FRACTIONAL_BITS)) { |
+ state->SetResult(MediaResult::INVALID_ARGUMENT); |
+ return; |
+ } |
+ |
+ regions.emplace_back( |
+ static_cast<const uint8_t*>(buffer()) + (*region)->offset, |
+ frame_count << AudioTrackImpl::PTS_FRACTIONAL_BITS); |
+ |
+ if (ndx >= packet->extra_payload.size()) { |
+ break; |
+ } |
+ |
+ region = &(packet->extra_payload[ndx]); |
+ ndx++; |
+ } |
+ |
+ // Figure out the starting PTS. |
+ int64_t start_pts; |
+ if (packet->pts != MediaPacket::kNoTimestamp) { |
+ // The user provided an explicit PTS for this audio. Transform it into |
+ // units of fractional frames. |
+ LinearTransform tmp(0, owner_->FractionalFrameToMediaTimeRatio(), 0); |
+ if (!tmp.DoForwardTransform(packet->pts, &start_pts)) { |
+ state->SetResult(MediaResult::INTERNAL_ERROR); |
+ return; |
+ } |
+ } else { |
+ // No PTS was provided. Use the end time of the last audio packet, if |
+ // known. Otherwise, just assume a media time of 0. |
+ start_pts = next_pts_known_ ? next_pts_ : 0; |
+ } |
+ |
+ // The end pts is the value we will use for the next packet's start PTS, if |
+ // the user does not provide an explicit PTS. |
+ int64_t pts_delta = (static_cast<int64_t>(frame_count) |
+ << AudioTrackImpl::PTS_FRACTIONAL_BITS); |
+ next_pts_ = start_pts + pts_delta; |
+ next_pts_known_ = true; |
+ |
+ owner_->OnPacketReceived(AudioPacketRefPtr( |
+ new AudioPacketRef(std::move(state), |
+ server_, |
+ std::move(regions), |
+ start_pts, |
+ next_pts_))); |
+} |
+ |
+void AudioPipe::OnFlushRequested(const FlushCallback& cbk) { |
+ DCHECK(owner_); |
+ owner_->OnFlushRequested(cbk); |
+ next_pts_known_ = false; |
+} |
+ |
+} // namespace audio |
+} // namespace media |
+} // namespace mojo |