1/* AudioDaemon.cpp
2Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
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
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF 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
46int bootup_complete = 0;
47bool cpe_bootup_complete = false;
48
49namespace android {
50
51    AudioDaemon::AudioDaemon() : Thread(false) {
52    }
53
54    AudioDaemon::~AudioDaemon() {
55        putStateFDs(mSndCardFd);
56    }
57
58    void AudioDaemon::onFirstRef() {
59        ALOGV("Start audiod daemon");
60        run("AudioDaemon", PRIORITY_URGENT_AUDIO);
61    }
62
63    void AudioDaemon::binderDied(const wp<IBinder>& who)
64    {
65        requestExit();
66    }
67
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
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
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
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
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
206    status_t AudioDaemon::readyToRun() {
207
208        ALOGV("readyToRun: open snd card state node files");
209        return NO_ERROR;
210    }
211
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
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
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