| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 1 | // 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 | |
| 8 | namespace mojo { |
| 9 | namespace media { |
| 10 | |
| Dale Sather | 4ccdd21 | 2016-03-23 09:27:19 -0700 | [diff] [blame] | 11 | MojoPullModeProducer::MojoPullModeProducer() |
| 12 | : state_(MediaState::UNPREPARED), |
| 13 | demand_(Demand::kNegative), |
| 14 | pts_(0), |
| 15 | cached_packet_(nullptr) {} |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 16 | |
| 17 | MojoPullModeProducer::~MojoPullModeProducer() { |
| 18 | base::AutoLock lock(lock_); |
| 19 | } |
| 20 | |
| 21 | void MojoPullModeProducer::AddBinding( |
| 22 | InterfaceRequest<MediaPullModeProducer> producer) { |
| 23 | bindings_.AddBinding(this, producer.Pass()); |
| 24 | } |
| 25 | |
| 26 | void MojoPullModeProducer::GetBuffer(const GetBufferCallback& callback) { |
| 27 | if (!mojo_allocator_.initialized()) { |
| Dale Sather | 4ccdd21 | 2016-03-23 09:27:19 -0700 | [diff] [blame] | 28 | mojo_allocator_.InitNew(256 * 1024); // TODO(dalesat): Made up! |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 29 | } |
| 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 Sather | 4ccdd21 | 2016-03-23 09:27:19 -0700 | [diff] [blame] | 45 | void MojoPullModeProducer::PullPacket(MediaPacketPtr to_release, |
| 46 | const PullPacketCallback& callback) { |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 47 | 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 | |
| 76 | void MojoPullModeProducer::ReleasePacket(MediaPacketPtr to_release) { |
| 77 | { |
| 78 | base::AutoLock lock(lock_); |
| 79 | uint64_t size = to_release->payload ? to_release->payload->length : 0; |
| Dale Sather | 4ccdd21 | 2016-03-23 09:27:19 -0700 | [diff] [blame] | 80 | void* payload = size == 0 ? nullptr : mojo_allocator_.PtrFromOffset( |
| 81 | to_release->payload->offset); |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 82 | |
| 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 | |
| 102 | PayloadAllocator* MojoPullModeProducer::allocator() { |
| 103 | return mojo_allocator_.initialized() ? &mojo_allocator_ : nullptr; |
| 104 | } |
| 105 | |
| 106 | void MojoPullModeProducer::SetDemandCallback( |
| 107 | const DemandCallback& demand_callback) { |
| 108 | demand_callback_ = demand_callback; |
| 109 | } |
| 110 | |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 111 | Demand 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 | |
| 136 | void 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 | |
| 150 | bool 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 Sather | 4ccdd21 | 2016-03-23 09:27:19 -0700 | [diff] [blame] | 157 | HandlePullWithPacketUnsafe(callback, Packet::CreateEndOfStream(pts_)); |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 158 | 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 | |
| 170 | void 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 | |
| 181 | MediaPacketPtr 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 Sather | 103f68e | 2016-03-21 17:07:19 -0700 | [diff] [blame] | 190 | media_packet->pts = packet->pts(); |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 191 | media_packet->end_of_stream = packet->end_of_stream(); |
| 192 | media_packet->payload = region.Pass(); |
| Dale Sather | 103f68e | 2016-03-21 17:07:19 -0700 | [diff] [blame] | 193 | pts_ = packet->pts(); |
| Dale Sather | de39bcb | 2016-03-01 13:24:14 -0800 | [diff] [blame] | 194 | |
| 195 | return media_packet.Pass(); |
| 196 | } |
| 197 | |
| Dale Sather | 4ccdd21 | 2016-03-23 09:27:19 -0700 | [diff] [blame] | 198 | } // namespace media |
| 199 | } // namespace mojo |