• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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