1 /*
2  * Copyright (c) 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 #ifndef LOG_TAG
16 #define LOG_TAG "AudioPnpServer"
17 #endif
18 
19 #include "audio_pnp_server.h"
20 
21 #include <poll.h>
22 #include "securec.h"
23 #include "osal_time.h"
24 #include "audio_utils.h"
25 #include "audio_errors.h"
26 #include "audio_input_thread.h"
27 #include "audio_policy_log.h"
28 #include "audio_socket_thread.h"
29 
30 using namespace std;
31 namespace OHOS {
32 namespace AudioStandard {
33 static bool g_socketRunThread = false;
34 static bool g_inputRunThread = false;
35 #ifdef AUDIO_DOUBLE_PNP_DETECT
36 AudioEvent g_usbHeadset = {0};
37 #endif
38 
GetAudioEventInfo(const AudioEvent audioEvent)39 static std::string GetAudioEventInfo(const AudioEvent audioEvent)
40 {
41     int32_t ret;
42     char event[AUDIO_PNP_INFO_LEN_MAX] = {0};
43     if (audioEvent.eventType == PNP_EVENT_UNKNOWN || audioEvent.deviceType == PNP_DEVICE_UNKNOWN) {
44         AUDIO_ERR_LOG("audio event is not updated");
45         return event;
46     }
47     ret = snprintf_s(event, AUDIO_PNP_INFO_LEN_MAX, AUDIO_PNP_INFO_LEN_MAX - 1,
48         "EVENT_TYPE=%u;DEVICE_TYPE=%u;EVENT_NAME=%s;DEVICE_ADDRESS=%s",
49         audioEvent.eventType, audioEvent.deviceType, audioEvent.name.c_str(), audioEvent.address.c_str());
50     if (ret < 0) {
51         AUDIO_ERR_LOG("snprintf_s failed");
52         return event;
53     }
54 
55     return event;
56 }
57 
~AudioPnpServer()58 AudioPnpServer::~AudioPnpServer()
59 {
60     AUDIO_INFO_LOG("~AudioPnpServer");
61     g_socketRunThread = false;
62     g_inputRunThread = false;
63 
64     if (socketThread_ && socketThread_->joinable()) {
65         socketThread_->detach();
66     }
67 
68     if (inputThread_ && inputThread_->joinable()) {
69         inputThread_->detach();
70     }
71 }
72 
init(void)73 bool AudioPnpServer::init(void)
74 {
75     AUDIO_INFO_LOG("Init");
76     g_socketRunThread = true;
77     g_inputRunThread = true;
78 
79     socketThread_ = std::make_unique<std::thread>([this] { this->OpenAndReadWithSocket(); });
80     pthread_setname_np(socketThread_->native_handle(), "OS_SocketEvent");
81     inputThread_ = std::make_unique<std::thread>([this] { this->OpenAndReadInput(); });
82     pthread_setname_np(inputThread_->native_handle(), "OS_InputEvent");
83     return true;
84 }
85 
RegisterPnpStatusListener(std::shared_ptr<AudioPnpDeviceChangeCallback> callback)86 int32_t AudioPnpServer::RegisterPnpStatusListener(std::shared_ptr<AudioPnpDeviceChangeCallback> callback)
87 {
88     AUDIO_INFO_LOG("Enter");
89     {
90         std::lock_guard<std::mutex> lock(pnpMutex_);
91         pnpCallback_ = callback;
92     }
93 
94     DetectAudioDevice();
95     return SUCCESS;
96 }
97 
UnRegisterPnpStatusListener()98 int32_t AudioPnpServer::UnRegisterPnpStatusListener()
99 {
100     std::lock_guard<std::mutex> lock(pnpMutex_);
101     pnpCallback_ = nullptr;
102     return SUCCESS;
103 }
104 
OnPnpDeviceStatusChanged(const std::string & info)105 void AudioPnpServer::OnPnpDeviceStatusChanged(const std::string &info)
106 {
107     std::lock_guard<std::mutex> lock(pnpMutex_);
108     if (pnpCallback_ != nullptr) {
109         pnpCallback_->OnPnpDeviceStatusChanged(info);
110     }
111 }
112 
OnMicrophoneBlocked(const std::string & info,AudioPnpServer & audioPnpServer)113 void MicrophoneBlocked::OnMicrophoneBlocked(const std::string &info, AudioPnpServer &audioPnpServer)
114 {
115     std::lock_guard<std::mutex> lock(audioPnpServer.pnpMutex_);
116     if (audioPnpServer.pnpCallback_ != nullptr) {
117         audioPnpServer.pnpCallback_->OnMicrophoneBlocked(info);
118     }
119 }
120 
OpenAndReadInput()121 void AudioPnpServer::OpenAndReadInput()
122 {
123     int32_t ret = -1;
124     int32_t status = AudioInputThread::AudioPnpInputOpen();
125     if (status != SUCCESS) {
126         return;
127     }
128 
129     do {
130         ret = AudioInputThread::AudioPnpInputPollAndRead();
131         if (ret != SUCCESS) {
132             AUDIO_ERR_LOG("[AudioPnpInputPollAndRead] failed");
133             return;
134         }
135         eventInfo_ = GetAudioEventInfo(AudioInputThread::audioInputEvent_);
136         CHECK_AND_RETURN_LOG(!eventInfo_.empty(), "invalid input info");
137         if (AudioSocketThread::audioSocketEvent_.eventType == PNP_EVENT_MIC_BLOCKED ||
138             AudioSocketThread::audioSocketEvent_.eventType == PNP_EVENT_MIC_UNBLOCKED) {
139             MicrophoneBlocked::GetInstance().OnMicrophoneBlocked(eventInfo_, GetAudioPnpServer());
140         } else {
141             OnPnpDeviceStatusChanged(eventInfo_);
142         }
143     } while (g_inputRunThread);
144     return;
145 }
146 
OpenAndReadWithSocket()147 void AudioPnpServer::OpenAndReadWithSocket()
148 {
149     ssize_t rcvLen;
150     int32_t socketFd = -1;
151     struct pollfd fd;
152     char msg[UEVENT_MSG_LEN + 1] = {0};
153 
154     int32_t ret = AudioSocketThread::AudioPnpUeventOpen(&socketFd);
155     if (ret != SUCCESS) {
156         AUDIO_ERR_LOG("open audio pnp socket failed");
157         return;
158     }
159 
160     fd.fd = socketFd;
161     fd.events = POLLIN | POLLERR;
162     fd.revents = 0;
163 
164     while (g_socketRunThread) {
165         if (poll(&fd, 1, -1) <= 0) {
166             AUDIO_ERR_LOG("audio event poll fail %{public}d", errno);
167             OsalMSleep(UEVENT_POLL_WAIT_TIME);
168             continue;
169         }
170 
171         if (((uint32_t)fd.revents & POLLIN) == POLLIN) {
172             memset_s(&msg, sizeof(msg), 0, sizeof(msg));
173             rcvLen = AudioSocketThread::AudioPnpReadUeventMsg(socketFd, msg, UEVENT_MSG_LEN);
174             if (rcvLen <= 0) {
175                 continue;
176             }
177             bool status = AudioSocketThread::AudioPnpUeventParse(msg, rcvLen);
178             if (!status) {
179                 continue;
180             }
181             eventInfo_ = GetAudioEventInfo(AudioSocketThread::audioSocketEvent_);
182             CHECK_AND_RETURN_LOG(!eventInfo_.empty(), "invalid socket info");
183             if (AudioSocketThread::audioSocketEvent_.eventType == PNP_EVENT_MIC_BLOCKED ||
184                 AudioSocketThread::audioSocketEvent_.eventType == PNP_EVENT_MIC_UNBLOCKED) {
185                 MicrophoneBlocked::GetInstance().OnMicrophoneBlocked(eventInfo_, GetAudioPnpServer());
186             } else {
187                 OnPnpDeviceStatusChanged(eventInfo_);
188             }
189         }
190     }
191     CloseFd(socketFd);
192     return;
193 }
194 
195 #ifdef AUDIO_DOUBLE_PNP_DETECT
UpdateUsbHeadset()196 void AudioPnpServer::UpdateUsbHeadset()
197 {
198     char pnpInfo[AUDIO_EVENT_INFO_LEN_MAX] = {0};
199     int32_t ret;
200     bool status = AudioSocketThread::IsUpdatePnpDeviceState(&g_usbHeadset);
201     if (!status) {
202         AUDIO_ERR_LOG("audio first pnp device[%{public}u] state[%{public}u] not need flush !",
203             g_usbHeadset.deviceType, g_usbHeadset.eventType);
204         return;
205     }
206     ret = snprintf_s(pnpInfo, AUDIO_EVENT_INFO_LEN_MAX, AUDIO_EVENT_INFO_LEN_MAX - 1, "EVENT_TYPE=%u;DEVICE_TYPE=%u",
207         g_usbHeadset.eventType, g_usbHeadset.deviceType);
208     if (ret < 0) {
209         AUDIO_ERR_LOG("snprintf_s fail!");
210         return;
211     }
212     AUDIO_DEBUG_LOG("g_usbHeadset.eventType [%{public}u], g_usbHeadset.deviceType [%{public}u]",
213         g_usbHeadset.eventType, g_usbHeadset.deviceType);
214     AudioSocketThread::UpdatePnpDeviceState(&g_usbHeadset);
215     return;
216 }
217 #endif
218 
DetectAudioDevice()219 void AudioPnpServer::DetectAudioDevice()
220 {
221     AUDIO_INFO_LOG("Enter");
222     int32_t ret;
223     AudioEvent audioEvent = {0};
224 
225     OsalMSleep(AUDIO_DEVICE_WAIT_USB_ONLINE);
226     ret = AudioSocketThread::DetectAnalogHeadsetState(&audioEvent);
227     if ((ret == SUCCESS) && (audioEvent.eventType == AUDIO_DEVICE_ADD)) {
228         AUDIO_INFO_LOG("audio detect analog headset");
229         AudioSocketThread::UpdateDeviceState(audioEvent);
230 
231         eventInfo_ = GetAudioEventInfo(AudioSocketThread::audioSocketEvent_);
232         CHECK_AND_RETURN_LOG(!eventInfo_.empty(), "invalid detect info");
233         OnPnpDeviceStatusChanged(eventInfo_);
234 #ifndef AUDIO_DOUBLE_PNP_DETECT
235         return;
236 #endif
237     }
238 #ifdef AUDIO_DOUBLE_PNP_DETECT
239     ret = AudioSocketThread::DetectUsbHeadsetState(&g_usbHeadset);
240     if ((ret == SUCCESS) && (g_usbHeadset.eventType == AUDIO_DEVICE_ADD)) {
241         AUDIO_INFO_LOG("audio detect usb headset");
242         std::unique_ptr<std::thread> bootupThread_ = nullptr;
243         bootupThread_ = std::make_unique<std::thread>([this] { this->UpdateUsbHeadset(); });
244         pthread_setname_np(bootupThread_->native_handle(), "OS_BootupEvent");
245         OsalMSleep(AUDIO_DEVICE_WAIT_USB_EVENT_UPDATE);
246         if (AudioSocketThread::audioSocketEvent_.eventType != AUDIO_EVENT_UNKNOWN &&
247             AudioSocketThread::audioSocketEvent_.deviceType != AUDIO_DEVICE_UNKNOWN) {
248             eventInfo_ = GetAudioEventInfo(AudioSocketThread::audioSocketEvent_);
249             CHECK_AND_RETURN_LOG(!eventInfo_.empty(), "invalid detect info");
250             OnPnpDeviceStatusChanged(eventInfo_);
251         }
252         if (bootupThread_ && bootupThread_->joinable()) {
253             bootupThread_->join();
254         }
255     }
256     return;
257 #else
258     audioEvent.eventType = AUDIO_EVENT_UNKNOWN;
259     audioEvent.deviceType = AUDIO_DEVICE_UNKNOWN;
260     ret = AudioSocketThread::DetectUsbHeadsetState(&audioEvent);
261     if ((ret == SUCCESS) && (audioEvent.eventType == AUDIO_DEVICE_ADD)) {
262         AUDIO_INFO_LOG("audio detect usb headset");
263         AudioSocketThread::UpdateDeviceState(audioEvent);
264         eventInfo_ = GetAudioEventInfo(AudioSocketThread::audioSocketEvent_);
265         CHECK_AND_RETURN_LOG(!eventInfo_.empty(), "invalid detect info");
266         OnPnpDeviceStatusChanged(eventInfo_);
267     }
268 #endif
269     AUDIO_INFO_LOG("Done");
270 }
271 
StopPnpServer()272 void AudioPnpServer::StopPnpServer()
273 {
274     g_socketRunThread = false;
275     g_inputRunThread = false;
276     if (socketThread_ && socketThread_->joinable()) {
277         socketThread_->detach();
278     }
279 
280     if (inputThread_ && inputThread_->joinable()) {
281         inputThread_->detach();
282     }
283 }
284 } // namespace AudioStandard
285 } // namespace OHOS