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