1#include "include/dvr/dvr_api.h"
2#include "include/dvr/dvr_buffer_queue.h"
3
4#include <android/native_window.h>
5#include <gui/Surface.h>
6#include <private/dvr/buffer_hub_queue_client.h>
7#include <private/dvr/buffer_hub_queue_producer.h>
8
9#include "dvr_internal.h"
10
11#define CHECK_PARAM(param)                                               \
12  LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
13                      __FUNCTION__)
14
15using namespace android;
16
17namespace android {
18namespace dvr {
19
20DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
21    const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
22  return new DvrWriteBufferQueue{std::move(producer_queue)};
23}
24
25DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
26    const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
27  return new DvrReadBufferQueue{std::move(consumer_queue)};
28}
29
30dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
31    DvrWriteBufferQueue* write_queue) {
32  return write_queue->producer_queue.get();
33}
34
35}  // namespace dvr
36}  // namespace android
37
38extern "C" {
39
40void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
41  if (write_queue != nullptr && write_queue->native_window != nullptr)
42    ANativeWindow_release(write_queue->native_window);
43
44  delete write_queue;
45}
46
47ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
48  if (!write_queue || !write_queue->producer_queue)
49    return -EINVAL;
50
51  return write_queue->producer_queue->capacity();
52}
53
54int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
55  if (!write_queue)
56    return -EINVAL;
57
58  return write_queue->producer_queue->id();
59}
60
61int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
62                                          ANativeWindow** out_window) {
63  if (!write_queue || !out_window)
64    return -EINVAL;
65
66  if (write_queue->producer_queue->metadata_size() !=
67      sizeof(DvrNativeBufferMetadata)) {
68    ALOGE(
69        "The size of buffer metadata (%zu) of the write queue does not match "
70        "of size of DvrNativeBufferMetadata (%zu).",
71        write_queue->producer_queue->metadata_size(),
72        sizeof(DvrNativeBufferMetadata));
73    return -EINVAL;
74  }
75
76  // Lazy creation of |native_window|.
77  if (write_queue->native_window == nullptr) {
78    sp<IGraphicBufferProducer> gbp =
79        dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
80    sp<Surface> surface = new Surface(gbp, true);
81    write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
82    ANativeWindow_acquire(write_queue->native_window);
83  }
84
85  *out_window = write_queue->native_window;
86  return 0;
87}
88
89int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
90                                       DvrReadBufferQueue** out_read_queue) {
91  if (!write_queue || !write_queue->producer_queue || !out_read_queue)
92    return -EINVAL;
93
94  auto read_queue = std::make_unique<DvrReadBufferQueue>();
95  read_queue->consumer_queue =
96      write_queue->producer_queue->CreateConsumerQueue();
97  if (read_queue->consumer_queue == nullptr) {
98    ALOGE(
99        "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
100        "from DvrWriteBufferQueue[%p].",
101        write_queue);
102    return -ENOMEM;
103  }
104
105  *out_read_queue = read_queue.release();
106  return 0;
107}
108
109int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
110                               DvrWriteBuffer* write_buffer,
111                               int* out_fence_fd) {
112  if (!write_queue || !write_queue->producer_queue || !write_buffer ||
113      !out_fence_fd) {
114    return -EINVAL;
115  }
116
117  size_t slot;
118  pdx::LocalHandle release_fence;
119  auto buffer_status =
120      write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
121  if (!buffer_status) {
122    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
123             "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
124             buffer_status.GetErrorMessage().c_str());
125    return -buffer_status.error();
126  }
127
128  write_buffer->write_buffer = buffer_status.take();
129  *out_fence_fd = release_fence.Release();
130  return 0;
131}
132
133// ReadBufferQueue
134void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
135  delete read_queue;
136}
137
138ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
139  if (!read_queue)
140    return -EINVAL;
141
142  return read_queue->consumer_queue->capacity();
143}
144
145int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
146  if (!read_queue)
147    return -EINVAL;
148
149  return read_queue->consumer_queue->id();
150}
151
152int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
153                                      DvrReadBufferQueue** out_read_queue) {
154  if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
155    return -EINVAL;
156
157  auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
158  new_read_queue->consumer_queue =
159      read_queue->consumer_queue->CreateConsumerQueue();
160  if (new_read_queue->consumer_queue == nullptr) {
161    ALOGE(
162        "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
163        "from DvrReadBufferQueue[%p].",
164        read_queue);
165    return -ENOMEM;
166  }
167
168  *out_read_queue = new_read_queue.release();
169  return 0;
170}
171
172int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
173                              DvrReadBuffer* read_buffer, int* out_fence_fd,
174                              void* out_meta, size_t meta_size_bytes) {
175  if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
176      !out_fence_fd || !out_meta) {
177    return -EINVAL;
178  }
179
180  if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
181    ALOGE(
182        "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
183        "but actual (%zu).",
184        read_queue->consumer_queue->metadata_size(), meta_size_bytes);
185    return -EINVAL;
186  }
187
188  size_t slot;
189  pdx::LocalHandle acquire_fence;
190  auto buffer_status = read_queue->consumer_queue->Dequeue(
191      timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
192  if (!buffer_status) {
193    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
194             "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s",
195             buffer_status.GetErrorMessage().c_str());
196    return -buffer_status.error();
197  }
198
199  read_buffer->read_buffer = buffer_status.take();
200  *out_fence_fd = acquire_fence.Release();
201  return 0;
202}
203
204}  // extern "C"
205