1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "audio_buffer_cache.h"
17 #include "log.h"
18 #include "monitor_error.h"
19 
20 namespace {
21 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FOUNDATION, "HiStreamer"};
22 }
23 
24 namespace OHOS {
25 namespace Media {
26 namespace MediaMonitor {
27 
AudioBufferCache(std::shared_ptr<DumpBufferWrap> wrap)28 AudioBufferCache::AudioBufferCache(std::shared_ptr<DumpBufferWrap> wrap)
29 {
30     dumpBufferWrap_ = wrap;
31 }
32 
~AudioBufferCache()33 AudioBufferCache::~AudioBufferCache()
34 {
35     Clear();
36     dumpBufferWrap_ = nullptr;
37 }
38 
RequestBuffer(std::shared_ptr<AudioBuffer> & buffer,int32_t size)39 int32_t AudioBufferCache::RequestBuffer(std::shared_ptr<AudioBuffer> &buffer, int32_t size)
40 {
41     std::unique_lock<std::mutex> lock(mutex_);
42     auto status = RequestCacheBuffer(buffer, size);
43     if (status == SUCCESS && buffer != nullptr) {
44         return SUCCESS;
45     }
46     status = AllocAudioBuffer(buffer, size);
47     if (status != SUCCESS) {
48         return status;
49     }
50     bufferSize_ += 1;
51     return SUCCESS;
52 }
53 
ReleaseBuffer(std::shared_ptr<AudioBuffer> & buffer)54 int32_t AudioBufferCache::ReleaseBuffer(std::shared_ptr<AudioBuffer> &buffer)
55 {
56     if (buffer == nullptr || dumpBufferWrap_ == nullptr) {
57         MEDIA_LOG_E("release buffer error");
58         return ERROR;
59     }
60     std::unique_lock<std::mutex> lock(mutex_);
61     auto bufferId = dumpBufferWrap_->GetUniqueId(buffer.get());
62     for (auto it = freeBufferList_.begin(); it != freeBufferList_.end(); it++) {
63         if (*it == bufferId) {
64             return SUCCESS;
65         }
66     }
67     if (bufferMap_.find(bufferId) == bufferMap_.end()) {
68         buffer = nullptr;
69         return ERROR;
70     }
71 
72     freeBufferList_.emplace_back(bufferId);
73     return SUCCESS;
74 }
75 
Clear()76 int32_t AudioBufferCache::Clear()
77 {
78     std::unique_lock<std::mutex> lock(mutex_);
79     if (freeBufferList_.size() != bufferMap_.size()) {
80         MEDIA_LOG_E("exist buffer not free");
81     }
82 
83     for (auto it = freeBufferList_.begin(); it != freeBufferList_.end(); it++) {
84         bufferMap_[*it].buffer = nullptr;
85     }
86     freeBufferList_.clear();
87     bufferMap_.clear();
88     bufferSize_ = 0;
89     return SUCCESS;
90 }
91 
GetBufferById(std::shared_ptr<AudioBuffer> & buffer,uint64_t bufferId)92 int32_t AudioBufferCache::GetBufferById(std::shared_ptr<AudioBuffer> &buffer, uint64_t bufferId)
93 {
94     std::unique_lock<std::mutex> lock(mutex_);
95     auto it = bufferMap_.find(bufferId);
96     if (it != bufferMap_.end()) {
97         buffer = bufferMap_[bufferId].buffer;
98         return SUCCESS;
99     }
100     return ERROR;
101 }
102 
SetBufferSize(std::shared_ptr<AudioBuffer> & buffer,int32_t size)103 int32_t AudioBufferCache::SetBufferSize(std::shared_ptr<AudioBuffer> &buffer, int32_t size)
104 {
105     if (dumpBufferWrap_ && dumpBufferWrap_->SetSize(buffer.get(), size)) {
106         return SUCCESS;
107     }
108     return ERROR;
109 }
110 
RequestCacheBuffer(std::shared_ptr<AudioBuffer> & buffer,int32_t size)111 int32_t AudioBufferCache::RequestCacheBuffer(std::shared_ptr<AudioBuffer> &buffer, int32_t size)
112 {
113     for (auto it = freeBufferList_.begin(); it != freeBufferList_.end(); it++) {
114         if (size <= bufferMap_[*it].size) {
115             buffer = bufferMap_[*it].buffer;
116             freeBufferList_.erase(it);
117             return SUCCESS;
118         }
119     }
120     if (freeBufferList_.empty()) {
121         buffer = nullptr;
122         return ERROR;
123     }
124     int32_t status = DeleteAudioBuffer(freeBufferList_.front(), size);
125     freeBufferList_.pop_front();
126     if (status != SUCCESS) {
127         return status;
128     }
129     status = AllocAudioBuffer(buffer, size);
130     return status;
131 }
132 
AllocBuffer(std::shared_ptr<AudioBuffer> & buffer,int32_t size)133 int32_t AudioBufferCache::AllocBuffer(std::shared_ptr<AudioBuffer> &buffer, int32_t size)
134 {
135     AudioBuffer *ptr = dumpBufferWrap_->CreateDumpBuffer(size);
136     buffer = std::shared_ptr<AudioBuffer>(ptr, [this](AudioBuffer* ptr) {
137          dumpBufferWrap_->DestroyDumpBuffer(ptr);
138     });
139     if (buffer == nullptr) {
140         return ERROR;
141     }
142     return SUCCESS;
143 }
144 
AllocAudioBuffer(std::shared_ptr<AudioBuffer> & buffer,int32_t size)145 int32_t AudioBufferCache::AllocAudioBuffer(std::shared_ptr<AudioBuffer> &buffer, int32_t size)
146 {
147     int32_t status = AllocBuffer(buffer, size);
148     if (status != SUCCESS || buffer == nullptr) {
149         MEDIA_LOG_E("alloc buffer error");
150         return ERROR;
151     }
152     AudioBufferElement ele = {
153         .size = size,
154         .buffer = buffer
155     };
156     auto bufferId = dumpBufferWrap_->GetUniqueId(buffer.get());
157     bufferMap_[bufferId] = ele;
158     return SUCCESS;
159 }
160 
DeleteAudioBuffer(uint64_t bufferId,int32_t size)161 int32_t AudioBufferCache::DeleteAudioBuffer(uint64_t bufferId, int32_t size)
162 {
163     auto it = bufferMap_.find(bufferId);
164     if (it != bufferMap_.end()) {
165         bufferMap_.erase(it);
166         return SUCCESS;
167     }
168     return ERROR;
169 }
170 
171 } // namespace MediaMonitor
172 } // namespace Media
173 } // namespace OHOS