1 
2 /*
3  * Copyright (C) 2023 Huawei Device Co., Ltd.
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 #include "cache_buffer.h"
18 #include "media_log.h"
19 #include "media_errors.h"
20 #include "securec.h"
21 
22 namespace {
23     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SOUNDPOOL, "CacheBuffer"};
24 }
25 
26 namespace OHOS {
27 namespace Media {
CacheBuffer(const Format &trackFormat, const std::deque<std::shared_ptr<AudioBufferEntry>> &cacheData, const size_t &cacheDataTotalSize, const int32_t &soundID, const int32_t &streamID)28 CacheBuffer::CacheBuffer(const Format &trackFormat,
29     const std::deque<std::shared_ptr<AudioBufferEntry>> &cacheData,
30     const size_t &cacheDataTotalSize, const int32_t &soundID, const int32_t &streamID) : trackFormat_(trackFormat),
31     cacheData_(cacheData), cacheDataTotalSize_(cacheDataTotalSize), soundID_(soundID), streamID_(streamID),
32     cacheDataFrameIndex_(0), havePlayedCount_(0)
33 
34 {
35     MEDIA_LOGI("Construction CacheBuffer soundID:%{public}d, streamID:%{public}d", soundID, streamID);
36 }
37 
~CacheBuffer()38 CacheBuffer::~CacheBuffer()
39 {
40     MEDIA_LOGI("Destruction CacheBuffer soundID:%{public}d, streamID:%{public}d", soundID_, streamID_);
41     Release();
42 }
43 
IsAudioRendererCanMix(const AudioStandard::AudioRendererInfo &audioRendererInfo)44 bool CacheBuffer::IsAudioRendererCanMix(const AudioStandard::AudioRendererInfo &audioRendererInfo)
45 {
46     AudioStandard::AudioStreamType streamType = AudioStandard::AudioSystemManager::GetStreamType(
47         audioRendererInfo.contentType, audioRendererInfo.streamUsage);
48     if (streamType == AudioStandard::AudioStreamType::STREAM_MUSIC ||
49         streamType == AudioStandard::AudioStreamType::STREAM_MOVIE ||
50         streamType == AudioStandard::AudioStreamType::STREAM_SPEECH) {
51             return true;
52         }
53     return false;
54 }
55 
CreateAudioRenderer(const int32_t streamID, const AudioStandard::AudioRendererInfo audioRendererInfo, const PlayParams playParams)56 std::unique_ptr<AudioStandard::AudioRenderer> CacheBuffer::CreateAudioRenderer(const int32_t streamID,
57     const AudioStandard::AudioRendererInfo audioRendererInfo, const PlayParams playParams)
58 {
59     MediaTrace trace("CacheBuffer::CreateAudioRenderer");
60     CHECK_AND_RETURN_RET_LOG(streamID == streamID_, nullptr,
61         "Invalid streamID, failed to create normal audioRenderer.");
62     int32_t sampleRate;
63     int32_t sampleFormat;
64     int32_t channelCount;
65     AudioStandard::AudioRendererOptions rendererOptions = {};
66     // Set to PCM encoding
67     rendererOptions.streamInfo.encoding = AudioStandard::AudioEncodingType::ENCODING_PCM;
68     // Get sample rate from trackFormat and set it to audiorender.
69     trackFormat_.GetIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sampleRate);
70     rendererOptions.streamInfo.samplingRate = static_cast<AudioStandard::AudioSamplingRate>(sampleRate);
71     // Get sample format from trackFormat and set it to audiorender.
72     trackFormat_.GetIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT, sampleFormat);
73     // Align audiorender capability
74     rendererOptions.streamInfo.format = static_cast<AudioStandard::AudioSampleFormat>(sampleFormat);
75     // Get channel count from trackFormat and set it to audiorender.
76     trackFormat_.GetIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channelCount);
77     rendererOptions.streamInfo.channels = static_cast<AudioStandard::AudioChannel>(channelCount);
78     // contentType streamUsage rendererFlags come from user.
79     if (IsAudioRendererCanMix(audioRendererInfo)) {
80         rendererOptions.strategy.concurrencyMode = AudioStandard::AudioConcurrencyMode::MIX_WITH_OTHERS;
81     }
82     rendererOptions.rendererInfo.contentType = audioRendererInfo.contentType;
83     rendererOptions.rendererInfo.streamUsage = audioRendererInfo.streamUsage;
84     rendererOptions.privacyType = AudioStandard::PRIVACY_TYPE_PUBLIC;
85     std::string cacheDir = "/data/storage/el2/base/temp";
86     if (playParams.cacheDir != "") {
87         cacheDir = playParams.cacheDir;
88     }
89 
90     rendererFlags_ = audioRendererInfo.rendererFlags;
91     rendererOptions.rendererInfo.rendererFlags = rendererFlags_;
92     std::unique_ptr<AudioStandard::AudioRenderer> audioRenderer =
93         AudioStandard::AudioRenderer::Create(cacheDir, rendererOptions);
94 
95     if (audioRenderer == nullptr) {
96         MEDIA_LOGE("create audiorenderer failed, try again.");
97         rendererFlags_ = NORMAL_PLAY_RENDERER_FLAGS;
98         rendererOptions.rendererInfo.rendererFlags = rendererFlags_;
99         audioRenderer = AudioStandard::AudioRenderer::Create(cacheDir, rendererOptions);
100     }
101 
102     CHECK_AND_RETURN_RET_LOG(audioRenderer != nullptr, nullptr, "Invalid audioRenderer.");
103     size_t targetSize = 0;
104     int32_t ret = audioRenderer->GetBufferSize(targetSize);
105     audioRenderer->SetRenderMode(AudioStandard::AudioRenderMode::RENDER_MODE_CALLBACK);
106     if (ret == 0 && targetSize != 0 && !audioRenderer->IsFastRenderer()) {
107         size_t bufferDuration = 20; // 20 -> 20ms
108         audioRenderer->SetBufferDuration(bufferDuration);
109         MEDIA_LOGI("Using buffer size:%{public}zu, duration %{public}zu", targetSize, bufferDuration);
110     }
111     int32_t retCallback = audioRenderer->SetRendererWriteCallback(shared_from_this());
112     int32_t retFirstCallback = audioRenderer->SetRendererFirstFrameWritingCallback(shared_from_this());
113     MEDIA_LOGI("CacheBuffer::CreateAudioRenderer retCallback:%{public}d, retFirstCallback:%{public}d",
114         retCallback, retFirstCallback);
115     return audioRenderer;
116 }
117 
PreparePlay(const int32_t streamID, const AudioStandard::AudioRendererInfo audioRendererInfo, const PlayParams playParams)118 int32_t CacheBuffer::PreparePlay(const int32_t streamID, const AudioStandard::AudioRendererInfo audioRendererInfo,
119     const PlayParams playParams)
120 {
121     // create audioRenderer
122     if (audioRenderer_ == nullptr) {
123         MEDIA_LOGI("CacheBuffer::PreparePlay CreateAudioRenderer start streamID:%{public}d", streamID);
124         audioRenderer_ = CreateAudioRenderer(streamID, audioRendererInfo, playParams);
125         MEDIA_LOGI("CacheBuffer::PreparePlay CreateAudioRenderer end streamID:%{public}d", streamID);
126         ReCombineCacheData();
127     } else {
128         MEDIA_LOGI("CacheBuffer::PreparePlay audioRenderer inited, streamID:%{public}d", streamID);
129     }
130     // deal play params
131     DealPlayParamsBeforePlay(streamID, playParams);
132     return MSERR_OK;
133 }
134 
DoPlay(const int32_t streamID)135 int32_t CacheBuffer::DoPlay(const int32_t streamID)
136 {
137     MediaTrace trace("CacheBuffer::DoPlay");
138     CHECK_AND_RETURN_RET_LOG(streamID == streamID_, MSERR_INVALID_VAL, "Invalid streamID, failed to DoPlay.");
139     std::lock_guard lock(cacheBufferLock_);
140     CHECK_AND_RETURN_RET_LOG(fullCacheData_ != nullptr, MSERR_INVALID_VAL, "fullCacheData_ is nullptr.");
141     CHECK_AND_RETURN_RET_LOG(audioRenderer_ != nullptr, MSERR_INVALID_VAL, "Invalid audioRenderer.");
142     cacheDataFrameIndex_ = 0;
143     havePlayedCount_ = 0;
144     isRunning_.store(true);
145     if (!audioRenderer_->Start()) {
146         OHOS::AudioStandard::RendererState state = audioRenderer_->GetStatus();
147         if (state == OHOS::AudioStandard::RendererState::RENDERER_RUNNING) {
148             MEDIA_LOGI("CacheBuffer::DoPlay audioRenderer has started, streamID:%{public}d", streamID);
149             isRunning_.store(true);
150             if (callback_ != nullptr) {
151                 MEDIA_LOGI("CacheBuffer::DoPlay callback_ OnPlayFinished, streamID:%{public}d", streamID);
152                 callback_->OnPlayFinished();
153             }
154             return MSERR_OK;
155         } else {
156             MEDIA_LOGE("CacheBuffer::DoPlay audioRenderer start failed, streamID:%{public}d", streamID);
157             isRunning_.store(false);
158             if (callback_ != nullptr) {
159                 MEDIA_LOGI("CacheBuffer::DoPlay failed, call callback, streamID:%{public}d", streamID);
160                 callback_->OnError(MSERR_INVALID_VAL);
161             }
162             if (cacheBufferCallback_ != nullptr) cacheBufferCallback_->OnError(MSERR_INVALID_VAL);
163             return MSERR_INVALID_VAL;
164         }
165     }
166     MEDIA_LOGI("CacheBuffer::DoPlay success, streamID:%{public}d", streamID);
167     return MSERR_OK;
168 }
169 
ReCombineCacheData()170 int32_t CacheBuffer::ReCombineCacheData()
171 {
172     std::lock_guard lock(cacheBufferLock_);
173     CHECK_AND_RETURN_RET_LOG(audioRenderer_ != nullptr, MSERR_INVALID_VAL, "Invalid audioRenderer.");
174     CHECK_AND_RETURN_RET_LOG(!cacheData_.empty(), MSERR_INVALID_VAL, "empty cache data.");
175 
176     uint8_t *fullBuffer = new(std::nothrow) uint8_t[cacheDataTotalSize_];
177     CHECK_AND_RETURN_RET_LOG(fullBuffer != nullptr, MSERR_INVALID_VAL, "Invalid fullBuffer");
178     int32_t copyIndex = 0;
179     int32_t remainBufferSize = static_cast<int32_t>(cacheDataTotalSize_);
180     MEDIA_LOGI("ReCombine start copyIndex:%{public}d, remainSize:%{public}d", copyIndex, remainBufferSize);
181     for (std::shared_ptr<AudioBufferEntry> bufferEntry : cacheData_) {
182         if (bufferEntry != nullptr && bufferEntry->size > 0 && bufferEntry->buffer != nullptr) {
183             if (remainBufferSize < bufferEntry->size) {
184                 delete[] fullBuffer;
185                 MEDIA_LOGE("ReCombine not enough remainBufferSize:%{public}d, bufferEntry->size:%{public}d",
186                     remainBufferSize, bufferEntry->size);
187                 return MSERR_INVALID_VAL;
188             }
189             int32_t ret = memcpy_s(fullBuffer + copyIndex, remainBufferSize,
190                 bufferEntry->buffer, bufferEntry->size);
191             if (ret != MSERR_OK) {
192                 delete[] fullBuffer;
193                 MEDIA_LOGE("ReCombine memcpy failed");
194                 return MSERR_INVALID_VAL;
195             }
196             copyIndex += bufferEntry->size;
197             remainBufferSize -= bufferEntry->size;
198         } else {
199             MEDIA_LOGE("ReCombineCacheData, bufferEntry size:%{public}d, buffer:%{public}d",
200                 bufferEntry->size, bufferEntry->buffer != nullptr);
201         }
202     }
203     MEDIA_LOGI("ReCombine finish copyIndex:%{public}d, remainSize:%{public}d", copyIndex, remainBufferSize);
204 
205     fullCacheData_ = std::make_shared<AudioBufferEntry>(fullBuffer, cacheDataTotalSize_);
206 
207     if (!cacheData_.empty()) {
208         cacheData_.clear();
209     }
210 
211     return MSERR_OK;
212 }
213 
DealPlayParamsBeforePlay(const int32_t streamID, const PlayParams playParams)214 int32_t CacheBuffer::DealPlayParamsBeforePlay(const int32_t streamID, const PlayParams playParams)
215 {
216     std::lock_guard lock(cacheBufferLock_);
217     CHECK_AND_RETURN_RET_LOG(audioRenderer_ != nullptr, MSERR_INVALID_VAL, "Invalid audioRenderer.");
218     audioRenderer_->SetOffloadAllowed(false);
219     loop_ = playParams.loop;
220     audioRenderer_->SetRenderRate(CheckAndAlignRendererRate(playParams.rate));
221     audioRenderer_->SetVolume(playParams.leftVolume);
222     priority_ = playParams.priority;
223     audioRenderer_->SetParallelPlayFlag(playParams.parallelPlayFlag);
224     return MSERR_OK;
225 }
226 
CheckAndAlignRendererRate(const int32_t rate)227 AudioStandard::AudioRendererRate CacheBuffer::CheckAndAlignRendererRate(const int32_t rate)
228 {
229     AudioStandard::AudioRendererRate renderRate = AudioStandard::AudioRendererRate::RENDER_RATE_NORMAL;
230     switch (rate) {
231         case AudioStandard::AudioRendererRate::RENDER_RATE_NORMAL:
232             renderRate = AudioStandard::AudioRendererRate::RENDER_RATE_NORMAL;
233             break;
234         case AudioStandard::AudioRendererRate::RENDER_RATE_DOUBLE:
235             renderRate = AudioStandard::AudioRendererRate::RENDER_RATE_DOUBLE;
236             break;
237         case AudioStandard::AudioRendererRate::RENDER_RATE_HALF:
238             renderRate = AudioStandard::AudioRendererRate::RENDER_RATE_HALF;
239             break;
240         default:
241             renderRate = AudioStandard::AudioRendererRate::RENDER_RATE_NORMAL;
242             break;
243     }
244     return renderRate;
245 }
246 
OnWriteData(size_t length)247 void CacheBuffer::OnWriteData(size_t length)
248 {
249     if (audioRenderer_ == nullptr) {
250         MEDIA_LOGE("audioRenderer is nullptr.");
251         return;
252     }
253     if (!isRunning_.load()) {
254         MEDIA_LOGE("audioRenderer is stop.");
255         return;
256     }
257     if (cacheDataFrameIndex_ >= static_cast<size_t>(fullCacheData_->size)) {
258         cacheBufferLock_.lock();
259         if (loop_ >= 0 && havePlayedCount_ >= loop_) {
260             MEDIA_LOGI("CacheBuffer stream write finish, cacheDataFrameIndex_:%{public}zu,"
261                 " havePlayedCount_:%{public}d, loop:%{public}d, streamID_:%{public}d, length: %{public}zu",
262                 cacheDataFrameIndex_, havePlayedCount_, loop_, streamID_, length);
263             cacheBufferLock_.unlock();
264             Stop(streamID_);
265             return;
266         }
267         cacheDataFrameIndex_ = 0;
268         havePlayedCount_++;
269         cacheBufferLock_.unlock();
270     }
271     DealWriteData(length);
272 }
273 
DealWriteData(size_t length)274 void CacheBuffer::DealWriteData(size_t length)
275 {
276     std::lock_guard lock(cacheBufferLock_);
277     CHECK_AND_RETURN_LOG(audioRenderer_ != nullptr, "DealWriteData audioRenderer_ is nullptr");
278     AudioStandard::BufferDesc bufDesc;
279     audioRenderer_->GetBufferDesc(bufDesc);
280     if (bufDesc.buffer != nullptr && fullCacheData_ != nullptr && fullCacheData_->buffer != nullptr) {
281         if (static_cast<size_t>(fullCacheData_->size) - cacheDataFrameIndex_ >= length) {
282             int32_t ret = memcpy_s(bufDesc.buffer, length,
283                 fullCacheData_->buffer + cacheDataFrameIndex_, length);
284             CHECK_AND_RETURN_LOG(ret == MSERR_OK, "memcpy failed total length.");
285             bufDesc.bufLength = length;
286             bufDesc.dataLength = length;
287             cacheDataFrameIndex_ += length;
288         } else {
289             size_t copyLength = static_cast<size_t>(fullCacheData_->size) - cacheDataFrameIndex_;
290             int32_t ret = memset_s(bufDesc.buffer, length, 0, length);
291             CHECK_AND_RETURN_LOG(ret == MSERR_OK, "memset failed.");
292             ret = memcpy_s(bufDesc.buffer, length, fullCacheData_->buffer + cacheDataFrameIndex_,
293                 copyLength);
294             CHECK_AND_RETURN_LOG(ret == MSERR_OK, "memcpy failed not enough length.");
295             bufDesc.bufLength = length;
296             bufDesc.dataLength = length;
297             cacheDataFrameIndex_ += copyLength;
298         }
299         audioRenderer_->Enqueue(bufDesc);
300     } else {
301         MEDIA_LOGE("OnWriteData, cacheDataFrameIndex_: %{public}zu, length: %{public}zu,"
302             " bufDesc.buffer:%{public}d, fullCacheData_:%{public}d, fullCacheData_->buffer:%{public}d,"
303             " streamID_:%{public}d",
304             cacheDataFrameIndex_, length, bufDesc.buffer != nullptr, fullCacheData_ != nullptr,
305             fullCacheData_->buffer != nullptr, streamID_);
306     }
307 }
308 
OnFirstFrameWriting(uint64_t latency)309 void CacheBuffer::OnFirstFrameWriting(uint64_t latency)
310 {
311     MEDIA_LOGI("CacheBuffer::OnFirstFrameWriting, streamID_:%{public}d", streamID_);
312     CHECK_AND_RETURN_LOG(frameWriteCallback_ != nullptr, "frameWriteCallback is null.");
313     frameWriteCallback_->OnFirstAudioFrameWritingCallback(latency);
314 }
315 
Stop(const int32_t streamID)316 int32_t CacheBuffer::Stop(const int32_t streamID)
317 {
318     MediaTrace trace("CacheBuffer::Stop");
319     std::lock_guard lock(cacheBufferLock_);
320     if (streamID == streamID_) {
321         MEDIA_LOGI("CacheBuffer::Stop streamID:%{public}d", streamID_);
322         if (audioRenderer_ != nullptr && isRunning_.load()) {
323             isRunning_.store(false);
324             if (audioRenderer_->IsFastRenderer()) {
325                 MEDIA_LOGI("audioRenderer fast renderer pause.");
326                 audioRenderer_->Pause();
327                 audioRenderer_->Flush();
328             } else {
329                 MEDIA_LOGI("audioRenderer normal stop.");
330                 audioRenderer_->Stop();
331             }
332             cacheDataFrameIndex_ = 0;
333             havePlayedCount_ = 0;
334             if (callback_ != nullptr) {
335                 MEDIA_LOGI("cachebuffer callback_ OnPlayFinished.");
336                 callback_->OnPlayFinished();
337             }
338             if (cacheBufferCallback_ != nullptr) {
339                 MEDIA_LOGI("cachebuffer cacheBufferCallback_ OnPlayFinished.");
340                 cacheBufferCallback_->OnPlayFinished();
341             }
342         }
343         return MSERR_OK;
344     }
345     return MSERR_INVALID_VAL;
346 }
347 
SetVolume(const int32_t streamID, const float leftVolume, const float rightVolume)348 int32_t CacheBuffer::SetVolume(const int32_t streamID, const float leftVolume, const float rightVolume)
349 {
350     std::lock_guard lock(cacheBufferLock_);
351     int32_t ret = MSERR_OK;
352     if (streamID == streamID_) {
353         if (audioRenderer_ != nullptr) {
354             // audio cannot support left & right volume, all use left volume.
355             (void) rightVolume;
356             ret = audioRenderer_->SetVolume(leftVolume);
357         }
358     }
359     return ret;
360 }
361 
SetRate(const int32_t streamID, const AudioStandard::AudioRendererRate renderRate)362 int32_t CacheBuffer::SetRate(const int32_t streamID, const AudioStandard::AudioRendererRate renderRate)
363 {
364     std::lock_guard lock(cacheBufferLock_);
365     int32_t ret = MSERR_INVALID_VAL;
366     if (streamID == streamID_) {
367         if (audioRenderer_ != nullptr) {
368             ret = audioRenderer_->SetRenderRate(CheckAndAlignRendererRate(renderRate));
369         }
370     }
371     return ret;
372 }
373 
SetPriority(const int32_t streamID, const int32_t priority)374 int32_t CacheBuffer::SetPriority(const int32_t streamID, const int32_t priority)
375 {
376     std::lock_guard lock(cacheBufferLock_);
377     if (streamID == streamID_) {
378         priority_ = priority;
379     }
380     return MSERR_OK;
381 }
382 
SetLoop(const int32_t streamID, const int32_t loop)383 int32_t CacheBuffer::SetLoop(const int32_t streamID, const int32_t loop)
384 {
385     std::lock_guard lock(cacheBufferLock_);
386     if (streamID == streamID_) {
387         loop_ = loop;
388         havePlayedCount_ = 0;
389     }
390     return MSERR_OK;
391 }
392 
SetParallelPlayFlag(const int32_t streamID, const bool parallelPlayFlag)393 int32_t CacheBuffer::SetParallelPlayFlag(const int32_t streamID, const bool parallelPlayFlag)
394 {
395     std::lock_guard lock(cacheBufferLock_);
396     if (streamID == streamID_) {
397         MEDIA_LOGI("CacheBuffer parallelPlayFlag:%{public}d.", parallelPlayFlag);
398         if (audioRenderer_ != nullptr) {
399             audioRenderer_->SetParallelPlayFlag(parallelPlayFlag);
400         }
401     }
402     return MSERR_OK;
403 }
404 
Release()405 int32_t CacheBuffer::Release()
406 {
407     MediaTrace trace("CacheBuffer::Release");
408     // Define a temporary variable.Let audioRenderer_ to audioRenderer can protect audioRenderer_ concurrently
409     // modified.So will not cause null pointers.
410     std::unique_ptr<AudioStandard::AudioRenderer> audioRenderer;
411     {
412         std::lock_guard lock(cacheBufferLock_);
413         audioRenderer = std::move(audioRenderer_);
414         audioRenderer_ = nullptr;
415         isRunning_.store(false);
416     }
417 
418     MEDIA_LOGI("CacheBuffer::Release start, streamID:%{public}d", streamID_);
419     // Use audioRenderer to release and don't lock, so it will not cause dead lock. if here locked, audioRenderer
420     // will wait callback thread stop, and the callback thread can't get the lock, it will cause dead lock
421     if (audioRenderer != nullptr) {
422         audioRenderer->Stop();
423         audioRenderer->Release();
424         audioRenderer = nullptr;
425     }
426 
427     std::lock_guard lock(cacheBufferLock_);
428     if (!cacheData_.empty()) cacheData_.clear();
429     if (fullCacheData_ != nullptr) fullCacheData_.reset();
430     if (callback_ != nullptr) callback_.reset();
431     if (cacheBufferCallback_ != nullptr) cacheBufferCallback_.reset();
432     if (frameWriteCallback_ != nullptr) frameWriteCallback_.reset();
433     MEDIA_LOGI("CacheBuffer::Release end, streamID:%{public}d", streamID_);
434     return MSERR_OK;
435 }
436 
SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)437 int32_t CacheBuffer::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
438 {
439     callback_ = callback;
440     return MSERR_OK;
441 }
442 
SetCacheBufferCallback(const std::shared_ptr<ISoundPoolCallback> &callback)443 int32_t CacheBuffer::SetCacheBufferCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
444 {
445     cacheBufferCallback_ = callback;
446     return MSERR_OK;
447 }
448 
SetFrameWriteCallback(const std::shared_ptr<ISoundPoolFrameWriteCallback> &callback)449 int32_t CacheBuffer::SetFrameWriteCallback(const std::shared_ptr<ISoundPoolFrameWriteCallback> &callback)
450 {
451     frameWriteCallback_ = callback;
452     return MSERR_OK;
453 }
454 } // namespace Media
455 } // namespace OHOS
456