1/*
2 * Copyright (c) 2020-2021 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_capturer_impl.h"
17
18#include <sys/select.h>
19
20#include "audio_source.h"
21#include "audio_encoder.h"
22#include "media_log.h"
23
24namespace OHOS {
25namespace Audio {
26using namespace OHOS::Media;
27
28const uint64_t TIME_CONVERSION_US_S = 1000000; /* us to s */
29const uint64_t TIME_CONVERSION_NS_US = 1000; /* ns  to us  */
30
31#define CHK_NULL_RETURN(ptr, ret) \
32    do { \
33        if ((ptr) == nullptr) { \
34            MEDIA_ERR_LOG("ptr null"); \
35            return (ret); \
36        } \
37    } while (0)
38
39AudioCapturerImpl::AudioCapturerImpl()
40    :audioSource_(new(std::nothrow) AudioSource()),
41     audioEncoder_(nullptr)
42{
43    MEDIA_DEBUG_LOG("ctor");
44}
45
46AudioCapturerImpl::~AudioCapturerImpl()
47{
48    if (status_ != RELEASED) {
49        Release();
50    }
51    MEDIA_ERR_LOG("dtor");
52}
53
54bool AudioCapturerImpl::GetMinFrameCount(int32_t sampleRate, int32_t channelCount, AudioCodecFormat audioFormat,
55    size_t &frameCount)
56{
57    return AudioSource::GetMinFrameCount(sampleRate, channelCount, audioFormat, frameCount);
58}
59
60uint64_t AudioCapturerImpl::GetFrameCount()
61{
62    CHK_NULL_RETURN(audioSource_, 0);
63    std::lock_guard<std::mutex> lock(mutex_);
64    if (status_ == INITIALIZED || status_ == RELEASED) {
65        MEDIA_ERR_LOG("check state:%u failed", status_);
66        return 0;
67    }
68    return audioSource_->GetFrameCount();
69}
70
71State AudioCapturerImpl::GetStatus()
72{
73    std::lock_guard<std::mutex> lock(mutex_);
74    return status_;
75}
76
77bool AudioCapturerImpl::GetTimestamp(Timestamp &timestamp, Timestamp::Timebase base)
78{
79    std::lock_guard<std::mutex> lock(mutex_);
80    if (status_ == RELEASED) {
81        MEDIA_ERR_LOG("check state:%u failed", status_);
82        return false;
83    }
84    timestamp = timestamp_;
85    return true;
86}
87
88static void FillSourceConfig(AudioSourceConfig &sourceConfig, const AudioCapturerInfo &info, uint32_t deviceId)
89{
90    sourceConfig.deviceId = deviceId;
91    sourceConfig.audioFormat = info.audioFormat;
92    sourceConfig.sampleRate = info.sampleRate;
93    sourceConfig.channelCount = info.channelCount;
94    sourceConfig.interleaved = false;
95    sourceConfig.bitWidth = info.bitWidth;
96    sourceConfig.streamUsage = info.streamType;
97}
98
99static void FillEncConfig(AudioEncodeConfig &encodeConfig, const AudioCapturerInfo &info)
100{
101    encodeConfig.audioFormat = info.audioFormat;
102    encodeConfig.bitRate = info.bitRate;
103    encodeConfig.sampleRate = info.sampleRate;
104    encodeConfig.channelCount = info.channelCount;
105    encodeConfig.bitWidth = info.bitWidth;
106}
107
108int32_t AudioCapturerImpl::SetCapturerInfo(const AudioCapturerInfo info)
109{
110    CHK_NULL_RETURN(audioSource_, ERROR);
111    std::lock_guard<std::mutex> lock(mutex_);
112    if (status_ != INITIALIZED) {
113        MEDIA_ERR_LOG("check state:%u failed", status_);
114        return ERR_ILLEGAL_STATE;
115    }
116    std::vector<AudioDeviceDesc> devices;
117    int32_t ret = audioSource_->EnumDeviceBySourceType(info.inputSource, devices);
118    if (ret != SUCCESS || devices.empty()) {
119        MEDIA_ERR_LOG("EnumDeviceBySourceType failed inputSource:%d", info.inputSource);
120        return ret;
121    }
122    MEDIA_INFO_LOG("info.sampleRate:%d", info.sampleRate);
123    AudioSourceConfig sourceConfig;
124    FillSourceConfig(sourceConfig, info, devices[0].deviceId);
125    ret = audioSource_->Initialize(sourceConfig);
126    if (ret != SUCCESS) {
127        MEDIA_ERR_LOG("Initialize failed inputSource:%d", info.inputSource);
128        return ret;
129    }
130    if (info.audioFormat != PCM && info.audioFormat != AUDIO_DEFAULT) {
131        AudioEncodeConfig encodeConfig;
132        FillEncConfig(encodeConfig, info);
133        MEDIA_INFO_LOG("audioEncoder_ bitRate:%d", info.bitRate);
134        std::unique_ptr<AudioEncoder> audioEncoder(new(std::nothrow) AudioEncoder());
135        audioEncoder_ = std::move(audioEncoder);
136        if (audioEncoder_ == nullptr) {
137            MEDIA_ERR_LOG("new AudioEncoder failed inputSource:%d", info.inputSource);
138            return ERR_UNKNOWN;
139        }
140        ret = audioEncoder_->Initialize(encodeConfig);
141        if (ret != SUCCESS) {
142            MEDIA_ERR_LOG("Initialize failed inputSource:%d", info.inputSource);
143            (void)audioSource_->Release();
144            return ret;
145        }
146    }
147    info_ = info;
148    status_ = PREPARED;
149    MEDIA_INFO_LOG("Set Capturer Info SUCCESS");
150    return SUCCESS;
151}
152
153int32_t AudioCapturerImpl::GetCapturerInfo(AudioCapturerInfo &info)
154{
155    std::lock_guard<std::mutex> lock(mutex_);
156    if (status_ == RELEASED) {
157        MEDIA_ERR_LOG("check state:%u failed", status_);
158        return ERR_INVALID_OPERATION;
159    }
160    info = info_;
161    return SUCCESS;
162}
163
164bool AudioCapturerImpl::Record()
165{
166    CHK_NULL_RETURN(audioSource_, false);
167    std::lock_guard<std::mutex> lock(mutex_);
168    if (status_ != PREPARED && status_ != STOPPED) {
169        MEDIA_ERR_LOG("not PREPARED or STOPPED status:%u", status_);
170        return false;
171    }
172    int32_t ret = audioSource_->Start();
173    if (ret != SUCCESS) {
174        MEDIA_ERR_LOG("audioSource_ Start failed:0x%x", ret);
175        return false;
176    }
177    if (audioEncoder_ != nullptr) {
178        uint32_t deviceId = 0;
179        ret = audioSource_->GetCurrentDeviceId(deviceId);
180        if (ret != SUCCESS) {
181            MEDIA_ERR_LOG("audioSource_ GetCurrentDevice failed:0x%x", ret);
182            return false;
183        }
184        inputDeviceId_ = deviceId;
185        ret = audioEncoder_->BindSource(deviceId);
186        if (ret != SUCCESS) {
187            MEDIA_ERR_LOG("audioEncoder_ BindSource failed:0x%x", ret);
188            return false;
189        }
190        ret = audioEncoder_->Start();
191        if (ret != SUCCESS) {
192            MEDIA_ERR_LOG("audioEncoder_ Start failed:0x%x", ret);
193            return false;
194        }
195    }
196    status_ = RECORDING;
197    MEDIA_INFO_LOG("Start Audio Capturer SUCCESS");
198    return true;
199}
200
201int32_t AudioCapturerImpl::Read(uint8_t *buffer, size_t userSize, bool isBlockingRead)
202{
203    if (buffer == nullptr || !userSize) {
204        MEDIA_ERR_LOG("Invalid buffer or userSize:%u", userSize);
205        return ERR_INVALID_READ;
206    }
207    CHK_NULL_RETURN(audioSource_, ERROR);
208
209    if (status_ != RECORDING) {
210        MEDIA_ERR_LOG("ILLEGAL_STATE  status_:%u", status_);
211        return ERR_INVALID_READ;
212    }
213    int32_t readLen = ERR_INVALID_READ;
214    if (info_.audioFormat == PCM || info_.audioFormat == AUDIO_DEFAULT) {
215        AudioFrame frame;
216        frame.buffer = buffer;
217        frame.bufferLen = userSize;
218        readLen = audioSource_->ReadFrame(frame, isBlockingRead);
219        if (readLen == ERR_INVALID_READ) {
220            MEDIA_ERR_LOG("audioSource_ ReadFrame fail,ret:0x%x", readLen);
221            return ERR_INVALID_READ;
222        }
223        timestamp_.time.tv_sec = frame.time.tvSec;
224        timestamp_.time.tv_nsec = frame.time.tvNSec;
225    } else {
226        AudioStream stream;
227        stream.buffer = buffer;
228        stream.bufferLen = userSize;
229
230        if (audioEncoder_ == nullptr) {
231            MEDIA_ERR_LOG("audioEncoder_ ReadStream fail, audioEncoder_ value is nullptr");
232            return ERR_INVALID_READ;
233        }
234
235        readLen = audioEncoder_->ReadStream(stream, isBlockingRead);
236        if (readLen == ERR_INVALID_READ) {
237            MEDIA_ERR_LOG("audioEncoder_ ReadStream fail,ret:0x%x", readLen);
238            return ERR_INVALID_READ;
239        }
240        timestamp_.time.tv_sec = static_cast<time_t>(stream.timeStamp / TIME_CONVERSION_US_S);
241        timestamp_.time.tv_nsec = static_cast<time_t>((stream.timeStamp -
242            timestamp_.time.tv_sec * TIME_CONVERSION_US_S) * TIME_CONVERSION_NS_US);
243    }
244    return readLen;
245}
246
247bool AudioCapturerImpl::StopInternal()
248{
249    CHK_NULL_RETURN(audioSource_, false);
250    int32_t ret;
251    if (audioEncoder_ != nullptr) {
252        MEDIA_INFO_LOG("audioEncoder Stop");
253        ret = audioEncoder_->Stop();
254        if (ret != SUCCESS) {
255            MEDIA_DEBUG_LOG("audioEncoder_ stop fail,ret:0x%x", ret);
256            return false;
257        }
258    }
259    MEDIA_INFO_LOG("audioSource Stop");
260    ret = audioSource_->Stop();
261    if (ret != SUCCESS) {
262        MEDIA_ERR_LOG("audioSource_ stop fail,ret:0x%x", ret);
263        return false;
264    }
265    MEDIA_INFO_LOG("Stop Audio Capturer SUCCESS");
266    status_ = STOPPED;
267    return true;
268}
269
270bool AudioCapturerImpl::Stop()
271{
272    std::lock_guard<std::mutex> lock(mutex_);
273    if (status_ != RECORDING) {
274        MEDIA_ERR_LOG("not RECORDING status:%u", status_);
275        return false;
276    }
277    return StopInternal();
278}
279
280bool AudioCapturerImpl::Release()
281{
282    std::lock_guard<std::mutex> lock(mutex_);
283    if (status_ == RELEASED) {
284        MEDIA_ERR_LOG("ILLEGAL_STATE status_:%u", status_);
285        return false;
286    }
287    if (status_ == INITIALIZED) {
288        status_ = RELEASED;
289        return true;
290    }
291    if (status_ == RECORDING) {
292        if (!StopInternal()) {
293            MEDIA_ERR_LOG("StopInternal err");
294            return false;
295        }
296    }
297    int32_t ret;
298    if (audioEncoder_ != nullptr) {
299        ret = audioEncoder_->Release();
300        if (ret != SUCCESS) {
301            MEDIA_ERR_LOG("audioEncoder_ Release failed:0x%x", ret);
302            return false;
303        }
304    }
305    ret = (audioSource_ != nullptr) ? audioSource_->Release() : SUCCESS;
306    if (ret != SUCCESS) {
307        MEDIA_ERR_LOG("audioSource_ Release failed:0x%x", ret);
308        return false;
309    }
310    status_ = RELEASED;
311    MEDIA_INFO_LOG("Release Audio Capturer SUCCESS");
312    return true;
313}
314}  // namespace Audio
315}  // namespace OHOS
316