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     isParsing_.store(true);
71     int32_t result = MSERR_OK;
72     result = DoDemuxer(&trackFormat_);
73     if (result != MSERR_OK && callback_ != nullptr) {
74         MEDIA_LOGI("DoDemuxer failed, call callback");
75         callback_->OnError(MSERR_UNSUPPORT_FILE);
76         return MSERR_INVALID_VAL;
77     }
78     result = DoDecode(trackFormat_);
79     if (result != MSERR_OK && callback_ != nullptr) {
80         MEDIA_LOGI("DoDecode failed, call callback");
81         callback_->OnError(MSERR_UNSUPPORT_FILE);
82         return MSERR_INVALID_VAL;
83     }
84     MEDIA_LOGI("SoundParser::DoParser end, soundID:%{public}d", soundID_);
85     return MSERR_OK;
86 }
87 
DoDemuxer(MediaAVCodec::Format *trackFormat)88 int32_t SoundParser::DoDemuxer(MediaAVCodec::Format *trackFormat)
89 {
90     MediaTrace trace("SoundParser::DoDemuxer");
91     MEDIA_LOGI("SoundParser::DoDemuxer start, soundID:%{public}d", soundID_);
92     MediaAVCodec::Format sourceFormat;
93     int32_t sourceTrackCountInfo = 0;
94     int64_t sourceDurationInfo = 0;
95     CHECK_AND_RETURN_RET_LOG(source_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain av source");
96     CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain demuxer");
97     CHECK_AND_RETURN_RET_LOG(trackFormat != nullptr, MSERR_INVALID_VAL, "Invalid trackFormat.");
98     int32_t ret = source_->GetSourceFormat(sourceFormat);
99     if (ret != 0) {
100         MEDIA_LOGE("Get source format failed:%{public}d", ret);
101     }
102     sourceFormat.GetIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_TRACK_COUNT, sourceTrackCountInfo);
103     sourceFormat.GetLongValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_DURATION, sourceDurationInfo);
104 
105     MEDIA_LOGI("SoundParser sourceTrackCountInfo:%{public}d", sourceTrackCountInfo);
106     for (int32_t sourceTrackIndex = 0; sourceTrackIndex < sourceTrackCountInfo; sourceTrackIndex++) {
107         int32_t trackType = 0;
108         ret = source_->GetTrackFormat(*trackFormat, sourceTrackIndex);
109         if (ret != 0) {
110             MEDIA_LOGE("Get track format failed:%{public}d", ret);
111         }
112         trackFormat->GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
113         MEDIA_LOGI("SoundParser trackType:%{public}d", trackType);
114         if (trackType == MEDIA_TYPE_AUD) {
115             demuxer_->SelectTrackByID(sourceTrackIndex);
116             std::string trackMimeTypeInfo;
117             trackFormat->GetStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME, trackMimeTypeInfo);
118             if (AUDIO_RAW_MIMETYPE_INFO.compare(trackMimeTypeInfo) != 0) {
119                 // resample format
120                 trackFormat->PutIntValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT,
121                     MediaAVCodec::SAMPLE_S16LE);
122             } else {
123                 isRawFile_ = true;
124                 trackFormat->PutStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME,
125                     AUDIO_MPEG_MIMETYPE_INFO);
126             }
127             break;
128         }
129     }
130     MEDIA_LOGI("SoundParser::DoDemuxer end, soundID:%{public}d", soundID_);
131     return MSERR_OK;
132 }
133 
DoDecode(MediaAVCodec::Format trackFormat)134 int32_t SoundParser::DoDecode(MediaAVCodec::Format trackFormat)
135 {
136     MediaTrace trace("SoundParser::DoDecode");
137     MEDIA_LOGI("SoundParser::DoDecode start, soundID:%{public}d", soundID_);
138     int32_t trackTypeInfo;
139     trackFormat.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackTypeInfo);
140     if (trackTypeInfo == MEDIA_TYPE_AUD) {
141         std::string trackMimeTypeInfo;
142         trackFormat.GetStringValue(MediaAVCodec::MediaDescriptionKey::MD_KEY_CODEC_MIME, trackMimeTypeInfo);
143         MEDIA_LOGI("SoundParser mime type:%{public}s", trackMimeTypeInfo.c_str());
144         audioDec_ = MediaAVCodec::AudioDecoderFactory::CreateByMime(trackMimeTypeInfo);
145         CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain audioDecorder.");
146         int32_t ret = audioDec_->Configure(trackFormat);
147         CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to configure audioDecorder.");
148         audioDecCb_ = std::make_shared<SoundDecoderCallback>(soundID_, audioDec_, demuxer_, isRawFile_);
149         CHECK_AND_RETURN_RET_LOG(audioDecCb_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain decode callback.");
150         ret = audioDec_->SetCallback(audioDecCb_);
151         CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to setCallback audioDecorder");
152         soundParserListener_ = std::make_shared<SoundParserListener>(weak_from_this());
153         CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, MSERR_INVALID_VAL, "Invalid sound parser listener");
154         audioDecCb_->SetDecodeCallback(soundParserListener_);
155         if (callback_ != nullptr) audioDecCb_->SetCallback(callback_);
156         ret = audioDec_->Start();
157         CHECK_AND_RETURN_RET_LOG(ret == 0, MSERR_INVALID_VAL, "Failed to Start audioDecorder.");
158         MEDIA_LOGI("SoundParser::DoDecode, audioDec_ started, soundID:%{public}d", soundID_);
159     }
160     return MSERR_OK;
161 }
162 
GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> &soundData) const163 int32_t SoundParser::GetSoundData(std::deque<std::shared_ptr<AudioBufferEntry>> &soundData) const
164 {
165     CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, MSERR_INVALID_VAL, "Invalid sound parser listener");
166     return soundParserListener_->GetSoundData(soundData);
167 }
168 
GetSoundDataTotalSize() const169 size_t SoundParser::GetSoundDataTotalSize() const
170 {
171     CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, 0, "Invalid sound parser listener");
172     return soundParserListener_->GetSoundDataTotalSize();
173 }
174 
IsSoundParserCompleted() const175 bool SoundParser::IsSoundParserCompleted() const
176 {
177     CHECK_AND_RETURN_RET_LOG(soundParserListener_ != nullptr, false, "Invalid sound parser listener");
178     return soundParserListener_->IsSoundParserCompleted();
179 }
180 
SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)181 int32_t SoundParser::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
182 {
183     callback_ = callback;
184     return MSERR_OK;
185 }
186 
Release()187 int32_t SoundParser::Release()
188 {
189     MediaTrace trace("SoundParser::Release");
190     MEDIA_LOGI("SoundParser::Release start, soundID:%{public}d", soundID_);
191     std::unique_lock<ffrt::mutex> lock(soundParserLock_);
192     isParsing_.store(false);
193     int32_t ret = MSERR_OK;
194     if (soundParserListener_ != nullptr) soundParserListener_.reset();
195     if (audioDecCb_ != nullptr) {
196         ret = audioDecCb_->Release();
197         audioDecCb_.reset();
198     }
199     if (audioDec_ != nullptr) {
200         ret = audioDec_->Release();
201         audioDec_.reset();
202     }
203     if (demuxer_ != nullptr) demuxer_.reset();
204     if (source_ != nullptr) source_.reset();
205     if (callback_ != nullptr) callback_.reset();
206     if (fdSource_ > 0) {
207         MEDIA_LOGI("SoundParser::Release() fdSource_:%{public}d", fdSource_);
208         (void)close(fdSource_);
209         fdSource_ = -1;
210     }
211     MEDIA_LOGI("SoundParser::Release end, soundID:%{public}d", soundID_);
212     return ret;
213 }
214 
SoundDecoderCallback(const int32_t soundID, const std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> &audioDec, const std::shared_ptr<MediaAVCodec::AVDemuxer> &demuxer, const bool isRawFile)215 SoundDecoderCallback::SoundDecoderCallback(const int32_t soundID,
216     const std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> &audioDec,
217     const std::shared_ptr<MediaAVCodec::AVDemuxer> &demuxer,
218     const bool isRawFile) : soundID_(soundID), audioDec_(audioDec),
219     demuxer_(demuxer), isRawFile_(isRawFile), eosFlag_(false),
220     decodeShouldCompleted_(false), currentSoundBufferSize_(0)
221 {
222     MEDIA_LOGI("Construction SoundDecoderCallback");
223 }
224 
~SoundDecoderCallback()225 SoundDecoderCallback::~SoundDecoderCallback()
226 {
227     MEDIA_LOGI("Destruction SoundDecoderCallback");
228     Release();
229 }
OnError(AVCodecErrorType errorType, int32_t errorCode)230 void SoundDecoderCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
231 {
232     if (isRawFile_) {
233         MEDIA_LOGI("Recive error, errorType:%{public}d,errorCode:%{public}d", errorType, errorCode);
234     }
235 }
236 
OnOutputFormatChanged(const Format &format)237 void SoundDecoderCallback::OnOutputFormatChanged(const Format &format)
238 {
239     (void)format;
240 }
241 
OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)242 void SoundDecoderCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
243 {
244     amutex_.lock();
245     MediaAVCodec::AVCodecBufferFlag bufferFlag = MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE;
246     MediaAVCodec::AVCodecBufferInfo sampleInfo;
247     if (demuxer_ == nullptr || audioDec_ == nullptr) {
248         MEDIA_LOGE("SoundDecoderCallback Input demuxer_:%{public}d, audioDec_:%{public}d,",
249             demuxer_ == nullptr, audioDec_ == nullptr);
250         amutex_.unlock();
251         return;
252     }
253 
254     if (buffer != nullptr && isRawFile_ && !decodeShouldCompleted_) {
255         DealBufferRawFile(bufferFlag, sampleInfo, index, buffer);
256         amutex_.unlock();
257         return;
258     }
259 
260     if (buffer != nullptr && !eosFlag_ && !decodeShouldCompleted_) {
261         if (demuxer_->ReadSample(0, buffer, sampleInfo, bufferFlag) != AVCS_ERR_OK) {
262             MEDIA_LOGE("SoundDecoderCallback demuxer error.");
263             amutex_.unlock();
264             return;
265         }
266         if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) {
267             eosFlag_ = true;
268         }
269         audioDec_->QueueInputBuffer(index, sampleInfo, bufferFlag);
270     }
271     amutex_.unlock();
272 }
273 
DealBufferRawFile(MediaAVCodec::AVCodecBufferFlag bufferFlag, MediaAVCodec::AVCodecBufferInfo sampleInfo, uint32_t index, std::shared_ptr<AVSharedMemory> buffer)274 void SoundDecoderCallback::DealBufferRawFile(MediaAVCodec::AVCodecBufferFlag bufferFlag,
275     MediaAVCodec::AVCodecBufferInfo sampleInfo, uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
276 {
277     if (demuxer_->ReadSample(0, buffer, sampleInfo, bufferFlag) != AVCS_ERR_OK) {
278         MEDIA_LOGE("SoundDecoderCallback demuxer error.");
279         return;
280     }
281     if (!decodeShouldCompleted_ && (currentSoundBufferSize_ > MAX_SOUND_BUFFER_SIZE ||
282             bufferFlag == AVCODEC_BUFFER_FLAG_EOS)) {
283         decodeShouldCompleted_ = true;
284         CHECK_AND_RETURN_LOG(listener_ != nullptr, "sound decode listener invalid.");
285         listener_->OnSoundDecodeCompleted(availableAudioBuffers_);
286         listener_->SetSoundBufferTotalSize(static_cast<size_t>(currentSoundBufferSize_));
287         CHECK_AND_RETURN_LOG(callback_ != nullptr, "sound decode:soundpool callback invalid.");
288         callback_->OnLoadCompleted(soundID_);
289         return;
290     }
291     int32_t size = sampleInfo.size;
292     uint8_t *buf = new(std::nothrow) uint8_t[size];
293     if (buf != nullptr) {
294         if (memcpy_s(buf, size, buffer->GetBase(), size) != EOK) {
295             delete[] buf;
296             MEDIA_LOGI("audio buffer copy failed:%{public}s", strerror(errno));
297         } else {
298             availableAudioBuffers_.push_back(std::make_shared<AudioBufferEntry>(buf, size));
299             bufferCond_.notify_all();
300         }
301     }
302     currentSoundBufferSize_ += size;
303     audioDec_->QueueInputBuffer(index, sampleInfo, bufferFlag);
304     return;
305 }
306 
OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag, std::shared_ptr<AVSharedMemory> buffer)307 void SoundDecoderCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
308     std::shared_ptr<AVSharedMemory> buffer)
309 {
310     amutex_.lock();
311     if (demuxer_ == nullptr || audioDec_ == nullptr) {
312         MEDIA_LOGE("SoundDecoderCallback Output demuxer_:%{public}d, audioDec_:%{public}d,",
313             demuxer_ == nullptr, audioDec_ == nullptr);
314         amutex_.unlock();
315         return;
316     }
317     if (isRawFile_) {
318         audioDec_->ReleaseOutputBuffer(index);
319         amutex_.unlock();
320         return;
321     }
322     if (buffer != nullptr && !decodeShouldCompleted_) {
323         if (currentSoundBufferSize_ > MAX_SOUND_BUFFER_SIZE || flag == AVCODEC_BUFFER_FLAG_EOS) {
324             decodeShouldCompleted_ = true;
325             if (listener_ != nullptr) {
326                 listener_->OnSoundDecodeCompleted(availableAudioBuffers_);
327                 listener_->SetSoundBufferTotalSize(static_cast<size_t>(currentSoundBufferSize_));
328             }
329             if (callback_ != nullptr) {
330                 callback_->OnLoadCompleted(soundID_);
331             }
332             amutex_.unlock();
333             return;
334         }
335         int32_t size = info.size;
336         uint8_t *buf = new(std::nothrow) uint8_t[size];
337         if (buf != nullptr) {
338             if (memcpy_s(buf, size, buffer->GetBase(), info.size) != EOK) {
339                 delete[] buf;
340                 MEDIA_LOGI("audio buffer copy failed:%{public}s", strerror(errno));
341             } else {
342                 availableAudioBuffers_.push_back(std::make_shared<AudioBufferEntry>(buf, size));
343                 bufferCond_.notify_all();
344             }
345         }
346         currentSoundBufferSize_ += size;
347     }
348     audioDec_->ReleaseOutputBuffer(index);
349     amutex_.unlock();
350 }
351 
SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)352 int32_t SoundDecoderCallback::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
353 {
354     MEDIA_LOGI("SoundDecoderCallback::SetCallback");
355     callback_ = callback;
356     return MSERR_OK;
357 }
358 
Release()359 int32_t SoundDecoderCallback::Release()
360 {
361     int32_t ret = MSERR_OK;
362     MEDIA_LOGI("SoundDecoderCallback::Release");
363     //here use audioDec, the reason is the same reason in CacheBuffer::Release().please check it
364     //in CacheBuffer::Release()
365     std::shared_ptr<MediaAVCodec::AVCodecAudioDecoder> audioDec;
366     {
367         std::lock_guard lock(amutex_);
368         audioDec = std::move(audioDec_);
369         audioDec_ = nullptr;
370     }
371     if (audioDec != nullptr) {
372         ret = audioDec->Release();
373         audioDec.reset();
374         audioDec = nullptr;
375     }
376     std::lock_guard lock(amutex_);
377     if (demuxer_ != nullptr) demuxer_.reset();
378     if (listener_ != nullptr) listener_.reset();
379     if (!availableAudioBuffers_.empty()) availableAudioBuffers_.clear();
380     if (callback_ != nullptr) callback_.reset();
381     return ret;
382 }
383 } // namespace Media
384 } // namespace OHOS
385