1 /*
2  * Copyright (C) 2023 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 <fcntl.h>
17 #include <functional>
18 #include <cstdio>
19 #include "isoundpool.h"
20 #include "sound_parser.h"
21 
22 namespace {
23     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SOUNDPOOL, "SoundParser"};
24     static constexpr int32_t MAX_SOUND_BUFFER_SIZE = 1 * 1024 * 1024;
25     static const std::string AUDIO_RAW_MIMETYPE_INFO = "audio/raw";
26     static const std::string AUDIO_MPEG_MIMETYPE_INFO = "audio/mpeg";
27 }
28 
29 namespace OHOS {
30 namespace Media {
SoundParser(int32_t soundID,std::string url)31 SoundParser::SoundParser(int32_t soundID, std::string url)
32 {
33     std::shared_ptr<MediaAVCodec::AVSource> source = MediaAVCodec::AVSourceFactory::CreateWithURI(url);
34     CHECK_AND_RETURN_LOG(source != nullptr, "Create AVSource failed");
35     std::shared_ptr<MediaAVCodec::AVDemuxer> demuxer = MediaAVCodec::AVDemuxerFactory::CreateWithSource(source);
36     CHECK_AND_RETURN_LOG(demuxer != nullptr, "Create AVDemuxer failed");
37     soundID_ = soundID;
38     demuxer_ = demuxer;
39     source_ = source;
40 }
41 
SoundParser(int32_t soundID,int32_t fd,int64_t offset,int64_t length)42 SoundParser::SoundParser(int32_t soundID, int32_t fd, int64_t offset, int64_t length)
43 {
44     fdSource_ = fcntl(fd, F_DUPFD_CLOEXEC, MIN_FD); // dup(fd) + close on exec to prevent leaks.
45     offset = offset >= INT64_MAX ? INT64_MAX : offset;
46     length = length >= INT64_MAX ? INT64_MAX : length;
47     MEDIA_LOGI("SoundParser::SoundParser fd:%{public}d, fdSource_:%{public}d,", fd, fdSource_);
48     std::shared_ptr<MediaAVCodec::AVSource> source =
49         MediaAVCodec::AVSourceFactory::CreateWithFD(fdSource_, offset, length);
50     CHECK_AND_RETURN_LOG(source != nullptr, "Create AVSource failed");
51     std::shared_ptr<MediaAVCodec::AVDemuxer> demuxer = MediaAVCodec::AVDemuxerFactory::CreateWithSource(source);
52     CHECK_AND_RETURN_LOG(demuxer != nullptr, "Create AVDemuxer failed");
53 
54     soundID_ = soundID;
55     demuxer_ = demuxer;
56     source_ = source;
57 }
58 
~SoundParser()59 SoundParser::~SoundParser()
60 {
61     MEDIA_LOGI("SoundParser Destruction, soundID:%{public}d", soundID_);
62     Release();
63 }
64 
DoParser()65 int32_t SoundParser::DoParser()
66 {
67     MediaTrace trace("SoundParser::DoParser");
68     MEDIA_LOGI("SoundParser::DoParser start, soundID:%{public}d", soundID_);
69     std::unique_lock<ffrt::mutex> lock(soundParserLock_);
70     CHECK_AND_RETURN_RET_LOG(source_ != nullptr, MSERR_INVALID_VAL, "DoParser source_ is nullptr");
71     CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, MSERR_INVALID_VAL, "DoParser demuxer_ is nullptr");
72     int32_t result = MSERR_OK;
73     result = DoDemuxer(&trackFormat_);
74     if (result != MSERR_OK && callback_ != nullptr) {
75         MEDIA_LOGI("DoDemuxer failed, call callback");
76         callback_->OnError(MSERR_UNSUPPORT_FILE);
77         return MSERR_INVALID_VAL;
78     } else if (result != MSERR_OK && callback_ == nullptr) {
79         MEDIA_LOGI("DoDemuxer failed, callback is nullptr");
80         return MSERR_INVALID_VAL;
81     }
82     result = DoDecode(trackFormat_);
83     if (result != MSERR_OK && callback_ != nullptr) {
84         MEDIA_LOGI("DoDecode failed, call callback");
85         callback_->OnError(MSERR_UNSUPPORT_FILE);
86         return MSERR_INVALID_VAL;
87     } else if (result != MSERR_OK && callback_ == nullptr) {
88         MEDIA_LOGI("DoDecode failed, callback is nullptr");
89         return MSERR_INVALID_VAL;
90     }
91     MEDIA_LOGI("SoundParser::DoParser end, soundID:%{public}d", soundID_);
92     return MSERR_OK;
93 }
94 
DoDemuxer(MediaAVCodec::Format * trackFormat)95 int32_t SoundParser::DoDemuxer(MediaAVCodec::Format *trackFormat)
96 {
97     MediaTrace trace("SoundParser::DoDemuxer");
98     MEDIA_LOGI("SoundParser::DoDemuxer start, soundID:%{public}d", soundID_);
99     MediaAVCodec::Format sourceFormat;
100     int32_t sourceTrackCountInfo = 0;
101     int64_t sourceDurationInfo = 0;
102     CHECK_AND_RETURN_RET_LOG(source_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain av source");
103     CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain demuxer");
104     CHECK_AND_RETURN_RET_LOG(trackFormat != nullptr, MSERR_INVALID_VAL, "Invalid trackFormat.");
105     int32_t ret = source_->GetSourceFormat(sourceFormat);
106     if (ret != 0) {
107         MEDIA_LOGE("Get source format failed:%{public}d", ret);
108     }
109     sourceFormat.GetIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_TRACK_COUNT, sourceTrackCountInfo);
110     sourceFormat.GetLongValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_DURATION, sourceDurationInfo);
111 
112     MEDIA_LOGI("SoundParser sourceTrackCountInfo:%{public}d", sourceTrackCountInfo);
113     for (int32_t sourceTrackIndex = 0; sourceTrackIndex < sourceTrackCountInfo; sourceTrackIndex++) {
114         int32_t trackType = 0;
115         ret = source_->GetTrackFormat(*trackFormat, sourceTrackIndex);
116         if (ret != 0) {
117             MEDIA_LOGE("Get track format failed:%{public}d", ret);
118         }
119         trackFormat->GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
120         MEDIA_LOGI("SoundParser trackType:%{public}d", trackType);
121         if (trackType == MEDIA_TYPE_AUD) {
122             demuxer_->SelectTrackByID(sourceTrackIndex);
123             std::string trackMimeTypeInfo;
124             trackFormat->GetStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME, trackMimeTypeInfo);
125             if (AUDIO_RAW_MIMETYPE_INFO.compare(trackMimeTypeInfo) != 0) {
126                 // resample format
127                 trackFormat->PutIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT,
128                     MediaAVCodec::SAMPLE_S16LE);
129             } else {
130                 isRawFile_ = true;
131                 trackFormat->PutStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME,
132                     AUDIO_MPEG_MIMETYPE_INFO);
133             }
134             break;
135         }
136     }
137     MEDIA_LOGI("SoundParser::DoDemuxer end, soundID:%{public}d", soundID_);
138     return MSERR_OK;
139 }
140 
DoDecode(MediaAVCodec::Format trackFormat)141 int32_t SoundParser::DoDecode(MediaAVCodec::Format trackFormat)
142 {
143     MediaTrace trace("SoundParser::DoDecode");
144     MEDIA_LOGI("SoundParser::DoDecode start, soundID:%{public}d", soundID_);
145     int32_t trackTypeInfo;
146     trackFormat.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackTypeInfo);
147     if (trackTypeInfo == MEDIA_TYPE_AUD) {
148         std::string trackMimeTypeInfo;
149         trackFormat.GetStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME, trackMimeTypeInfo);
150         MEDIA_LOGI("SoundParser mime type:%{public}s", trackMimeTypeInfo.c_str());
151         audioDec_ = MediaAVCodec::AudioDecoderFactory::CreateByMime(trackMimeTypeInfo);
152         CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain audioDecorder.");
153         int32_t ret = audioDec_->Configure(trackFormat);
154         CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to configure audioDecorder.");
155         audioDecCb_ = std::make_shared<SoundDecoderCallback>(soundID_, audioDec_, demuxer_, isRawFile_);
156         CHECK_AND_RETURN_RET_LOG(audioDecCb_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain decode callback.");
157         ret = audioDec_->SetCallback(audioDecCb_);
158         CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to setCallback audioDecorder");
159         soundParserListener_ = std::make_shared<SoundParserListener>(weak_from_this());
160         CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, MSERR_INVALID_VAL, "Invalid sound parser listener");
161         audioDecCb_->SetDecodeCallback(soundParserListener_);
162         if (callback_ != nullptr) audioDecCb_->SetCallback(callback_);
163         ret = audioDec_->Start();
164         CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to Start audioDecorder.");
165         MEDIA_LOGI("SoundParser::DoDecode, audioDec_ started, soundID:%{public}d", soundID_);
166     }
167     return MSERR_OK;
168 }
169 
GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> & soundData) const170 int32_t SoundParser::GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> &soundData) const
171 {
172     CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, MSERR_INVALID_VAL, "Invalid sound parser listener");
173     return soundParserListener_->GetSoundData(soundData);
174 }
175 
GetSoundDataTotalSize() const176 size_t SoundParser::GetSoundDataTotalSize() const
177 {
178     CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, 0, "Invalid sound parser listener");
179     return soundParserListener_->GetSoundDataTotalSize();
180 }
181 
IsSoundParserCompleted() const182 bool SoundParser::IsSoundParserCompleted() const
183 {
184     CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, false, "Invalid sound parser listener");
185     return soundParserListener_->IsSoundParserCompleted();
186 }
187 
SetCallback(const std::shared_ptr<ISoundPoolCallback> & callback)188 int32_t SoundParser::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
189 {
190     callback_ = callback;
191     return MSERR_OK;
192 }
193 
Release()194 int32_t SoundParser::Release()
195 {
196     MediaTrace trace("SoundParser::Release");
197     MEDIA_LOGI("SoundParser::Release start, soundID:%{public}d", soundID_);
198     int32_t ret = MSERR_OK;
199     std::shared_ptr<SoundDecoderCallback> audioDecCbRelease;
200     {
201         std::unique_lock<ffrt::mutex> lock(soundParserLock_);
202         if (soundParserListener_ != nullptr) soundParserListener_.reset();
203         audioDecCbRelease = std::move(audioDecCb_);
204         audioDecCb_ = nullptr;
205     }
206     if (audioDecCbRelease != nullptr) {
207         ret = audioDecCbRelease->Release();
208         audioDecCbRelease.reset();
209     }
210     std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> audioDecRelease;
211     {
212         std::unique_lock<ffrt::mutex> lock(soundParserLock_);
213         audioDecRelease = std::move(audioDec_);
214         audioDec_ = nullptr;
215     }
216     if (audioDecRelease != nullptr) {
217         ret = audioDecRelease->Release();
218         audioDecRelease.reset();
219     }
220     std::unique_lock<ffrt::mutex> lock(soundParserLock_);
221     if (demuxer_ != nullptr) demuxer_.reset();
222     if (source_ != nullptr) source_.reset();
223     if (callback_ != nullptr) callback_.reset();
224     if (fdSource_ > 0) {
225         MEDIA_LOGI("SoundParser::Release() fdSource_:%{public}d", fdSource_);
226         (void)close(fdSource_);
227         fdSource_ = -1;
228     }
229     MEDIA_LOGI("SoundParser::Release end, soundID:%{public}d", soundID_);
230     return ret;
231 }
232 
SoundDecoderCallback(const int32_t soundID,const std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> & audioDec,const std::shared_ptr<MediaAVCodec::AVDemuxer> & demuxer,const bool isRawFile)233 SoundDecoderCallback::SoundDecoderCallback(const int32_t soundID,
234     const std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> &audioDec,
235     const std::shared_ptr<MediaAVCodec::AVDemuxer> &demuxer,
236     const bool isRawFile) : soundID_(soundID), audioDec_(audioDec),
237     demuxer_(demuxer), isRawFile_(isRawFile), eosFlag_(false),
238     decodeShouldCompleted_(false), currentSoundBufferSize_(0)
239 {
240     MEDIA_LOGI("Construction SoundDecoderCallback");
241 }
242 
~SoundDecoderCallback()243 SoundDecoderCallback::~SoundDecoderCallback()
244 {
245     MEDIA_LOGI("Destruction SoundDecoderCallback");
246     Release();
247 }
OnError(AVCodecErrorType errorType,int32_t errorCode)248 void SoundDecoderCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
249 {
250     if (isRawFile_) {
251         MEDIA_LOGI("Recive error, errorType:%{public}d,errorCode:%{public}d", errorType, errorCode);
252     }
253 }
254 
OnOutputFormatChanged(const Format & format)255 void SoundDecoderCallback::OnOutputFormatChanged(const Format &format)
256 {
257     (void)format;
258 }
259 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)260 void SoundDecoderCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
261 {
262     amutex_.lock();
263     MediaAVCodec::AVCodecBufferFlag bufferFlag = MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE;
264     MediaAVCodec::AVCodecBufferInfo sampleInfo;
265     if (demuxer_ == nullptr || audioDec_ == nullptr) {
266         MEDIA_LOGE("SoundDecoderCallback Input demuxer_:%{public}d, audioDec_:%{public}d,",
267             demuxer_ == nullptr, audioDec_ == nullptr);
268         amutex_.unlock();
269         return;
270     }
271 
272     if (buffer != nullptr && isRawFile_ && !decodeShouldCompleted_) {
273         DealBufferRawFile(bufferFlag, sampleInfo, index, buffer);
274         amutex_.unlock();
275         return;
276     }
277 
278     if (buffer != nullptr && !eosFlag_ && !decodeShouldCompleted_) {
279         if (demuxer_->ReadSample(0, buffer, sampleInfo, bufferFlag) != AVCS_ERR_OK) {
280             MEDIA_LOGE("SoundDecoderCallback demuxer error.");
281             amutex_.unlock();
282             return;
283         }
284         if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) {
285             eosFlag_ = true;
286         }
287         audioDec_->QueueInputBuffer(index, sampleInfo, bufferFlag);
288     }
289     amutex_.unlock();
290 }
291 
DealBufferRawFile(MediaAVCodec::AVCodecBufferFlag bufferFlag,MediaAVCodec::AVCodecBufferInfo sampleInfo,uint32_t index,std::shared_ptr<AVSharedMemory> buffer)292 void SoundDecoderCallback::DealBufferRawFile(MediaAVCodec::AVCodecBufferFlag bufferFlag,
293     MediaAVCodec::AVCodecBufferInfo sampleInfo, uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
294 {
295     if (demuxer_->ReadSample(0, buffer, sampleInfo, bufferFlag) != AVCS_ERR_OK) {
296         MEDIA_LOGE("SoundDecoderCallback demuxer error.");
297         return;
298     }
299     if (!decodeShouldCompleted_ && (currentSoundBufferSize_ > MAX_SOUND_BUFFER_SIZE ||
300             bufferFlag == AVCODEC_BUFFER_FLAG_EOS)) {
301         decodeShouldCompleted_ = true;
302         CHECK_AND_RETURN_LOG(listener_ != nullptr, "sound decode listener invalid.");
303         listener_->OnSoundDecodeCompleted(availableAudioBuffers_);
304         listener_->SetSoundBufferTotalSize(static_cast<size_t>(currentSoundBufferSize_));
305         CHECK_AND_RETURN_LOG(callback_ != nullptr, "sound decode:soundpool callback invalid.");
306         callback_->OnLoadCompleted(soundID_);
307         return;
308     }
309     int32_t size = sampleInfo.size;
310     uint8_t *buf = new(std::nothrow) uint8_t[size];
311     if (buf != nullptr) {
312         if (memcpy_s(buf, size, buffer->GetBase(), size) != EOK) {
313             delete[] buf;
314             MEDIA_LOGI("audio buffer copy failed:%{public}s", strerror(errno));
315         } else {
316             availableAudioBuffers_.push_back(std::make_shared<AudioBufferEntry>(buf, size));
317             bufferCond_.notify_all();
318         }
319     }
320     currentSoundBufferSize_ += size;
321     audioDec_->QueueInputBuffer(index, sampleInfo, bufferFlag);
322     return;
323 }
324 
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)325 void SoundDecoderCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
326     std::shared_ptr<AVSharedMemory> buffer)
327 {
328     amutex_.lock();
329     if (demuxer_ == nullptr || audioDec_ == nullptr) {
330         MEDIA_LOGE("SoundDecoderCallback Output demuxer_:%{public}d, audioDec_:%{public}d,",
331             demuxer_ == nullptr, audioDec_ == nullptr);
332         amutex_.unlock();
333         return;
334     }
335     if (isRawFile_) {
336         audioDec_->ReleaseOutputBuffer(index);
337         amutex_.unlock();
338         return;
339     }
340     if (buffer != nullptr && !decodeShouldCompleted_) {
341         if (currentSoundBufferSize_ > MAX_SOUND_BUFFER_SIZE || flag == AVCODEC_BUFFER_FLAG_EOS) {
342             decodeShouldCompleted_ = true;
343             if (listener_ != nullptr) {
344                 listener_->OnSoundDecodeCompleted(availableAudioBuffers_);
345                 listener_->SetSoundBufferTotalSize(static_cast<size_t>(currentSoundBufferSize_));
346             }
347             if (callback_ != nullptr) {
348                 callback_->OnLoadCompleted(soundID_);
349             }
350             amutex_.unlock();
351             return;
352         }
353         int32_t size = info.size;
354         uint8_t *buf = new(std::nothrow) uint8_t[size];
355         if (buf != nullptr) {
356             if (memcpy_s(buf, size, buffer->GetBase(), info.size) != EOK) {
357                 delete[] buf;
358                 MEDIA_LOGI("audio buffer copy failed:%{public}s", strerror(errno));
359             } else {
360                 availableAudioBuffers_.push_back(std::make_shared<AudioBufferEntry>(buf, size));
361                 bufferCond_.notify_all();
362             }
363         }
364         currentSoundBufferSize_ += size;
365     }
366     audioDec_->ReleaseOutputBuffer(index);
367     amutex_.unlock();
368 }
369 
SetCallback(const std::shared_ptr<ISoundPoolCallback> & callback)370 int32_t SoundDecoderCallback::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
371 {
372     MEDIA_LOGI("SoundDecoderCallback::SetCallback");
373     callback_ = callback;
374     return MSERR_OK;
375 }
376 
Release()377 int32_t SoundDecoderCallback::Release()
378 {
379     int32_t ret = MSERR_OK;
380     MEDIA_LOGI("SoundDecoderCallback::Release");
381     //here use audioDec, the reason is the same reason in CacheBuffer::Release().please check it
382     //in CacheBuffer::Release()
383     std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> audioDec;
384     {
385         std::lock_guard lock(amutex_);
386         audioDec = std::move(audioDec_);
387         audioDec_ = nullptr;
388     }
389     if (audioDec != nullptr) {
390         ret = audioDec->Release();
391         audioDec.reset();
392         audioDec = nullptr;
393     }
394     std::lock_guard lock(amutex_);
395     if (demuxer_ != nullptr) demuxer_.reset();
396     if (listener_ != nullptr) listener_.reset();
397     if (!availableAudioBuffers_.empty()) availableAudioBuffers_.clear();
398     if (callback_ != nullptr) callback_.reset();
399     return ret;
400 }
401 
OnSoundDecodeCompleted(const std::deque<std::shared_ptr<AudioBufferEntry>> & availableAudioBuffers)402 void SoundParser::SoundParserListener::OnSoundDecodeCompleted(
403     const std::deque<std::shared_ptr<AudioBufferEntry>> &availableAudioBuffers)
404 {
405     if (std::shared_ptr<SoundParser> soundPaser = soundParserInner_.lock()) {
406         std::unique_lock<ffrt::mutex> lock(soundPaser->soundParserLock_);
407         soundData_ = availableAudioBuffers;
408         isSoundParserCompleted_.store(true);
409     }
410 }
411 
SetSoundBufferTotalSize(const size_t soundBufferTotalSize)412 void SoundParser::SoundParserListener::SetSoundBufferTotalSize(const size_t soundBufferTotalSize)
413 {
414     if (std::shared_ptr<SoundParser> soundPaser = soundParserInner_.lock()) {
415         std::unique_lock<ffrt::mutex> lock(soundPaser->soundParserLock_);
416         soundBufferTotalSize_ = soundBufferTotalSize;
417     }
418 }
419 
GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> & soundData) const420 int32_t SoundParser::SoundParserListener::GetSoundData(
421     std::deque<std::shared_ptr<AudioBufferEntry>> &soundData) const
422 {
423     if (std::shared_ptr<SoundParser> soundPaser = soundParserInner_.lock()) {
424         std::unique_lock<ffrt::mutex> lock(soundPaser->soundParserLock_);
425         soundData = soundData_;
426     }
427     return MSERR_OK;
428 }
429 
GetSoundDataTotalSize() const430 size_t SoundParser::SoundParserListener::GetSoundDataTotalSize() const
431 {
432     return soundBufferTotalSize_;
433 }
434 
IsSoundParserCompleted() const435 bool SoundParser::SoundParserListener::IsSoundParserCompleted() const
436 {
437     return isSoundParserCompleted_.load();
438 }
439 
440 } // namespace Media
441 } // namespace OHOS
442