blob: e1c1aa96c0e502890829876785c853ebf5625360 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "include/private/dvr/buffer_hub_queue_client.h"
2
Alex Vakulenko4fe60582017-02-02 11:35:59 -08003#include <inttypes.h>
4#include <log/log.h>
Corey Tabaka2b99ee52017-05-04 10:56:05 -07005#include <poll.h>
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -07006#include <sys/epoll.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08007
8#include <array>
9
10#include <pdx/default_transport/client_channel.h>
11#include <pdx/default_transport/client_channel_factory.h>
12#include <pdx/file_handle.h>
Corey Tabaka52ea25c2017-09-13 18:02:48 -070013#include <pdx/trace.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080014
Corey Tabaka2b99ee52017-05-04 10:56:05 -070015#define RETRY_EINTR(fnc_call) \
16 ([&]() -> decltype(fnc_call) { \
17 decltype(fnc_call) result; \
18 do { \
19 result = (fnc_call); \
20 } while (result == -1 && errno == EINTR); \
21 return result; \
22 })()
23
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070024using android::pdx::ErrorStatus;
25using android::pdx::LocalChannelHandle;
Corey Tabakab7ca5de2017-05-08 18:55:02 -070026using android::pdx::LocalHandle;
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070027using android::pdx::Status;
28
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080029namespace android {
30namespace dvr {
31
Corey Tabakab7ca5de2017-05-08 18:55:02 -070032namespace {
33
Corey Tabakab7ca5de2017-05-08 18:55:02 -070034std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
35 return {static_cast<int32_t>(value >> 32),
36 static_cast<int32_t>(value & ((1ull << 32) - 1))};
37}
38
39uint64_t Stuff(int32_t a, int32_t b) {
40 const uint32_t ua = static_cast<uint32_t>(a);
41 const uint32_t ub = static_cast<uint32_t>(b);
42 return (static_cast<uint64_t>(ua) << 32) | static_cast<uint64_t>(ub);
43}
44
45} // anonymous namespace
46
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070047BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080048 : Client{pdx::default_transport::ClientChannel::Create(
Corey Tabakab7ca5de2017-05-08 18:55:02 -070049 std::move(channel_handle))} {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080050 Initialize();
51}
52
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070053BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
Corey Tabakab7ca5de2017-05-08 18:55:02 -070054 : Client{
55 pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080056 Initialize();
57}
58
59void BufferHubQueue::Initialize() {
60 int ret = epoll_fd_.Create();
61 if (ret < 0) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -080062 ALOGE("BufferHubQueue::BufferHubQueue: Failed to create epoll fd: %s",
63 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080064 return;
65 }
66
Corey Tabakab7ca5de2017-05-08 18:55:02 -070067 epoll_event event = {
68 .events = EPOLLIN | EPOLLET,
69 .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080070 ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
71 if (ret < 0) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070072 ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
Alex Vakulenko4fe60582017-02-02 11:35:59 -080073 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080074 }
75}
76
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070077Status<void> BufferHubQueue::ImportQueue() {
78 auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080079 if (!status) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070080 ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
81 status.GetErrorMessage().c_str());
82 return ErrorStatus(status.error());
83 } else {
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -070084 SetupQueue(status.get());
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070085 return {};
86 }
87}
88
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -070089void BufferHubQueue::SetupQueue(const QueueInfo& queue_info) {
90 is_async_ = queue_info.producer_config.is_async;
91 default_width_ = queue_info.producer_config.default_width;
92 default_height_ = queue_info.producer_config.default_height;
93 default_format_ = queue_info.producer_config.default_format;
Corey Tabaka52ea25c2017-09-13 18:02:48 -070094 user_metadata_size_ = queue_info.producer_config.user_metadata_size;
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -070095 id_ = queue_info.id;
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070096}
97
98std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -070099 if (auto status = CreateConsumerQueueHandle(/*silent*/ false))
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700100 return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
101 else
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800102 return nullptr;
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700103}
104
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700105std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700106 if (auto status = CreateConsumerQueueHandle(/*silent*/ true))
107 return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700108 else
109 return nullptr;
110}
111
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700112Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle(
113 bool silent) {
114 auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent);
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700115 if (!status) {
116 ALOGE(
117 "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
118 "%s",
119 status.GetErrorMessage().c_str());
120 return ErrorStatus(status.error());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800121 }
122
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700123 return status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800124}
125
Jiwen 'Steve' Caia88e3ee2017-11-03 17:33:33 -0700126pdx::Status<ConsumerQueueParcelable>
127BufferHubQueue::CreateConsumerQueueParcelable(bool silent) {
128 auto status = CreateConsumerQueueHandle(silent);
129 if (!status)
130 return status.error_status();
131
132 // A temporary consumer queue client to pull its channel parcelable.
133 auto consumer_queue =
134 std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
135 ConsumerQueueParcelable queue_parcelable(
136 consumer_queue->GetChannel()->TakeChannelParcelable());
137
138 if (!queue_parcelable.IsValid()) {
139 ALOGE(
140 "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
141 "consumer queue parcelable.");
142 return ErrorStatus(EINVAL);
143 }
144
145 return {std::move(queue_parcelable)};
146}
147
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800148bool BufferHubQueue::WaitForBuffers(int timeout) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700149 ATRACE_NAME("BufferHubQueue::WaitForBuffers");
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800150 std::array<epoll_event, kMaxEvents> events;
151
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700152 // Loop at least once to check for hangups.
153 do {
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700154 ALOGD_IF(
155 TRACE,
156 "BufferHubQueue::WaitForBuffers: queue_id=%d count=%zu capacity=%zu",
157 id(), count(), capacity());
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700158
159 // If there is already a buffer then just check for hangup without waiting.
160 const int ret = epoll_fd_.Wait(events.data(), events.size(),
161 count() == 0 ? timeout : 0);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800162
163 if (ret == 0) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700164 ALOGI_IF(TRACE,
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700165 "BufferHubQueue::WaitForBuffers: No events before timeout: "
166 "queue_id=%d",
167 id());
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700168 return count() != 0;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800169 }
170
171 if (ret < 0 && ret != -EINTR) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700172 ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
173 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800174 return false;
175 }
176
177 const int num_events = ret;
178
179 // A BufferQueue's epoll fd tracks N+1 events, where there are N events,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700180 // one for each buffer in the queue, and one extra event for the queue
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800181 // client itself.
182 for (int i = 0; i < num_events; i++) {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700183 int32_t event_fd;
184 int32_t index;
185 std::tie(event_fd, index) = Unstuff(events[i].data.u64);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800186
Corey Tabaka4a05cbf2017-10-11 10:52:54 -0700187 PDX_TRACE_FORMAT(
188 "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;"
189 "slot=%d|",
190 id(), num_events, i, event_fd, index);
191
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700192 ALOGD_IF(TRACE,
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700193 "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d",
194 i, event_fd, index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800195
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800196 if (is_buffer_event_index(index)) {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700197 HandleBufferEvent(static_cast<size_t>(index), event_fd,
198 events[i].events);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800199 } else if (is_queue_event_index(index)) {
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700200 HandleQueueEvent(events[i].events);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800201 } else {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700202 ALOGW(
203 "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d "
204 "index=%d",
205 event_fd, index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800206 }
207 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700208 } while (count() == 0 && capacity() > 0 && !hung_up());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800209
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700210 return count() != 0;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800211}
212
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700213Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
214 int poll_events) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700215 ATRACE_NAME("BufferHubQueue::HandleBufferEvent");
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700216 if (!buffers_[slot]) {
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800217 ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700218 return ErrorStatus(ENOENT);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800219 }
220
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700221 auto status = buffers_[slot]->GetEventMask(poll_events);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800222 if (!status) {
223 ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
224 status.GetErrorMessage().c_str());
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700225 return status.error_status();
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800226 }
227
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700228 const int events = status.get();
Corey Tabaka4a05cbf2017-10-11 10:52:54 -0700229 PDX_TRACE_FORMAT(
230 "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;"
231 "events=%d|",
232 id(), buffers_[slot]->id(), slot, event_fd, poll_events, events);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700233
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800234 if (events & EPOLLIN) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700235 return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()});
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800236 } else if (events & EPOLLHUP) {
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800237 ALOGW(
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700238 "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700239 "event_fd=%d buffer_id=%d",
240 slot, buffers_[slot]->event_fd(), buffers_[slot]->id());
241 return RemoveBuffer(slot);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800242 } else {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700243 ALOGW(
244 "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
245 "events=%d",
246 slot, events);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800247 }
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700248
249 return {};
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800250}
251
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700252Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700253 ATRACE_NAME("BufferHubQueue::HandleQueueEvent");
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700254 auto status = GetEventMask(poll_event);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800255 if (!status) {
256 ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
257 status.GetErrorMessage().c_str());
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700258 return status.error_status();
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800259 }
260
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700261 const int events = status.get();
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800262 if (events & EPOLLIN) {
263 // Note that after buffer imports, if |count()| still returns 0, epoll
264 // wait will be tried again to acquire the newly imported buffer.
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700265 auto buffer_status = OnBufferAllocated();
266 if (!buffer_status) {
267 ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
268 buffer_status.GetErrorMessage().c_str());
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800269 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700270 } else if (events & EPOLLHUP) {
271 ALOGD_IF(TRACE, "BufferHubQueue::HandleQueueEvent: hang up event!");
272 hung_up_ = true;
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800273 } else {
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700274 ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800275 }
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700276
277 return {};
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800278}
279
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700280Status<void> BufferHubQueue::AddBuffer(
Jiwen 'Steve' Caic6fcf2f2018-09-27 23:34:45 -0700281 const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700282 ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
283 buffer->id(), slot);
284
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800285 if (is_full()) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800286 ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
287 capacity_);
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700288 return ErrorStatus(E2BIG);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800289 }
290
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700291 if (buffers_[slot]) {
292 // Replace the buffer if the slot is occupied. This could happen when the
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700293 // producer side replaced the slot with a newly allocated buffer. Remove the
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800294 // buffer before setting up with the new one.
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700295 auto remove_status = RemoveBuffer(slot);
296 if (!remove_status)
297 return remove_status.error_status();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800298 }
299
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700300 for (const auto& event_source : buffer->GetEventSources()) {
301 epoll_event event = {.events = event_source.event_mask | EPOLLET,
302 .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
303 const int ret =
304 epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
305 if (ret < 0) {
306 ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
307 strerror(-ret));
308 return ErrorStatus(-ret);
309 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800310 }
311
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700312 buffers_[slot] = buffer;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800313 capacity_++;
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700314 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800315}
316
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700317Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
318 ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700319
320 if (buffers_[slot]) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700321 for (const auto& event_source : buffers_[slot]->GetEventSources()) {
322 const int ret =
323 epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
324 if (ret < 0) {
325 ALOGE(
326 "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
327 "set: %s",
328 strerror(-ret));
329 return ErrorStatus(-ret);
330 }
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700331 }
332
Jiwen 'Steve' Cai0b801552017-05-24 11:50:11 -0700333 // Trigger OnBufferRemoved callback if registered.
334 if (on_buffer_removed_)
335 on_buffer_removed_(buffers_[slot]);
336
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700337 buffers_[slot] = nullptr;
338 capacity_--;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800339 }
340
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700341 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800342}
343
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700344Status<void> BufferHubQueue::Enqueue(Entry entry) {
345 if (!is_full()) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700346 available_buffers_.push(std::move(entry));
Jiwen 'Steve' Cai0b801552017-05-24 11:50:11 -0700347
348 // Trigger OnBufferAvailable callback if registered.
349 if (on_buffer_available_)
350 on_buffer_available_();
351
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700352 return {};
353 } else {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700354 ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700355 return ErrorStatus(E2BIG);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800356 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800357}
358
Jiwen 'Steve' Caic6fcf2f2018-09-27 23:34:45 -0700359Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
360 size_t* slot) {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700361 ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
362 timeout);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800363
Corey Tabaka4a05cbf2017-10-11 10:52:54 -0700364 PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
365
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700366 if (count() == 0) {
367 if (!WaitForBuffers(timeout))
368 return ErrorStatus(ETIMEDOUT);
369 }
370
371 auto& entry = available_buffers_.top();
Corey Tabaka4a05cbf2017-10-11 10:52:54 -0700372 PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(),
373 entry.slot);
374
Jiwen 'Steve' Caic6fcf2f2018-09-27 23:34:45 -0700375 std::shared_ptr<BufferHubBase> buffer = std::move(entry.buffer);
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700376 *slot = entry.slot;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800377
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700378 available_buffers_.pop();
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700379
380 return {std::move(buffer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800381}
382
Jiwen 'Steve' Cai0b801552017-05-24 11:50:11 -0700383void BufferHubQueue::SetBufferAvailableCallback(
384 BufferAvailableCallback callback) {
385 on_buffer_available_ = callback;
386}
387
388void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) {
389 on_buffer_removed_ = callback;
390}
391
Jiwen 'Steve' Cai005f45d2017-08-04 17:34:37 -0700392pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
393 // Clear all available buffers.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700394 while (!available_buffers_.empty())
395 available_buffers_.pop();
Jiwen 'Steve' Cai005f45d2017-08-04 17:34:37 -0700396
397 pdx::Status<void> last_error; // No error.
398 // Clear all buffers this producer queue is tracking.
399 for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
400 if (buffers_[slot] != nullptr) {
401 auto status = RemoveBuffer(slot);
402 if (!status) {
403 ALOGE(
404 "ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700405 "slot=%zu.",
Jiwen 'Steve' Cai005f45d2017-08-04 17:34:37 -0700406 slot);
407 last_error = status.error_status();
408 }
409 }
410 }
411
412 return last_error;
413}
414
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700415ProducerQueue::ProducerQueue(LocalChannelHandle handle)
416 : BASE(std::move(handle)) {
417 auto status = ImportQueue();
418 if (!status) {
419 ALOGE("ProducerQueue::ProducerQueue: Failed to import queue: %s",
420 status.GetErrorMessage().c_str());
421 Close(-status.error());
422 }
423}
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800424
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -0700425ProducerQueue::ProducerQueue(const ProducerQueueConfig& config,
426 const UsagePolicy& usage)
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700427 : BASE(BufferHubRPC::kClientPath) {
Jiwen 'Steve' Caicbd32bf2017-05-18 17:03:20 -0700428 auto status =
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -0700429 InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(config, usage);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800430 if (!status) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800431 ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
432 status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800433 Close(-status.error());
434 return;
435 }
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700436
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -0700437 SetupQueue(status.get());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800438}
439
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700440Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
441 uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
442 uint64_t usage, size_t buffer_count) {
Tianyua6e33a12018-09-20 15:57:17 -0700443 if (buffer_count == 0) {
444 return {std::vector<size_t>()};
445 }
446
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700447 if (capacity() + buffer_count > kMaxQueueCapacity) {
448 ALOGE(
449 "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
450 "allocate %zu more buffer(s).",
451 capacity(), buffer_count);
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700452 return ErrorStatus(E2BIG);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800453 }
454
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800455 Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
456 InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700457 width, height, layer_count, format, usage, buffer_count);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800458 if (!status) {
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700459 ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700460 status.GetErrorMessage().c_str());
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700461 return status.error_status();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800462 }
463
464 auto buffer_handle_slots = status.take();
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700465 LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800466 "BufferHubRPC::ProducerQueueAllocateBuffers should "
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700467 "return %zu buffer handle(s), but returned %zu instead.",
468 buffer_count, buffer_handle_slots.size());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800469
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700470 std::vector<size_t> buffer_slots;
471 buffer_slots.reserve(buffer_count);
472
473 // Bookkeeping for each buffer.
474 for (auto& hs : buffer_handle_slots) {
475 auto& buffer_handle = hs.first;
476 size_t buffer_slot = hs.second;
477
478 // Note that import might (though very unlikely) fail. If so, buffer_handle
479 // will be closed and included in returned buffer_slots.
480 if (AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
481 buffer_slot)) {
482 ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
483 buffer_slot);
484 buffer_slots.push_back(buffer_slot);
485 }
486 }
487
Tianyua6e33a12018-09-20 15:57:17 -0700488 if (buffer_slots.size() != buffer_count) {
489 // Error out if the count of imported buffer(s) is not correct.
490 ALOGE(
491 "ProducerQueue::AllocateBuffers: requested to import %zu "
492 "buffers, but actually imported %zu buffers.",
493 buffer_count, buffer_slots.size());
494 return ErrorStatus(ENOMEM);
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700495 }
496
497 return {std::move(buffer_slots)};
498}
499
500Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
501 uint32_t layer_count,
502 uint32_t format, uint64_t usage) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800503 // We only allocate one buffer at a time.
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700504 constexpr size_t buffer_count = 1;
505 auto status =
506 AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
507 if (!status) {
508 ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
509 status.GetErrorMessage().c_str());
510 return status.error_status();
511 }
Tianyu Jiangd8c000d2018-09-14 23:40:23 +0000512
Jiwen 'Steve' Cai8fa4e102017-05-24 23:16:54 -0700513 return {status.get()[0]};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800514}
515
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700516Status<void> ProducerQueue::AddBuffer(
517 const std::shared_ptr<BufferProducer>& buffer, size_t slot) {
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700518 ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700519 id(), buffer->id(), slot);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800520 // For producer buffer, we need to enqueue the newly added buffer
521 // immediately. Producer queue starts with all buffers in available state.
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700522 auto status = BufferHubQueue::AddBuffer(buffer, slot);
523 if (!status)
524 return status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800525
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700526 return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800527}
528
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700529Status<size_t> ProducerQueue::InsertBuffer(
530 const std::shared_ptr<BufferProducer>& buffer) {
531 if (buffer == nullptr ||
532 !BufferHubDefs::IsBufferGained(buffer->buffer_state())) {
533 ALOGE(
534 "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in "
535 "gained state.");
536 return ErrorStatus(EINVAL);
537 }
538
539 auto status_or_slot =
540 InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
541 buffer->cid());
542 if (!status_or_slot) {
543 ALOGE(
544 "ProducerQueue::InsertBuffer: Failed to insert producer buffer: "
545 "buffer_cid=%d, error: %s.",
546 buffer->cid(), status_or_slot.GetErrorMessage().c_str());
547 return status_or_slot.error_status();
548 }
549
550 size_t slot = status_or_slot.get();
551
552 // Note that we are calling AddBuffer() from the base class to explicitly
553 // avoid Enqueue() the BufferProducer.
554 auto status = BufferHubQueue::AddBuffer(buffer, slot);
555 if (!status) {
556 ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.",
557 status.GetErrorMessage().c_str());
558 return status.error_status();
559 }
560 return {slot};
561}
562
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700563Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700564 auto status =
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700565 InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800566 if (!status) {
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700567 ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700568 status.GetErrorMessage().c_str());
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700569 return status.error_status();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800570 }
571
Jiwen 'Steve' Caibb701db2017-05-23 11:15:33 -0700572 return BufferHubQueue::RemoveBuffer(slot);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800573}
574
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700575Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700576 int timeout, size_t* slot, LocalHandle* release_fence) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700577 DvrNativeBufferMetadata canonical_meta;
578 return Dequeue(timeout, slot, &canonical_meta, release_fence);
579}
580
581pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
582 int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
583 pdx::LocalHandle* release_fence) {
584 ATRACE_NAME("ProducerQueue::Dequeue");
585 if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
586 ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700587 return ErrorStatus(EINVAL);
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700588 }
589
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700590 auto status = BufferHubQueue::Dequeue(timeout, slot);
591 if (!status)
592 return status.error_status();
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700593
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700594 auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
595 const int ret = buffer->GainAsync(out_meta, release_fence);
596 if (ret < 0 && ret != -EALREADY)
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700597 return ErrorStatus(-ret);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700598
599 return {std::move(buffer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800600}
601
Jiwen 'Steve' Caia88e3ee2017-11-03 17:33:33 -0700602pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
603 if (capacity() != 0) {
604 ALOGE(
605 "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
606 " as a parcelable when empty. Current queue capacity: %zu",
607 capacity());
608 return ErrorStatus(EINVAL);
609 }
610
611 std::unique_ptr<pdx::ClientChannel> channel = TakeChannel();
612 ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable());
613
614 // Here the queue parcelable is returned and holds the underlying system
615 // resources backing the queue; while the original client channel of this
616 // producer queue is destroyed in place so that this client can no longer
617 // provide producer operations.
618 return {std::move(queue_parcelable)};
619}
620
Jiwen 'Steve' Caia2a27b22018-02-07 17:29:56 -0800621/*static */
622std::unique_ptr<ConsumerQueue> ConsumerQueue::Import(
623 LocalChannelHandle handle) {
624 return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle)));
625}
626
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700627ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
628 : BufferHubQueue(std::move(handle)) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700629 auto status = ImportQueue();
630 if (!status) {
631 ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
632 status.GetErrorMessage().c_str());
633 Close(-status.error());
634 }
635
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700636 auto import_status = ImportBuffers();
637 if (import_status) {
638 ALOGI("ConsumerQueue::ConsumerQueue: Imported %zu buffers.",
639 import_status.get());
640 } else {
641 ALOGE("ConsumerQueue::ConsumerQueue: Failed to import buffers: %s",
642 import_status.GetErrorMessage().c_str());
643 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800644}
645
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700646Status<size_t> ConsumerQueue::ImportBuffers() {
647 auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800648 if (!status) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700649 if (status.error() == EBADR) {
650 ALOGI(
651 "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
652 "imported.");
653 return {0};
654 } else {
655 ALOGE(
656 "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700657 status.GetErrorMessage().c_str());
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700658 return status.error_status();
659 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800660 }
661
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700662 int ret;
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700663 Status<void> last_error;
664 size_t imported_buffers_count = 0;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800665
666 auto buffer_handle_slots = status.take();
667 for (auto& buffer_handle_slot : buffer_handle_slots) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700668 ALOGD_IF(TRACE, "ConsumerQueue::ImportBuffers: buffer_handle=%d",
Jiwen 'Steve' Cai25fd3fa2017-03-20 15:30:21 -0700669 buffer_handle_slot.first.value());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800670
671 std::unique_ptr<BufferConsumer> buffer_consumer =
672 BufferConsumer::Import(std::move(buffer_handle_slot.first));
Corey Tabakacf023722017-07-28 19:46:30 -0700673 if (!buffer_consumer) {
674 ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
675 buffer_handle_slot.second);
676 last_error = ErrorStatus(EPIPE);
677 continue;
678 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700679
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700680 auto add_status =
681 AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
682 if (!add_status) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700683 ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700684 add_status.GetErrorMessage().c_str());
685 last_error = add_status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800686 } else {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700687 imported_buffers_count++;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800688 }
689 }
690
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700691 if (imported_buffers_count > 0)
692 return {imported_buffers_count};
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700693 else
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700694 return last_error.error_status();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800695}
696
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700697Status<void> ConsumerQueue::AddBuffer(
698 const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
Corey Tabaka2b99ee52017-05-04 10:56:05 -0700699 ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700700 id(), buffer->id(), slot);
Jiwen 'Steve' Cai394de7e2017-12-07 19:24:02 -0800701 return BufferHubQueue::AddBuffer(buffer, slot);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800702}
703
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700704Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700705 int timeout, size_t* slot, void* meta, size_t user_metadata_size,
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700706 LocalHandle* acquire_fence) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700707 if (user_metadata_size != user_metadata_size_) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800708 ALOGE(
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700709 "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
710 "does not match metadata size (%zu) for the queue.",
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700711 user_metadata_size, user_metadata_size_);
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700712 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800713 }
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700714
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700715 DvrNativeBufferMetadata canonical_meta;
716 auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence);
717 if (!status)
718 return status.error_status();
719
720 if (meta && user_metadata_size) {
721 void* metadata_src =
722 reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
723 if (metadata_src) {
724 memcpy(meta, metadata_src, user_metadata_size);
725 } else {
726 ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
727 }
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700728 }
729
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700730 return status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800731}
732
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700733Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
734 int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
735 pdx::LocalHandle* acquire_fence) {
736 ATRACE_NAME("ConsumerQueue::Dequeue");
737 if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
738 ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
739 return ErrorStatus(EINVAL);
740 }
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700741
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700742 auto status = BufferHubQueue::Dequeue(timeout, slot);
743 if (!status)
744 return status.error_status();
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700745
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700746 auto buffer = std::static_pointer_cast<BufferConsumer>(status.take());
747 const int ret = buffer->AcquireAsync(out_meta, acquire_fence);
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700748 if (ret < 0)
749 return ErrorStatus(-ret);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700750
751 return {std::move(buffer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800752}
753
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700754Status<void> ConsumerQueue::OnBufferAllocated() {
Corey Tabakab7ca5de2017-05-08 18:55:02 -0700755 ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
756
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700757 auto status = ImportBuffers();
758 if (!status) {
759 ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
760 status.GetErrorMessage().c_str());
761 return ErrorStatus(status.error());
762 } else if (status.get() == 0) {
763 ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
764 return ErrorStatus(ENOBUFS);
765 } else {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700766 ALOGD_IF(TRACE,
767 "ConsumerQueue::OnBufferAllocated: Imported %zu consumer buffers.",
768 status.get());
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700769 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800770 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800771}
772
773} // namespace dvr
774} // namespace android