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