1 /*
2 * Copyright (c) 2024-2025 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 #ifndef LOG_TAG
16 #define LOG_TAG "AudioUsbManager"
17 #endif
18
19 #include <sstream>
20 #include <dirent.h>
21 #include <fstream>
22 #include "common_event_manager.h"
23 #include "common_event_support.h"
24 #include "usb_srv_client.h"
25 #include "audio_usb_manager.h"
26 #include "audio_policy_log.h"
27
28 namespace OHOS {
29 namespace AudioStandard {
30
31 using namespace USB;
32
ReadTextFile(const string & file)33 static string ReadTextFile(const string &file)
34 {
35 string ret;
36 ifstream fin;
37 fin.open(file.c_str(), ios::binary | ios::in);
38 if (fin) {
39 int val;
40 while ((val = fin.get()) != EOF) {
41 ret.push_back(static_cast<char>(val));
42 }
43 fin.close();
44 }
45 return ret;
46 }
47
FillSoundCard(const string & path,SoundCard & card)48 static void FillSoundCard(const string &path, SoundCard &card)
49 {
50 DIR *dir = opendir(path.c_str());
51 CHECK_AND_RETURN_RET(dir != nullptr,);
52 struct dirent *tmp;
53 while ((tmp = readdir(dir)) != nullptr) {
54 string file(tmp->d_name);
55 if (file == "usbbus") {
56 card.usbBus_ = ReadTextFile(path + "/" + file);
57 continue;
58 } else if (file.find("pcm", 0) == 0) {
59 if (file.back() == 'c') {
60 card.isCapturer_ = true;
61 } else if (file.back() == 'p') {
62 card.isPlayer_ = true;
63 }
64 }
65 }
66 closedir(dir);
67 }
68
Trim(const string & str)69 static string Trim(const string &str)
70 {
71 static const set<char> WHITE_SPACE{' ', '\r', '\n', '\t'};
72 size_t pos = 0;
73 size_t end = str.length();
74 for (; pos < end; pos++) {
75 if (WHITE_SPACE.find(str[pos]) == WHITE_SPACE.end()) {
76 break;
77 }
78 }
79 for (; end > pos; end--) {
80 if (WHITE_SPACE.find(str[end - 1]) == WHITE_SPACE.end()) {
81 break;
82 }
83 }
84 return str.substr(pos, end - pos);
85 }
86
GetUsbSoundCards()87 static vector<SoundCard> GetUsbSoundCards()
88 {
89 const string baseDir{"/proc/asound"};
90 const string card{"card"};
91 vector<SoundCard> soundCards;
92 DIR *dir = opendir(baseDir.c_str());
93 CHECK_AND_RETURN_RET(dir != nullptr, soundCards);
94 struct dirent *tmp;
95 int cardNum;
96 while ((tmp = readdir(dir)) != nullptr) {
97 string file(tmp->d_name);
98 if (file.length() <= card.length() || !(file.find(card, 0) == 0)) {continue;}
99 string cardNumStr = file.substr(card.length());
100 if (!StrToInt(cardNumStr, cardNum)) {continue;}
101 SoundCard card = {.cardNum_ = static_cast<uint32_t>(cardNum)};
102 FillSoundCard(baseDir + "/" + file, card);
103 if (card.usbBus_.empty()) {continue;}
104 soundCards.push_back(card);
105 }
106 closedir(dir);
107 return soundCards;
108 }
109
GetDeviceAddr(const SoundCard & card)110 static string GetDeviceAddr(const SoundCard &card)
111 {
112 ostringstream oss;
113 oss << "card=" << card.cardNum_ << ";device=0";
114 return oss.str();
115 }
116
GetUsbAddr(const SoundCard & card)117 static UsbAddr GetUsbAddr(const SoundCard &card)
118 {
119 size_t pos = card.usbBus_.find('/');
120 CHECK_AND_RETURN_RET_LOG(pos != string::npos, {}, "Error Parameter: card.usbbus");
121 int busNum, devAddr;
122 string busNumStr = Trim(card.usbBus_.substr(0, pos));
123 string devAddrStr = Trim(card.usbBus_.substr(pos + 1));
124 CHECK_AND_RETURN_RET_LOG(StrToInt(busNumStr, busNum) && StrToInt(devAddrStr, devAddr), {}, "StrToInt ERROR");
125 return {static_cast<uint8_t>(busNum), static_cast<uint8_t>(devAddr)};
126 }
127
IsAudioDevice(UsbDevice & usbDevice)128 static bool IsAudioDevice(UsbDevice &usbDevice)
129 {
130 for (auto &usbConfig : usbDevice.GetConfigs()) {
131 for (auto &usbInterface : usbConfig.GetInterfaces()) {
132 if (usbInterface.GetClass() == 1 && usbInterface.GetSubClass() == 1) {
133 return true;
134 }
135 }
136 }
137 return false;
138 }
139
SubscribeCommonEvent()140 static shared_ptr<AudioUsbManager::EventSubscriber> SubscribeCommonEvent()
141 {
142 EventFwk::MatchingSkills matchingSkills;
143 matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USB_DEVICE_ATTACHED);
144 matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USB_DEVICE_DETACHED);
145 EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills);
146 subscribeInfo.SetThreadMode(EventFwk::CommonEventSubscribeInfo::COMMON);
147 auto subscriber = make_shared<AudioUsbManager::EventSubscriber>(subscribeInfo);
148 auto ret = EventFwk::CommonEventManager::NewSubscribeCommonEvent(subscriber);
149 CHECK_AND_RETURN_RET_LOG(ret == ERR_OK, nullptr, "NewSubscribeCommonEvent Failed. ret=%{public}d", ret);
150 return subscriber;
151 }
152
EncUsbAddr(const string & src)153 string EncUsbAddr(const string &src)
154 {
155 const string head("card=");
156 auto pos = src.find(';', head.length());
157 CHECK_AND_RETURN_RET_LOG(pos != string::npos, "", "Illegal usb address");
158 auto num = src.substr(head.length(), pos - head.length());
159 return string("c**") + num + "**";
160 }
161
GetInstance()162 AudioUsbManager& AudioUsbManager::GetInstance()
163 {
164 static AudioUsbManager sAudioUsbManager;
165 return sAudioUsbManager;
166 }
167
Init(IDeviceStatusObserver * observer)168 void AudioUsbManager::Init(IDeviceStatusObserver *observer)
169 {
170 lock_guard<mutex> lock(mutex_);
171 if (!initialized_) {
172 #ifdef DETECT_SOUNDBOX
173 AUDIO_INFO_LOG("Entry. DETECT_SOUNDBOX=true");
174 #else
175 AUDIO_INFO_LOG("Entry. DETECT_SOUNDBOX=false");
176 #endif
177 observer_ = observer;
178 RefreshUsbAudioDevices();
179 initialized_ = true;
180 }
181 }
182
Deinit()183 void AudioUsbManager::Deinit()
184 {
185 lock_guard<mutex> lock(mutex_);
186 if (initialized_) {
187 observer_ = nullptr;
188 if (eventSubscriber_) {
189 EventFwk::CommonEventManager::NewUnSubscribeCommonEvent(eventSubscriber_);
190 eventSubscriber_.reset();
191 }
192 audioDevices_.clear();
193 soundCardMap_.clear();
194 initialized_ = false;
195 }
196 }
197
RefreshUsbAudioDevices()198 void AudioUsbManager::RefreshUsbAudioDevices()
199 {
200 auto devices = GetUsbAudioDevices();
201 vector<UsbAudioDevice> toAdd;
202 for (auto &device : devices) {
203 auto it = find_if(audioDevices_.cbegin(), audioDevices_.cend(), [&device](auto &item) {
204 return device.usbAddr_ == item.usbAddr_ && device.name_ == item.name_;
205 });
206 if (it == audioDevices_.cend()) {
207 toAdd.push_back(device);
208 }
209 }
210 CHECK_AND_RETURN_RET(!toAdd.empty(),);
211 soundCardMap_ = GetUsbSoundCardMap();
212 for (auto &device : toAdd) {
213 audioDevices_.push_back(device);
214 NotifyDevice(device, true);
215 }
216 }
217
SubscribeEvent()218 void AudioUsbManager::SubscribeEvent()
219 {
220 AUDIO_INFO_LOG("Entry");
221 CHECK_AND_RETURN_LOG(eventSubscriber_ == nullptr, "feventSubscriber_ already exists");
222 eventSubscriber_ = SubscribeCommonEvent();
223 lock_guard<mutex> lock(mutex_);
224 RefreshUsbAudioDevices();
225 }
226
GetPlayerDevices()227 vector<UsbAudioDevice> AudioUsbManager::GetPlayerDevices()
228 {
229 auto cardMap = GetUsbSoundCardMap();
230 vector<UsbAudioDevice> result;
231 for (auto &device : GetUsbAudioDevices()) {
232 auto card = cardMap.find(device.usbAddr_);
233 if (card != cardMap.end() && card->second.isPlayer_) {
234 result.push_back(device);
235 }
236 }
237 return result;
238 }
239
NotifyDevice(const UsbAudioDevice & device,const bool isConnected)240 void AudioUsbManager::NotifyDevice(const UsbAudioDevice &device, const bool isConnected)
241 {
242 CHECK_AND_RETURN_LOG(observer_ != nullptr, "observer_ is nullptr");
243 DeviceType devType = DeviceType::DEVICE_TYPE_USB_HEADSET;
244 auto it = soundCardMap_.find(device.usbAddr_);
245 CHECK_AND_RETURN_LOG(it != soundCardMap_.end(), "Error:No sound card matches usb device");
246 auto &card = it->second;
247 CHECK_AND_RETURN_LOG(card.isPlayer_ || card.isCapturer_, "Error:Sound card is not player and not capturer");
248 string macAddress = GetDeviceAddr(card);
249 AudioStreamInfo streamInfo{};
250 string deviceName = device.name_ + "-" + to_string(card.cardNum_);
251 if (card.isPlayer_) {
252 AUDIO_INFO_LOG("Call observer_->OnDeviceStatusUpdated. devType=%{public}d, isConnected=%{public}d, "
253 "macAddress=%{public}s, deviceName=%{public}s, role=%{public}d", devType, isConnected,
254 EncUsbAddr(macAddress).c_str(), deviceName.c_str(), DeviceRole::OUTPUT_DEVICE);
255 observer_->OnDeviceStatusUpdated(devType, isConnected, macAddress,
256 deviceName, streamInfo, OUTPUT_DEVICE, card.isCapturer_);
257 }
258 if (card.isCapturer_) {
259 AUDIO_INFO_LOG("Call observer_->OnDeviceStatusUpdated. devType=%{public}d, isConnected=%{public}d, "
260 "macAddress=%{public}s, deviceName=%{public}s, role=%{public}d", devType, isConnected,
261 EncUsbAddr(macAddress).c_str(), deviceName.c_str(), DeviceRole::INPUT_DEVICE);
262 observer_->OnDeviceStatusUpdated(devType, isConnected, macAddress,
263 deviceName, streamInfo, INPUT_DEVICE, card.isPlayer_);
264 }
265 }
266
GetCapturerDevices()267 vector<UsbAudioDevice> AudioUsbManager::GetCapturerDevices()
268 {
269 auto cardMap = GetUsbSoundCardMap();
270 vector<UsbAudioDevice> result;
271 for (auto &device : GetUsbAudioDevices()) {
272 auto card = cardMap.find(device.usbAddr_);
273 if (card != cardMap.end() && card->second.isCapturer_) {
274 result.push_back(device);
275 }
276 }
277 return result;
278 }
279
GetUsbSoundCardMap()280 map<UsbAddr, SoundCard> AudioUsbManager::GetUsbSoundCardMap()
281 {
282 map<UsbAddr, SoundCard> cardMap;
283 auto cardList = GetUsbSoundCards();
284 for (auto &card : cardList) {
285 cardMap[GetUsbAddr(card)] = card;
286 }
287 return cardMap;
288 }
289
GetUsbAudioDevices()290 vector<UsbAudioDevice> AudioUsbManager::GetUsbAudioDevices()
291 {
292 vector<UsbDevice> deviceList;
293 vector<UsbAudioDevice> result;
294 auto ret = UsbSrvClient::GetInstance().GetDevices(deviceList);
295 if (ret != ERR_OK) {
296 AUDIO_ERR_LOG("GetDevices failed. ret=%{public}d. size=%{public}zu", ret, deviceList.size());
297 return result;
298 }
299 for (auto &usbDevice : deviceList) {
300 if (IsAudioDevice(usbDevice)) {
301 result.push_back({
302 {usbDevice.GetBusNum(), usbDevice.GetDevAddr()},
303 usbDevice.GetProductName(),
304 });
305 }
306 }
307 return result;
308 }
309
HandleUsbAudioDeviceAttach(const UsbAudioDevice & device)310 void AudioUsbManager::HandleUsbAudioDeviceAttach(const UsbAudioDevice &device)
311 {
312 AUDIO_INFO_LOG("Entry. deviceName=%{public}s", device.name_.c_str());
313 lock_guard<mutex> lock(mutex_);
314 soundCardMap_ = GetUsbSoundCardMap();
315 auto it = find(audioDevices_.begin(), audioDevices_.end(), device);
316 if (it == audioDevices_.end()) {
317 audioDevices_.push_back(device);
318 } else {
319 *it = device;
320 }
321 NotifyDevice(device, true);
322 }
323
HandleUsbAudioDeviceDetach(const UsbAudioDevice & device)324 void AudioUsbManager::HandleUsbAudioDeviceDetach(const UsbAudioDevice &device)
325 {
326 AUDIO_INFO_LOG("Entry. deviceName=%{public}s", device.name_.c_str());
327 lock_guard<mutex> lock(mutex_);
328 NotifyDevice(device, false);
329 soundCardMap_.erase(device.usbAddr_);
330 auto it = find(audioDevices_.begin(), audioDevices_.end(), device);
331 if (it != audioDevices_.end()) {
332 audioDevices_.erase(it);
333 }
334 }
335
OnReceiveEvent(const EventFwk::CommonEventData & data)336 void AudioUsbManager::EventSubscriber::OnReceiveEvent(const EventFwk::CommonEventData &data)
337 {
338 string action = data.GetWant().GetAction();
339 AUDIO_INFO_LOG("OnReceiveEvent Entry. action=%{public}s", action.c_str());
340 string devStr;
341 bool isAttach{false};
342 if (action == EventFwk::CommonEventSupport::COMMON_EVENT_USB_DEVICE_ATTACHED) {
343 devStr = data.GetData();
344 isAttach = true;
345 } else if (action == EventFwk::CommonEventSupport::COMMON_EVENT_USB_DEVICE_DETACHED) {
346 devStr = data.GetData();
347 isAttach = false;
348 } else {
349 return;
350 }
351 if (devStr.empty()) {
352 AUDIO_ERR_LOG("Error: data.GetData() returns empty");
353 return;
354 }
355 auto devJson = cJSON_Parse(devStr.c_str());
356 if (devJson == nullptr) {
357 cJSON_Delete(devJson);
358 AUDIO_ERR_LOG("Create devJson error");
359 return;
360 }
361 UsbDevice usbDevice(devJson);
362 cJSON_Delete(devJson);
363 if (!IsAudioDevice(usbDevice)) {
364 return;
365 }
366 UsbAudioDevice device = {
367 {usbDevice.GetBusNum(), usbDevice.GetDevAddr()},
368 usbDevice.GetProductName()
369 };
370 if (isAttach) {
371 AudioUsbManager::GetInstance().HandleUsbAudioDeviceAttach(device);
372 } else {
373 AudioUsbManager::GetInstance().HandleUsbAudioDeviceDetach(device);
374 }
375 }
376
377 } // namespace AudioStandard
378 } // namespace OHOS