blob: f953aa59b1e77dcda04ac254e0a1f2782e54c48e [file] [log] [blame]
Dale Satherde39bcb2016-03-01 13:24:14 -08001// Copyright 2016 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
5#include "base/logging.h"
6#include "services/media/framework_mojo/mojo_pull_mode_producer.h"
7
8namespace mojo {
9namespace media {
10
Dale Sather4ccdd212016-03-23 09:27:19 -070011MojoPullModeProducer::MojoPullModeProducer()
12 : state_(MediaState::UNPREPARED),
13 demand_(Demand::kNegative),
14 pts_(0),
15 cached_packet_(nullptr) {}
Dale Satherde39bcb2016-03-01 13:24:14 -080016
17MojoPullModeProducer::~MojoPullModeProducer() {
18 base::AutoLock lock(lock_);
19}
20
21void MojoPullModeProducer::AddBinding(
22 InterfaceRequest<MediaPullModeProducer> producer) {
23 bindings_.AddBinding(this, producer.Pass());
24}
25
26void MojoPullModeProducer::GetBuffer(const GetBufferCallback& callback) {
27 if (!mojo_allocator_.initialized()) {
Dale Sather4ccdd212016-03-23 09:27:19 -070028 mojo_allocator_.InitNew(256 * 1024); // TODO(dalesat): Made up!
Dale Satherde39bcb2016-03-01 13:24:14 -080029 }
30
31 {
32 base::AutoLock lock(lock_);
33 if (state_ == MediaState::UNPREPARED) {
34 state_ = MediaState::PAUSED;
35 }
36 }
37
38 callback.Run(mojo_allocator_.GetDuplicateHandle());
39
40 DCHECK(!cached_packet_);
41 DCHECK(demand_callback_);
42 demand_callback_(Demand::kPositive);
43}
44
Dale Sather4ccdd212016-03-23 09:27:19 -070045void MojoPullModeProducer::PullPacket(MediaPacketPtr to_release,
46 const PullPacketCallback& callback) {
Dale Satherde39bcb2016-03-01 13:24:14 -080047 if (to_release) {
48 // The client has piggy-backed a release on this pull request.
49 ReleasePacket(to_release.Pass());
50 }
51
52 {
53 base::AutoLock lock(lock_);
54
55 if (state_ == MediaState::UNPREPARED) {
56 // The consumer has yet to call GetBuffer. This request will have to wait.
57 pending_pulls_.push_back(callback);
58 return;
59 }
60
61 DCHECK(mojo_allocator_.initialized());
62
63 // If there are no pending requests, see if we can handle this now. If
64 // requests are pending, add the callback to the pending queue.
65 if (!pending_pulls_.empty() || !MaybeHandlePullUnsafe(callback)) {
66 pending_pulls_.push_back(callback);
67 }
68
69 DCHECK(!cached_packet_);
70 }
71
72 DCHECK(demand_callback_);
73 demand_callback_(Demand::kPositive);
74}
75
76void MojoPullModeProducer::ReleasePacket(MediaPacketPtr to_release) {
77 {
78 base::AutoLock lock(lock_);
79 uint64_t size = to_release->payload ? to_release->payload->length : 0;
Dale Sather4ccdd212016-03-23 09:27:19 -070080 void* payload = size == 0 ? nullptr : mojo_allocator_.PtrFromOffset(
81 to_release->payload->offset);
Dale Satherde39bcb2016-03-01 13:24:14 -080082
83 for (auto iterator = unreleased_packets_.begin(); true; ++iterator) {
84 if (iterator == unreleased_packets_.end()) {
85 DCHECK(false) << "released packet has bad offset and/or size";
86 break;
87 }
88
89 if ((*iterator)->payload() == payload && (*iterator)->size() == size) {
90 unreleased_packets_.erase(iterator);
91 break;
92 }
93 }
94
95 // TODO(dalesat): What if the allocator has starved?
96 }
97
98 DCHECK(demand_callback_);
99 demand_callback_(cached_packet_ ? Demand::kNegative : Demand::kPositive);
100}
101
102PayloadAllocator* MojoPullModeProducer::allocator() {
103 return mojo_allocator_.initialized() ? &mojo_allocator_ : nullptr;
104}
105
106void MojoPullModeProducer::SetDemandCallback(
107 const DemandCallback& demand_callback) {
108 demand_callback_ = demand_callback;
109}
110
Dale Satherde39bcb2016-03-01 13:24:14 -0800111Demand MojoPullModeProducer::SupplyPacket(PacketPtr packet) {
112 base::AutoLock lock(lock_);
113 DCHECK(demand_ != Demand::kNegative) << "packet pushed with negative demand";
114 DCHECK(state_ != MediaState::ENDED) << "packet pushed after end-of-stream";
115
116 DCHECK(!cached_packet_);
117
118 // If there's no binding on the stream, throw the packet away. This can
119 // happen if a pull client disconnects unexpectedly.
120 if (bindings_.size() == 0) {
121 demand_ = Demand::kNegative;
122 state_ = MediaState::UNPREPARED;
123 // TODO(dalesat): More shutdown?
124 return demand_;
125 }
126
127 // Accept the packet and handle pending pulls with it.
128 cached_packet_ = std::move(packet);
129
130 HandlePendingPullsUnsafe();
131
132 demand_ = cached_packet_ ? Demand::kNegative : Demand::kPositive;
133 return demand_;
134}
135
136void MojoPullModeProducer::HandlePendingPullsUnsafe() {
137 lock_.AssertAcquired();
138
139 while (!pending_pulls_.empty()) {
140 DCHECK(mojo_allocator_.initialized());
141
142 if (MaybeHandlePullUnsafe(pending_pulls_.front())) {
143 pending_pulls_.pop_front();
144 } else {
145 break;
146 }
147 }
148}
149
150bool MojoPullModeProducer::MaybeHandlePullUnsafe(
151 const PullPacketCallback& callback) {
152 DCHECK(!callback.is_null());
153 lock_.AssertAcquired();
154
155 if (state_ == MediaState::ENDED) {
156 // At end-of-stream. Respond with empty end-of-stream packet.
Dale Sather4ccdd212016-03-23 09:27:19 -0700157 HandlePullWithPacketUnsafe(callback, Packet::CreateEndOfStream(pts_));
Dale Satherde39bcb2016-03-01 13:24:14 -0800158 return true;
159 }
160
161 if (!cached_packet_) {
162 // Waiting for packet or end-of-stream indication.
163 return false;
164 }
165
166 HandlePullWithPacketUnsafe(callback, std::move(cached_packet_));
167 return true;
168}
169
170void MojoPullModeProducer::HandlePullWithPacketUnsafe(
171 const PullPacketCallback& callback,
172 PacketPtr packet) {
173 DCHECK(packet);
174 lock_.AssertAcquired();
175
176 // TODO(dalesat): Use TaskRunner for this callback.
177 callback.Run(CreateMediaPacket(packet));
178 unreleased_packets_.push_back(std::move(packet));
179}
180
181MediaPacketPtr MojoPullModeProducer::CreateMediaPacket(
182 const PacketPtr& packet) {
183 DCHECK(packet);
184
185 MediaPacketRegionPtr region = MediaPacketRegion::New();
186 region->offset = mojo_allocator_.OffsetFromPtr(packet->payload());
187 region->length = packet->size();
188
189 MediaPacketPtr media_packet = MediaPacket::New();
Dale Sather103f68e2016-03-21 17:07:19 -0700190 media_packet->pts = packet->pts();
Dale Satherde39bcb2016-03-01 13:24:14 -0800191 media_packet->end_of_stream = packet->end_of_stream();
192 media_packet->payload = region.Pass();
Dale Sather103f68e2016-03-21 17:07:19 -0700193 pts_ = packet->pts();
Dale Satherde39bcb2016-03-01 13:24:14 -0800194
195 return media_packet.Pass();
196}
197
Dale Sather4ccdd212016-03-23 09:27:19 -0700198} // namespace media
199} // namespace mojo