1 /* AudioDaemon.cpp
2 Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above
10       copyright notice, this list of conditions and the following
11       disclaimer in the documentation and/or other materials provided
12       with the distribution.
13     * Neither the name of The Linux Foundation nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
28 
29 #define LOG_TAG "AudioDaemon"
30 #define LOG_NDEBUG 0
31 #define LOG_NDDEBUG 0
32 
33 #include <dirent.h>
34 #include <media/AudioSystem.h>
35 #include <sys/poll.h>
36 
37 #include "AudioDaemon.h"
38 
39 #define CPE_MAGIC_NUM 0x2000
40 #define MAX_CPE_SLEEP_RETRY 2
41 #define CPE_SLEEP_WAIT 100
42 
43 #define MAX_SLEEP_RETRY 100
44 #define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */
45 
46 int bootup_complete = 0;
47 bool cpe_bootup_complete = false;
48 
49 namespace android {
50 
AudioDaemon()51     AudioDaemon::AudioDaemon() : Thread(false) {
52     }
53 
~AudioDaemon()54     AudioDaemon::~AudioDaemon() {
55         putStateFDs(mSndCardFd);
56     }
57 
onFirstRef()58     void AudioDaemon::onFirstRef() {
59         ALOGV("Start audiod daemon");
60         run("AudioDaemon", PRIORITY_URGENT_AUDIO);
61     }
62 
binderDied(const wp<IBinder> & who)63     void AudioDaemon::binderDied(const wp<IBinder>& who)
64     {
65         requestExit();
66     }
67 
getStateFDs(std::vector<std::pair<int,int>> & sndcardFdPair)68     bool AudioDaemon::getStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
69     {
70         FILE *fp;
71         int fd;
72         char *ptr, *saveptr;
73         char buffer[128];
74         int line = 0;
75         String8 path;
76         int sndcard;
77         const char* cards = "/proc/asound/cards";
78 
79         if ((fp = fopen(cards, "r")) == NULL) {
80             ALOGE("Cannot open %s file to get list of sound cars", cards);
81             return false;
82         }
83 
84         sndcardFdPair.clear();
85         memset(buffer, 0x0, sizeof(buffer));
86         while ((fgets(buffer, sizeof(buffer), fp) != NULL)) {
87             if (line % 2)
88                 continue;
89             ptr = strtok_r(buffer, " [", &saveptr);
90             if (ptr) {
91                 path = "/proc/asound/card";
92                 path += ptr;
93                 path += "/state";
94                 ALOGD("Opening sound card state : %s", path.string());
95                 fd = open(path.string(), O_RDONLY);
96                 if (fd == -1) {
97                     ALOGE("Open %s failed : %s", path.string(), strerror(errno));
98                 } else {
99                     /* returns vector of pair<sndcard, fd> */
100                     sndcard = atoi(ptr);
101                     sndcardFdPair.push_back(std::make_pair(sndcard, fd));
102                 }
103             }
104             line++;
105         }
106 
107         ALOGV("%s: %d sound cards detected", __func__, sndcardFdPair.size());
108         fclose(fp);
109 
110         return sndcardFdPair.size() > 0 ? true : false;
111     }
112 
putStateFDs(std::vector<std::pair<int,int>> & sndcardFdPair)113     void AudioDaemon::putStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
114     {
115         unsigned int i;
116         for (i = 0; i < sndcardFdPair.size(); i++)
117             close(sndcardFdPair[i].second);
118         sndcardFdPair.clear();
119     }
120 
getDeviceEventFDs()121     bool AudioDaemon::getDeviceEventFDs()
122     {
123         const char* events_dir = "/sys/class/switch/";
124         DIR *dp;
125         struct dirent* in_file;
126         int fd;
127         String8 path;
128         String8 d_name;
129 
130         if ((dp = opendir(events_dir)) == NULL) {
131             ALOGE("Cannot open switch directory to get list of audio events %s", events_dir);
132             return false;
133         }
134 
135         mAudioEvents.clear();
136         mAudioEventsStatus.clear();
137 
138         while ((in_file = readdir(dp)) != NULL) {
139 
140             if (!strstr(in_file->d_name, "qc_"))
141                 continue;
142             ALOGD(" Found event file = %s", in_file->d_name);
143             path = "/sys/class/switch/";
144             path += in_file->d_name;
145             path += "/state";
146 
147             ALOGE("Opening audio event state : %s ", path.string());
148             fd = open(path.string(), O_RDONLY);
149             if (fd == -1) {
150                 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
151             } else {
152                 d_name = in_file->d_name;
153                 mAudioEvents.push_back(std::make_pair(d_name, fd));
154                 mAudioEventsStatus.push_back(std::make_pair(d_name, 0));
155                 ALOGD("event status mAudioEventsStatus= %s",
156                           mAudioEventsStatus[0].first.string());
157             }
158         }
159 
160         ALOGV("%s: %d audio device event detected",
161                   __func__,
162                   mAudioEvents.size());
163 
164         closedir(dp);
165         return mAudioEvents.size() > 0 ? true : false;
166 
167     }
168 
putDeviceEventFDs()169     void  AudioDaemon::putDeviceEventFDs()
170     {
171         unsigned int i;
172         for (i = 0; i < mAudioEvents.size(); i++) {
173             close(mAudioEvents[i].second);
174             delete(mAudioEvents[i].first);
175         }
176         mAudioEvents.clear();
177         mAudioEventsStatus.clear();
178     }
179 
checkEventState(int fd,int index)180     void AudioDaemon::checkEventState(int fd, int index)
181     {
182         char state_buf[2];
183         audio_event_status event_cur_state = audio_event_off;
184 
185         if (!read(fd, (void *)state_buf, 1)) {
186             ALOGE("Error receiving device state event (%s)", strerror(errno));
187         } else {
188              state_buf[1] = '\0';
189             if (atoi(state_buf) != mAudioEventsStatus[index].second) {
190                 ALOGD("notify audio HAL %s",
191                         mAudioEvents[index].first.string());
192                 mAudioEventsStatus[index].second = atoi(state_buf);
193 
194                 if (mAudioEventsStatus[index].second == 1)
195                     event_cur_state = audio_event_on;
196                 else
197                     event_cur_state = audio_event_off;
198                 notifyAudioSystemEventStatus(
199                                mAudioEventsStatus[index].first.string(),
200                                event_cur_state);
201             }
202         }
203         lseek(fd, 0, SEEK_SET);
204     }
205 
readyToRun()206     status_t AudioDaemon::readyToRun() {
207 
208         ALOGV("readyToRun: open snd card state node files");
209         return NO_ERROR;
210     }
211 
threadLoop()212     bool AudioDaemon::threadLoop()
213     {
214         int max = -1;
215         unsigned int i;
216         bool ret = true;
217         notify_status cur_state = snd_card_offline;
218         struct pollfd *pfd = NULL;
219         char rd_buf[9];
220         unsigned int sleepRetry = 0;
221         bool audioInitDone = false;
222         int fd = 0;
223         char path[50];
224         notify_status cur_cpe_state = cpe_offline;
225         notify_status prev_cpe_state = cpe_offline;
226         unsigned int cpe_cnt = CPE_MAGIC_NUM;
227         unsigned int num_snd_cards = 0;
228 
229         ALOGV("Start threadLoop()");
230         while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) {
231             if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) {
232                 ALOGE("Sleeping for 100 ms");
233                 usleep(AUDIO_INIT_SLEEP_WAIT*1000);
234                 sleepRetry++;
235             } else {
236                 audioInitDone = true;
237             }
238         }
239 
240         if (!getDeviceEventFDs()) {
241             ALOGE("No audio device events detected");
242         }
243 
244         if (audioInitDone == false) {
245             ALOGE("Sound Card is empty!!!");
246             goto thread_exit;
247         }
248 
249         /* soundcards are opened, now get the cpe state nodes */
250         num_snd_cards = mSndCardFd.size();
251         for (i = 0; i < num_snd_cards; i++) {
252             snprintf(path, sizeof(path), "/proc/asound/card%d/cpe0_state", mSndCardFd[i].first);
253             ALOGD("Opening cpe0_state : %s", path);
254             sleepRetry = 0;
255             do {
256                 fd = open(path, O_RDONLY);
257                 if (fd == -1)  {
258                     sleepRetry++;
259                     ALOGE("CPE state open %s failed %s, Retrying %d",
260                           path, strerror(errno), sleepRetry);
261                     usleep(CPE_SLEEP_WAIT*1000);
262                 } else {
263                     ALOGD("cpe state opened: %s", path);
264                     mSndCardFd.push_back(std::make_pair(cpe_cnt++, fd));
265                 }
266             }while ((fd == -1) &&  sleepRetry < MAX_CPE_SLEEP_RETRY);
267         }
268         ALOGD("number of sndcards %d CPEs %d", i, cpe_cnt - CPE_MAGIC_NUM);
269 
270         pfd = new pollfd[mSndCardFd.size() + mAudioEvents.size()];
271         bzero(pfd, (sizeof(*pfd) * mSndCardFd.size() +
272                     sizeof(*pfd) * mAudioEvents.size()));
273         for (i = 0; i < mSndCardFd.size(); i++) {
274             pfd[i].fd = mSndCardFd[i].second;
275             pfd[i].events = POLLPRI;
276         }
277 
278         /*insert all audio events*/
279         for(i = 0; i < mAudioEvents.size(); i++) {
280             pfd[i+mSndCardFd.size()].fd = mAudioEvents[i].second;
281             pfd[i+mSndCardFd.size()].events = POLLPRI;
282         }
283 
284         ALOGD("read for sound card state change before while");
285         for (i = 0; i < mSndCardFd.size(); i++) {
286             if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
287                ALOGE("Error receiving sound card state event (%s)", strerror(errno));
288                ret = false;
289             } else {
290                rd_buf[8] = '\0';
291                lseek(pfd[i].fd, 0, SEEK_SET);
292 
293                if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
294                    ALOGD("CPE %d state file content: %s before while",
295                          mSndCardFd[i].first - CPE_MAGIC_NUM, rd_buf);
296                    if (strstr(rd_buf, "OFFLINE")) {
297                        ALOGD("CPE state offline");
298                        cur_cpe_state = cpe_offline;
299                    } else if (strstr(rd_buf, "ONLINE")){
300                        ALOGD("CPE state online");
301                        cur_cpe_state = cpe_online;
302                    } else {
303                        ALOGE("ERROR CPE rd_buf %s", rd_buf);
304                    }
305                    if (cur_cpe_state == cpe_online && !cpe_bootup_complete) {
306                        cpe_bootup_complete = true;
307                        ALOGD("CPE boot up completed before polling");
308                    }
309                    prev_cpe_state = cur_cpe_state;
310                }
311                else {
312                    ALOGD("sound card state file content: %s before while",rd_buf);
313                    if (strstr(rd_buf, "OFFLINE")) {
314                        ALOGE("put cur_state to offline");
315                        cur_state = snd_card_offline;
316                    } else if (strstr(rd_buf, "ONLINE")){
317                        ALOGE("put cur_state to online");
318                        cur_state = snd_card_online;
319                    } else {
320                        ALOGE("ERROR rd_buf %s", rd_buf);
321                    }
322 
323                    ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state );
324                    if (cur_state == snd_card_online && !bootup_complete) {
325                        bootup_complete = 1;
326                        ALOGE("sound card up is deteced before while");
327                        ALOGE("bootup_complete set to 1");
328                    }
329                }
330             }
331         }
332 
333        ALOGE("read for event state change before while");
334        for (i = 0; i < mAudioEvents.size(); i++){
335            checkEventState(pfd[i+mSndCardFd.size()].fd, i);
336        }
337 
338         while (1) {
339            ALOGD("poll() for sound card state change ");
340            if (poll(pfd, (mSndCardFd.size() + mAudioEvents.size()), -1) < 0) {
341               ALOGE("poll() failed (%s)", strerror(errno));
342               ret = false;
343               break;
344            }
345 
346            ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size());
347            for (i = 0; i < mSndCardFd.size(); i++) {
348                if (pfd[i].revents & POLLPRI) {
349                    if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
350                        ALOGE("Error receiving sound card %d state event (%s)",
351                              mSndCardFd[i].first, strerror(errno));
352                        ret = false;
353                    } else {
354                        rd_buf[8] = '\0';
355                        lseek(pfd[i].fd, 0, SEEK_SET);
356 
357                        if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
358                            if (strstr(rd_buf, "OFFLINE"))
359                                cur_cpe_state = cpe_offline;
360                            else if (strstr(rd_buf, "ONLINE"))
361                                cur_cpe_state = cpe_online;
362                            else
363                                ALOGE("ERROR CPE rd_buf %s", rd_buf);
364 
365                            if (cpe_bootup_complete && (prev_cpe_state != cur_cpe_state)) {
366                                ALOGD("CPE state is %d, nofity AudioSystem", cur_cpe_state);
367                                notifyAudioSystem(mSndCardFd[i].first, cur_cpe_state, CPE_STATE);
368                            }
369                            if (!cpe_bootup_complete && (cur_cpe_state == cpe_online)) {
370                                cpe_bootup_complete = true;
371                                ALOGD("CPE boot up completed");
372                            }
373                            prev_cpe_state = cur_cpe_state;
374                        }
375                        else {
376                            ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete);
377                            if (strstr(rd_buf, "OFFLINE")) {
378                                cur_state = snd_card_offline;
379                            } else if (strstr(rd_buf, "ONLINE")){
380                                cur_state = snd_card_online;
381                            }
382 
383                            if (bootup_complete) {
384                                ALOGV("bootup_complete, so NofityAudioSystem");
385                                notifyAudioSystem(mSndCardFd[i].first, cur_state, SND_CARD_STATE);
386                            }
387 
388                            if (cur_state == snd_card_online && !bootup_complete) {
389                                bootup_complete = 1;
390                            }
391                        }
392                    }
393                }
394            }
395            for (i = 0; i < mAudioEvents.size(); i++) {
396                if (pfd[i + mSndCardFd.size()].revents & POLLPRI) {
397                    ALOGE("EVENT recieved pfd[i].revents= 0x%x %d",
398                        pfd[i + mSndCardFd.size()].revents,
399                        mAudioEvents[i].second);
400 
401                    checkEventState(pfd[i + mSndCardFd.size()].fd, i);
402                }
403            }
404        }
405 
406        putStateFDs(mSndCardFd);
407        putDeviceEventFDs();
408        delete [] pfd;
409 
410     thread_exit:
411        ALOGV("Exiting Poll ThreadLoop");
412        return ret;
413     }
414 
notifyAudioSystem(int snd_card,notify_status status,notify_status_type type)415     void AudioDaemon::notifyAudioSystem(int snd_card,
416                                         notify_status status,
417                                         notify_status_type type)
418     {
419 
420         String8 str;
421         char buf[4] = {0,};
422 
423         if (type == CPE_STATE) {
424             str = "CPE_STATUS=";
425             snprintf(buf, sizeof(buf), "%d", snd_card - CPE_MAGIC_NUM);
426             str += buf;
427             if (status == cpe_online)
428                 str += ",ONLINE";
429             else
430                 str += ",OFFLINE";
431         }
432         else {
433             str = "SND_CARD_STATUS=";
434             snprintf(buf, sizeof(buf), "%d", snd_card);
435             str += buf;
436             if (status == snd_card_online)
437                 str += ",ONLINE";
438             else
439                 str += ",OFFLINE";
440         }
441         ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
442         AudioSystem::setParameters(0, str);
443     }
444 
notifyAudioSystemEventStatus(const char * event,audio_event_status status)445     void AudioDaemon::notifyAudioSystemEventStatus(const char* event,
446                                             audio_event_status status) {
447 
448         String8 str;
449         str += AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE;
450         str += "=";
451         str += event;
452 
453         if (status == audio_event_on)
454             str += ",ON";
455         else
456             str += ",OFF";
457         ALOGD("%s: notifyAudioSystemEventStatus : %s", __func__, str.string());
458         AudioSystem::setParameters(0, str);
459     }
460 }
461