1 /*
2  * Copyright (c) 2024 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 #include "wakeup_source_process.h"
16 #include "intell_voice_log.h"
17 
18 #define LOG_TAG "WakeupSourceProc"
19 
20 using namespace OHOS::IntellVoiceUtils;
21 
22 namespace OHOS {
23 namespace IntellVoiceEngine {
24 static constexpr uint32_t WAIT_TIME = 1000;  // 1000ms
25 static constexpr uint32_t CHANNEL_CNT_1 = 1;
26 static constexpr uint32_t CHANNEL_CNT_4 = 4;
27 static constexpr uint32_t MAX_CHANNEL_CNT = 4;
28 static const std::string WRITE_SOURCE = "_write_source";
29 static const std::string READ_SOURCE = "_read_source";
30 
~WakeupSourceProcess()31 WakeupSourceProcess::~WakeupSourceProcess()
32 {
33     Release();
34 }
35 
Init(uint32_t channelCnt)36 void WakeupSourceProcess::Init(uint32_t channelCnt)
37 {
38     if (channelCnt_ != 0) {
39         INTELL_VOICE_LOG_WARN("need to release before init, channel cnt:%{public}u", channelCnt_);
40         Release();
41     }
42     for (uint32_t i = 0; i < channelCnt; i++) {
43         auto queue = std::make_unique<Uint8ArrayBufferQueue>();
44         if (queue == nullptr) {
45             INTELL_VOICE_LOG_ERROR("failed to create buffer queue");
46             return;
47         }
48         queue->Init();
49         bufferQueue_.push_back(std::move(queue));
50     }
51     channelCnt_ = channelCnt;
52     InitDebugFile(channelCnt);
53 }
54 
Write(const std::vector<std::vector<uint8_t>> & audioData)55 void WakeupSourceProcess::Write(const std::vector<std::vector<uint8_t>> &audioData)
56 {
57     if ((static_cast<uint32_t>(audioData.size()) != channelCnt_) ||
58         (static_cast<uint32_t>(bufferQueue_.size()) != channelCnt_)) {
59         INTELL_VOICE_LOG_ERROR("data size:%{public}u, queue size:%{public}u, channel cnt:%{public}u",
60             static_cast<uint32_t>(audioData.size()), static_cast<uint32_t>(bufferQueue_.size()), channelCnt_);
61         return;
62     }
63 
64     if (channelCnt_ == CHANNEL_CNT_1) {
65         WriteChannelData(audioData[CHANNEL_ID_0], CHANNEL_ID_0);
66     } else if (channelCnt_ == CHANNEL_CNT_4) {
67         WriteChannelData(audioData[CHANNEL_ID_0], CHANNEL_ID_0);
68         WriteChannelData(audioData[CHANNEL_ID_1], CHANNEL_ID_1);
69         WriteChannelData(audioData[CHANNEL_ID_2], CHANNEL_ID_2);
70         WriteChannelData(audioData[CHANNEL_ID_3], CHANNEL_ID_3);
71     } else {
72         INTELL_VOICE_LOG_WARN("not support channel cnt:%{public}u", channelCnt_);
73     }
74 }
75 
Read(std::vector<uint8_t> & data,int32_t readChannel)76 int32_t WakeupSourceProcess::Read(std::vector<uint8_t> &data, int32_t readChannel)
77 {
78     INTELL_VOICE_LOG_INFO("enter, read channel:%{public}d", readChannel);
79     if ((readChannel == 0) || (readChannel >= (0x1 << MAX_CHANNEL_CNT))) {
80         return -1;
81     }
82 
83     for (uint32_t i = 0; i < CHANNEL_CNT_4; i++) {
84         if (!(readChannel & (0x1 << i))) {
85             continue;
86         }
87         if (!ReadChannelData(data, i)) {
88             return -1;
89         }
90     }
91 
92     return 0;
93 }
94 
Release()95 void WakeupSourceProcess::Release()
96 {
97     for (auto &queue : bufferQueue_) {
98         queue ->Uninit();
99     }
100     std::vector<std::unique_ptr<Uint8ArrayBufferQueue>>().swap(bufferQueue_);
101     ReleaseDebugFile();
102     channelCnt_ = 0;
103 }
104 
WriteChannelData(const std::vector<uint8_t> & channelData,uint32_t channelId)105 void WakeupSourceProcess::WriteChannelData(const std::vector<uint8_t> &channelData, uint32_t channelId)
106 {
107     if ((channelId >= bufferQueue_.size()) || (bufferQueue_[channelId] == nullptr)) {
108         INTELL_VOICE_LOG_ERROR("no buffer queue, channel id:%{public}d", channelId);
109         return;
110     }
111 
112     auto arrayBuffer = CreateArrayBuffer<uint8_t>(channelData.size(), &channelData[0]);
113     if (arrayBuffer == nullptr) {
114         INTELL_VOICE_LOG_ERROR("failed to create array buffer");
115         return;
116     }
117     if (!bufferQueue_[channelId]->Push(std::move(arrayBuffer), false)) {
118         INTELL_VOICE_LOG_ERROR("failed to push array buffer");
119         return;
120     }
121 
122     WriteDebugData(writeDebug_, channelData, channelId);
123 }
124 
ReadChannelData(std::vector<uint8_t> & channelData,uint32_t channelId)125 bool WakeupSourceProcess::ReadChannelData(std::vector<uint8_t> &channelData, uint32_t channelId)
126 {
127     if ((channelId >= bufferQueue_.size()) || (bufferQueue_[channelId] == nullptr)) {
128         INTELL_VOICE_LOG_ERROR("no buffer queue, channel id:%{public}d", channelId);
129         return false;
130     }
131 
132     std::unique_ptr<Uint8ArrayBuffer> arrayBuffer = nullptr;
133     bufferQueue_[channelId]->PopUntilTimeout(WAIT_TIME, arrayBuffer);
134     if (arrayBuffer == nullptr) {
135         INTELL_VOICE_LOG_ERROR("failed to pop data");
136         return false;
137     }
138 
139     channelData.insert(channelData.end(), arrayBuffer->GetData(), arrayBuffer->GetData() + arrayBuffer->GetSize());
140     WriteDebugData(readDebug_, channelData, channelId);
141     return true;
142 }
143 
InitDebugFile(uint32_t channelCnt)144 void WakeupSourceProcess::InitDebugFile(uint32_t channelCnt)
145 {
146     for (uint32_t i = 0; i < channelCnt; i++) {
147         auto writeObj = std::make_shared<AudioDebug>();
148         auto readObj = std::make_shared<AudioDebug>();
149         if ((writeObj == nullptr) || (readObj == nullptr)) {
150             INTELL_VOICE_LOG_ERROR("failed to create audio debug obj");
151             return;
152         }
153 
154         writeObj->CreateAudioDebugFile(WRITE_SOURCE + std::to_string(i));
155         readObj->CreateAudioDebugFile(READ_SOURCE + std::to_string(i));
156         writeDebug_.emplace_back(writeObj);
157         readDebug_.emplace_back(readObj);
158     }
159 }
160 
WriteDebugData(const std::vector<std::shared_ptr<AudioDebug>> & debugVec,const std::vector<uint8_t> & channelData,uint32_t channelId)161 void WakeupSourceProcess::WriteDebugData(const std::vector<std::shared_ptr<AudioDebug>> &debugVec,
162     const std::vector<uint8_t> &channelData, uint32_t channelId)
163 {
164     if ((channelId >= debugVec.size()) || (debugVec[channelId] == nullptr)) {
165         INTELL_VOICE_LOG_ERROR("no debug obj, channel id:%{public}d", channelId);
166         return;
167     }
168 
169     debugVec[channelId]->WriteData(reinterpret_cast<const char *>(channelData.data()), channelData.size());
170 }
171 
ReleaseDebugFile()172 void WakeupSourceProcess::ReleaseDebugFile()
173 {
174     for (auto writeObj : writeDebug_) {
175         writeObj->DestroyAudioDebugFile();
176     }
177     for (auto readObj : readDebug_) {
178         readObj->DestroyAudioDebugFile();
179     }
180     writeDebug_.clear();
181     readDebug_.clear();
182 }
183 }
184 }
185