1 /*
2 * Copyright (c) 2022-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 "audio_encoder.h"
17
18 #include "audio_info.h"
19 #include "avsharedmemory.h"
20 #include "media_errors.h"
21 #include "securec.h"
22
23 #include "audio_encoder_callback.h"
24 #include "daudio_errorcode.h"
25 #include "daudio_log.h"
26 #include "daudio_util.h"
27
28 #undef DH_LOG_TAG
29 #define DH_LOG_TAG "AudioEncoder"
30
31 namespace OHOS {
32 namespace DistributedHardware {
33 const std::string AudioEncoder::ENCODE_MIME_AAC = "audio/mp4a-latm";
34
~AudioEncoder()35 AudioEncoder::~AudioEncoder()
36 {
37 if (audioEncoder_ != nullptr) {
38 DHLOGD("Release audio codec.");
39 StopAudioCodec();
40 ReleaseAudioCodec();
41 }
42 }
43
ConfigureAudioCodec(const AudioCommonParam & codecParam,const std::shared_ptr<IAudioCodecCallback> & codecCallback)44 int32_t AudioEncoder::ConfigureAudioCodec(const AudioCommonParam &codecParam,
45 const std::shared_ptr<IAudioCodecCallback> &codecCallback)
46 {
47 DHLOGD("Configure audio codec.");
48 if (!IsInEncodeRange(codecParam) || codecCallback == nullptr) {
49 DHLOGE("Codec param error or callback is null.");
50 return ERR_DH_AUDIO_BAD_VALUE;
51 }
52 codecParam_ = codecParam;
53 codecCallback_ = codecCallback;
54
55 int32_t ret = InitAudioEncoder(codecParam);
56 if (ret != DH_SUCCESS) {
57 DHLOGE("Init audio encoder fail. Error code %d.", ret);
58 return ret;
59 }
60
61 ret = SetEncoderFormat(codecParam);
62 if (ret != DH_SUCCESS) {
63 DHLOGE("Set encoder format fail. Error code %d.", ret);
64 return ret;
65 }
66 return DH_SUCCESS;
67 }
68
IsInEncodeRange(const AudioCommonParam & codecParam)69 bool AudioEncoder::IsInEncodeRange(const AudioCommonParam &codecParam)
70 {
71 if (codecParam.channelMask >= CHANNEL_MASK_MIN && codecParam.channelMask <= CHANNEL_MASK_MAX &&
72 codecParam.sampleRate >= SAMPLE_RATE_MIN && codecParam.sampleRate <= SAMPLE_RATE_MAX &&
73 codecParam.bitFormat == SAMPLE_S16LE && codecParam.codecType == AUDIO_CODEC_AAC) {
74 return true;
75 }
76
77 DHLOGE("Param error, codec type %d, channel count %d, sample rate %d, sample format %d.",
78 codecParam.codecType, codecParam.channelMask, codecParam.sampleRate, codecParam.bitFormat);
79 return false;
80 }
81
InitAudioEncoder(const AudioCommonParam & codecParam)82 int32_t AudioEncoder::InitAudioEncoder(const AudioCommonParam &codecParam)
83 {
84 DHLOGI("Init audio encoder.");
85 audioEncoder_ = Media::AudioEncoderFactory::CreateByMime(ENCODE_MIME_AAC);
86 if (audioEncoder_ == nullptr) {
87 DHLOGE("Create audio encoder fail.");
88 return ERR_DH_AUDIO_CODEC_CONFIG;
89 }
90
91 encoderCallback_ = std::make_shared<AudioEncoderCallback>(shared_from_this());
92 int32_t ret = audioEncoder_->SetCallback(encoderCallback_);
93 if (ret != Media::MediaServiceErrCode::MSERR_OK) {
94 DHLOGE("Set encoder callback fail. Error code %d.", ret);
95 encoderCallback_ = nullptr;
96 return ERR_DH_AUDIO_CODEC_CONFIG;
97 }
98 return DH_SUCCESS;
99 }
100
SetEncoderFormat(const AudioCommonParam & codecParam)101 int32_t AudioEncoder::SetEncoderFormat(const AudioCommonParam &codecParam)
102 {
103 if (audioEncoder_ == nullptr) {
104 DHLOGE("Encoder is null.");
105 return ERR_DH_AUDIO_BAD_VALUE;
106 }
107
108 DHLOGI("Set encoder format, codec type %d, channel count %d, sample rate %d, sample format %d.",
109 codecParam.codecType, codecParam.channelMask, codecParam.sampleRate, codecParam.bitFormat);
110 cfgFormat_.PutIntValue("channel_count", codecParam.channelMask);
111 cfgFormat_.PutIntValue("sample_rate", codecParam.sampleRate);
112 cfgFormat_.PutIntValue("audio_sample_format",
113 static_cast<AudioStandard::AudioSampleFormat>(codecParam.bitFormat));
114
115 int32_t ret = audioEncoder_->Configure(cfgFormat_);
116 if (ret != Media::MSERR_OK) {
117 DHLOGE("Configure encoder format fail. Error code %d.", ret);
118 return ERR_DH_AUDIO_CODEC_CONFIG;
119 }
120
121 ret = audioEncoder_->Prepare();
122 if (ret != Media::MediaServiceErrCode::MSERR_OK) {
123 DHLOGE("Encoder prepare fail. Error code %d.", ret);
124 return ERR_DH_AUDIO_CODEC_CONFIG;
125 }
126 return DH_SUCCESS;
127 }
128
ReleaseAudioCodec()129 int32_t AudioEncoder::ReleaseAudioCodec()
130 {
131 DHLOGI("Release audio codec.");
132 if (audioEncoder_ == nullptr) {
133 DHLOGE("Encoder is null.");
134 return DH_SUCCESS;
135 }
136
137 int32_t ret = audioEncoder_->Release();
138 if (ret != Media::MediaServiceErrCode::MSERR_OK) {
139 DHLOGE("Encoder release fail. Error type: %d.", ret);
140 return ERR_DH_AUDIO_CODEC_RELEASE;
141 }
142 encoderCallback_ = nullptr;
143 audioEncoder_ = nullptr;
144 DHLOGI("Release audio codec end.");
145 return DH_SUCCESS;
146 }
147
StartAudioCodec()148 int32_t AudioEncoder::StartAudioCodec()
149 {
150 DHLOGI("Start audio codec.");
151 if (audioEncoder_ == nullptr) {
152 DHLOGE("Encoder is null.");
153 return ERR_DH_AUDIO_BAD_VALUE;
154 }
155
156 int32_t ret = audioEncoder_->Start();
157 if (ret != Media::MediaServiceErrCode::MSERR_OK) {
158 DHLOGE("Encoder start fail. Error code %d.", ret);
159 return ERR_DH_AUDIO_CODEC_START;
160 }
161 StartInputThread();
162 return DH_SUCCESS;
163 }
164
StartInputThread()165 void AudioEncoder::StartInputThread()
166 {
167 DHLOGI("Start input thread.");
168 isEncoderRunning_.store(true);
169 encodeThread_ = std::thread(&AudioEncoder::InputEncodeAudioData, this);
170 if (pthread_setname_np(encodeThread_.native_handle(), ENCODE_THREAD) != DH_SUCCESS) {
171 DHLOGE("Encode thread setname failed.");
172 }
173 }
174
StopAudioCodec()175 int32_t AudioEncoder::StopAudioCodec()
176 {
177 DHLOGI("Stop audio codec.");
178 StopInputThread();
179 if (audioEncoder_ == nullptr) {
180 DHLOGE("Encoder is null.");
181 return DH_SUCCESS;
182 }
183
184 bool isSuccess = true;
185 int32_t ret = audioEncoder_->Flush();
186 if (ret != Media::MediaServiceErrCode::MSERR_OK) {
187 DHLOGE("Encoder flush fail. Error type: %d.", ret);
188 isSuccess = false;
189 }
190 ret = audioEncoder_->Stop();
191 if (ret != Media::MediaServiceErrCode::MSERR_OK) {
192 DHLOGE("Encoder stop fail. Error type: %d.", ret);
193 isSuccess = false;
194 }
195 if (!isSuccess) {
196 return ERR_DH_AUDIO_CODEC_STOP;
197 }
198
199 firstInputTimeUs_ = 0;
200 inputTimeStampUs_ = 0;
201 outputTimeStampUs_ = 0;
202 waitOutputCount_ = 0;
203 DHLOGI("Stop audio codec end.");
204 return DH_SUCCESS;
205 }
206
StopInputThread()207 void AudioEncoder::StopInputThread()
208 {
209 isEncoderRunning_.store(false);
210 encodeCond_.notify_all();
211 if (encodeThread_.joinable()) {
212 encodeThread_.join();
213 }
214
215 std::lock_guard<std::mutex> dataLock(mtxData_);
216 std::queue<uint32_t>().swap(bufIndexQueue_);
217 std::queue<std::shared_ptr<AudioData>>().swap(inputBufQueue_);
218 DHLOGI("Stop input thread success.");
219 }
220
FeedAudioData(const std::shared_ptr<AudioData> & inputData)221 int32_t AudioEncoder::FeedAudioData(const std::shared_ptr<AudioData> &inputData)
222 {
223 DHLOGD("Feed audio data.");
224 if (!isEncoderRunning_.load()) {
225 DHLOGE("Encoder is stopped.");
226 return ERR_DH_AUDIO_CODEC_INPUT;
227 }
228 if (inputData == nullptr) {
229 DHLOGE("Input data is null.");
230 return ERR_DH_AUDIO_BAD_VALUE;
231 }
232
233 std::lock_guard<std::mutex> dataLock(mtxData_);
234 while (inputBufQueue_.size() > AUDIO_ENCODER_QUEUE_MAX) {
235 DHLOGE("Input data queue overflow.");
236 inputBufQueue_.pop();
237 }
238 inputBufQueue_.push(inputData);
239 encodeCond_.notify_all();
240
241 return DH_SUCCESS;
242 }
243
InputEncodeAudioData()244 void AudioEncoder::InputEncodeAudioData()
245 {
246 DHLOGI("Input encode audio data thread start.");
247 while (isEncoderRunning_.load()) {
248 std::shared_ptr<AudioData> audioData;
249 int32_t bufferIndex = 0;
250 {
251 std::unique_lock<std::mutex> lock(mtxData_);
252 encodeCond_.wait_for(lock, std::chrono::milliseconds(ENCODE_WAIT_MILLISECONDS),
253 [this]() {
254 return (!inputBufQueue_.empty() && !bufIndexQueue_.empty()) || !isEncoderRunning_.load();
255 });
256
257 if (inputBufQueue_.empty() || bufIndexQueue_.empty()) {
258 continue;
259 }
260 bufferIndex = (int32_t)bufIndexQueue_.front();
261 bufIndexQueue_.pop();
262 audioData = inputBufQueue_.front();
263 inputBufQueue_.pop();
264 }
265
266 int32_t ret = ProcessData(audioData, bufferIndex);
267 if (ret == ERR_DH_AUDIO_BAD_VALUE) {
268 DHLOGE("Encoder is stopped or null.");
269 return;
270 } else if (ret != DH_SUCCESS) {
271 DHLOGE("Process data fail. Error type: %d.", ret);
272 continue;
273 }
274 }
275 }
276
ProcessData(const std::shared_ptr<AudioData> & audioData,const int32_t bufferIndex)277 int32_t AudioEncoder::ProcessData(const std::shared_ptr<AudioData> &audioData, const int32_t bufferIndex)
278 {
279 if (!isEncoderRunning_.load() || audioEncoder_ == nullptr) {
280 DHLOGE("Encoder is stopped or null, isRunning %d.", isEncoderRunning_.load());
281 return ERR_DH_AUDIO_BAD_VALUE;
282 }
283
284 auto inMem = audioEncoder_->GetInputBuffer(bufferIndex);
285 if (inMem == nullptr) {
286 DHLOGE("Get input buffer fail.");
287 return ERR_DH_AUDIO_CODEC_INPUT;
288 }
289 if (inMem->GetSize() == INVALID_MEMORY_SIZE || static_cast<size_t>(inMem->GetSize()) < audioData->Size()) {
290 DHLOGE("Input buffer size error. Memory size %d, data size %zu.",
291 inMem->GetSize(), audioData->Size());
292 return ERR_DH_AUDIO_CODEC_INPUT;
293 }
294
295 errno_t err = memcpy_s(inMem->GetBase(), inMem->GetSize(), audioData->Data(), audioData->Size());
296 if (err != EOK) {
297 DHLOGE("Copy input data fail. Error code %d. Memory size %d, data size %zu.",
298 err, inMem->GetSize(), audioData->Size());
299 return ERR_DH_AUDIO_BAD_OPERATE;
300 }
301
302 inputTimeStampUs_ = GetEncoderTimeStamp();
303 Media::AVCodecBufferInfo bufferInfo = {inputTimeStampUs_, static_cast<int32_t>(audioData->Size()), 0};
304 DHLOGD("Queue input buffer. AVCodec info: input time stamp %lld, data size %zu.",
305 (long long)bufferInfo.presentationTimeUs, audioData->Size());
306 int32_t ret = audioEncoder_->QueueInputBuffer(bufferIndex, bufferInfo, Media::AVCODEC_BUFFER_FLAG_NONE);
307 if (ret != Media::MSERR_OK) {
308 DHLOGE("Queue input buffer fail. Error code %d.", ret);
309 return ERR_DH_AUDIO_CODEC_INPUT;
310 }
311
312 IncreaseWaitEncodeCnt();
313 return DH_SUCCESS;
314 }
315
GetEncoderTimeStamp()316 int64_t AudioEncoder::GetEncoderTimeStamp()
317 {
318 int64_t TimeIntervalStampUs = 0;
319 int64_t nowTimeUs = GetNowTimeUs();
320 if (firstInputTimeUs_ == 0) {
321 firstInputTimeUs_ = nowTimeUs;
322 return TimeIntervalStampUs;
323 }
324
325 TimeIntervalStampUs = nowTimeUs - firstInputTimeUs_;
326 return TimeIntervalStampUs;
327 }
328
IncreaseWaitEncodeCnt()329 void AudioEncoder::IncreaseWaitEncodeCnt()
330 {
331 std::lock_guard<std::mutex> lck(mtxCnt_);
332 waitOutputCount_++;
333 DHLOGD("Wait encoder output frames number is %d.", waitOutputCount_);
334 }
335
ReduceWaitEncodeCnt()336 void AudioEncoder::ReduceWaitEncodeCnt()
337 {
338 std::lock_guard<std::mutex> lck(mtxCnt_);
339 if (waitOutputCount_ <= 0) {
340 DHLOGE("Wait encoder output count %d.", waitOutputCount_);
341 }
342 waitOutputCount_--;
343 DHLOGD("Wait encoder output frames number is %d.", waitOutputCount_);
344 }
345
OnInputBufferAvailable(uint32_t index)346 void AudioEncoder::OnInputBufferAvailable(uint32_t index)
347 {
348 std::lock_guard<std::mutex> lck(mtxData_);
349 while (bufIndexQueue_.size() > AUDIO_ENCODER_QUEUE_MAX) {
350 DHLOGE("Index queue overflow.");
351 bufIndexQueue_.pop();
352 }
353
354 bufIndexQueue_.push(index);
355 encodeCond_.notify_all();
356 }
357
OnOutputBufferAvailable(uint32_t index,Media::AVCodecBufferInfo info,Media::AVCodecBufferFlag flag)358 void AudioEncoder::OnOutputBufferAvailable(uint32_t index, Media::AVCodecBufferInfo info,
359 Media::AVCodecBufferFlag flag)
360 {
361 if (!isEncoderRunning_.load() || audioEncoder_ == nullptr) {
362 DHLOGE("Encoder is stopped or null, isRunning %d.", isEncoderRunning_.load());
363 return;
364 }
365
366 auto outMem = audioEncoder_->GetOutputBuffer(index);
367 if (outMem == nullptr) {
368 DHLOGE("Get output buffer fail. index %u.", index);
369 return;
370 }
371 if (info.size <= 0 || info.size > outMem->GetSize()) {
372 DHLOGE("Codec output info error. AVCodec info: size %d, memory size %d.",
373 info.size, outMem->GetSize());
374 return;
375 }
376
377 auto outBuf = std::make_shared<AudioData>(static_cast<size_t>(info.size));
378 errno_t err = memcpy_s(outBuf->Data(), outBuf->Size(), outMem->GetBase(), info.size);
379 if (err != EOK) {
380 DHLOGE("Copy output data fail. Error code %d. Output Buffer Size %zu, AVCodec info: size %d.",
381 err, outBuf->Size(), info.size);
382 return;
383 }
384 outBuf->SetInt64("timeUs", info.presentationTimeUs);
385 outputTimeStampUs_ = info.presentationTimeUs;
386 DHLOGD("Get output buffer. AVCodec info: output time stamp %lld, data size %zu.",
387 (long long)info.presentationTimeUs, outBuf->Size());
388
389 ReduceWaitEncodeCnt();
390 err = EncodeDone(outBuf);
391 if (err != DH_SUCCESS) {
392 DHLOGE("Encode done fail. Error code: %d.", err);
393 return;
394 }
395
396 err = audioEncoder_->ReleaseOutputBuffer(index);
397 if (err != Media::MediaServiceErrCode::MSERR_OK) {
398 DHLOGE("Release output buffer fail. Error code: %d, index %u.", err, index);
399 }
400 }
401
OnOutputFormatChanged(const Media::Format & format)402 void AudioEncoder::OnOutputFormatChanged(const Media::Format &format)
403 {
404 if (format.GetFormatMap().empty()) {
405 DHLOGE("The first changed output data format is null.");
406 return;
407 }
408 outputFormat_ = format;
409 }
410
OnError(const AudioEvent & event)411 void AudioEncoder::OnError(const AudioEvent &event)
412 {
413 DHLOGE("Encoder error.");
414 std::shared_ptr<IAudioCodecCallback> cbObj = codecCallback_.lock();
415 if (cbObj == nullptr) {
416 DHLOGE("Codec callback is null.");
417 return;
418 }
419 cbObj->OnCodecStateNotify(event);
420 }
421
EncodeDone(const std::shared_ptr<AudioData> & outputData)422 int32_t AudioEncoder::EncodeDone(const std::shared_ptr<AudioData> &outputData)
423 {
424 DHLOGD("Encode done.");
425 std::shared_ptr<IAudioCodecCallback> cbObj = codecCallback_.lock();
426 if (cbObj == nullptr) {
427 DHLOGE("Codec callback is null.");
428 return ERR_DH_AUDIO_BAD_VALUE;
429 }
430 cbObj->OnCodecDataDone(outputData);
431 return DH_SUCCESS;
432 }
433 } // namespace DistributedHardware
434 } // namespace OHOS
435