1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "SharedMemoryWrapper"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <iomanip>
22 #include <iostream>
23 #include <sys/mman.h>
24
25 #include "SharedMemoryWrapper.h"
26
27 namespace aaudio {
28
29 constexpr int COUNTER_SIZE_IN_BYTES = sizeof(android::fifo_counter_t);
30 constexpr int WRAPPER_SIZE_IN_BYTES = 2 * COUNTER_SIZE_IN_BYTES;
31
SharedMemoryWrapper()32 SharedMemoryWrapper::SharedMemoryWrapper() {
33 mCounterFd.reset(ashmem_create_region("AAudioSharedMemoryWrapper", WRAPPER_SIZE_IN_BYTES));
34 if (mCounterFd.get() == -1) {
35 ALOGE("allocate() ashmem_create_region() failed %d", errno);
36 return;
37 }
38 int err = ashmem_set_prot_region(mCounterFd.get(), PROT_READ|PROT_WRITE);
39 if (err < 0) {
40 ALOGE("allocate() ashmem_set_prot_region() failed %d", errno);
41 mCounterFd.reset();
42 return;
43 }
44 auto tmpPtr = (uint8_t *) mmap(nullptr, WRAPPER_SIZE_IN_BYTES,
45 PROT_READ|PROT_WRITE,
46 MAP_SHARED,
47 mCounterFd.get(), 0);
48 if (tmpPtr == MAP_FAILED) {
49 ALOGE("allocate() mmap() failed %d", errno);
50 mCounterFd.reset();
51 return;
52 }
53 mCounterMemoryAddress = tmpPtr;
54
55 mReadCounterAddress = (android::fifo_counter_t*) mCounterMemoryAddress;
56 mWriteCounterAddress = (android::fifo_counter_t*) &mCounterMemoryAddress[COUNTER_SIZE_IN_BYTES];
57 }
58
~SharedMemoryWrapper()59 SharedMemoryWrapper::~SharedMemoryWrapper()
60 {
61 reset();
62 if (mCounterMemoryAddress != nullptr) {
63 munmap(mCounterMemoryAddress, COUNTER_SIZE_IN_BYTES);
64 mCounterMemoryAddress = nullptr;
65 }
66 }
67
setupFifoBuffer(android::fifo_frames_t bytesPerFrame,android::fifo_frames_t capacityInFrames)68 aaudio_result_t SharedMemoryWrapper::setupFifoBuffer(android::fifo_frames_t bytesPerFrame,
69 android::fifo_frames_t capacityInFrames) {
70 if (mDataFd.get() == -1) {
71 ALOGE("%s data file descriptor is not initialized", __func__);
72 return AAUDIO_ERROR_INTERNAL;
73 }
74 if (mCounterMemoryAddress == nullptr) {
75 ALOGE("%s the counter memory is not allocated correctly", __func__);
76 return AAUDIO_ERROR_INTERNAL;
77 }
78 mSharedMemorySizeInBytes = bytesPerFrame * capacityInFrames;
79 auto tmpPtr = (uint8_t *) mmap(nullptr, mSharedMemorySizeInBytes,
80 PROT_READ|PROT_WRITE,
81 MAP_SHARED,
82 mDataFd.get(), 0);
83 if (tmpPtr == MAP_FAILED) {
84 ALOGE("allocate() mmap() failed %d", errno);
85 return AAUDIO_ERROR_INTERNAL;
86 }
87 mSharedMemory = tmpPtr;
88
89 mFifoBuffer = std::make_shared<android::FifoBufferIndirect>(
90 bytesPerFrame, capacityInFrames, mReadCounterAddress,
91 mWriteCounterAddress, mSharedMemory);
92 return AAUDIO_OK;
93 }
94
reset()95 void SharedMemoryWrapper::reset() {
96 mFifoBuffer.reset();
97 if (mSharedMemory != nullptr) {
98 munmap(mSharedMemory, mSharedMemorySizeInBytes);
99 mSharedMemory = nullptr;
100 }
101 mDataFd.reset();
102 }
103
fillParcelable(AudioEndpointParcelable * endpointParcelable,RingBufferParcelable & ringBufferParcelable,int32_t bytesPerFrame,int32_t framesPerBurst,int32_t capacityInFrames,CounterFilling counterFilling)104 void SharedMemoryWrapper::fillParcelable(
105 AudioEndpointParcelable* endpointParcelable, RingBufferParcelable &ringBufferParcelable,
106 int32_t bytesPerFrame, int32_t framesPerBurst, int32_t capacityInFrames,
107 CounterFilling counterFilling) {
108 const int capacityInBytes = bytesPerFrame * capacityInFrames;
109 const int dataFdIndex =
110 endpointParcelable->addFileDescriptor(mDataFd, mSharedMemorySizeInBytes);
111 ringBufferParcelable.setBytesPerFrame(bytesPerFrame);
112 ringBufferParcelable.setFramesPerBurst(framesPerBurst);
113 ringBufferParcelable.setCapacityInFrames(capacityInFrames);
114 if (mCounterFd.get() == -1 || counterFilling == NONE) {
115 // Failed to create shared memory for read/write counter or requesting no filling counters.
116 ALOGD("%s no counter is filled, counterFd=%d", __func__, mCounterFd.get());
117 ringBufferParcelable.setupMemory(dataFdIndex, 0, capacityInBytes);
118 } else {
119 int counterFdIndex =
120 endpointParcelable->addFileDescriptor(mCounterFd, WRAPPER_SIZE_IN_BYTES);
121 const int readCounterSize = (counterFilling & READ) == NONE ? 0 : COUNTER_SIZE_IN_BYTES;
122 const int writeCounterSize = (counterFilling & WRITE) == NONE ? 0 : COUNTER_SIZE_IN_BYTES;
123 ALOGD("%s counterFdIndex=%d readCounterSize=%d, writeCounterSize=%d",
124 __func__, counterFdIndex, readCounterSize, writeCounterSize);
125 ringBufferParcelable.setupMemory(
126 {dataFdIndex, 0 /*offset*/, capacityInBytes},
127 {counterFdIndex, 0 /*offset*/, readCounterSize},
128 {counterFdIndex, COUNTER_SIZE_IN_BYTES, writeCounterSize});
129 }
130 }
131
132 } // namespace aaudio
133