blob: 6f3821874130ad1d8d35c1e6d6696dee29c4c9f7 [file] [log] [blame]
Fred Oh144d8742013-11-11 14:26:21 -08001/* AudioDaemon.cpp
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -07002Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Fred Oh144d8742013-11-11 14:26:21 -08003
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
Tanya Finkelf8d52aa2014-07-16 07:03:15 -070033#include <dirent.h>
Fred Oh144d8742013-11-11 14:26:21 -080034#include <media/AudioSystem.h>
35#include <sys/poll.h>
36
37#include "AudioDaemon.h"
38
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -070039#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
Fred Oh144d8742013-11-11 14:26:21 -080046int bootup_complete = 0;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -070047bool cpe_bootup_complete = false;
Fred Oh144d8742013-11-11 14:26:21 -080048
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");
Naresh Tanniru1aa072f2014-05-02 15:52:46 +053060 run("AudioDaemon", PRIORITY_URGENT_AUDIO);
Fred Oh144d8742013-11-11 14:26:21 -080061 }
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
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700121 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;
Mingming Yin497419f2015-07-01 16:57:32 -0700128 String8 d_name;
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700129
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 {
Mingming Yin497419f2015-07-01 16:57:32 -0700152 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));
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700155 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
Fred Oh144d8742013-11-11 14:26:21 -0800206 status_t AudioDaemon::readyToRun() {
207
208 ALOGV("readyToRun: open snd card state node files");
209 return NO_ERROR;
210 }
211
Fred Oh144d8742013-11-11 14:26:21 -0800212 bool AudioDaemon::threadLoop()
213 {
214 int max = -1;
215 unsigned int i;
216 bool ret = true;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700217 notify_status cur_state = snd_card_offline;
Fred Oh144d8742013-11-11 14:26:21 -0800218 struct pollfd *pfd = NULL;
219 char rd_buf[9];
220 unsigned int sleepRetry = 0;
221 bool audioInitDone = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700222 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;
Fred Oh144d8742013-11-11 14:26:21 -0800228
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
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700240 if (!getDeviceEventFDs()) {
241 ALOGE("No audio device events detected");
242 }
243
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700244 if (audioInitDone == false) {
Fred Oh144d8742013-11-11 14:26:21 -0800245 ALOGE("Sound Card is empty!!!");
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700246 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);
Fred Oh144d8742013-11-11 14:26:21 -0800269
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700270 pfd = new pollfd[mSndCardFd.size() + mAudioEvents.size()];
271 bzero(pfd, (sizeof(*pfd) * mSndCardFd.size() +
272 sizeof(*pfd) * mAudioEvents.size()));
Fred Oh144d8742013-11-11 14:26:21 -0800273 for (i = 0; i < mSndCardFd.size(); i++) {
274 pfd[i].fd = mSndCardFd[i].second;
275 pfd[i].events = POLLPRI;
276 }
277
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700278 /*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
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700284 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)) {
Fred Oh144d8742013-11-11 14:26:21 -0800287 ALOGE("Error receiving sound card state event (%s)", strerror(errno));
288 ret = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700289 } else {
Fred Oh144d8742013-11-11 14:26:21 -0800290 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800291 lseek(pfd[i].fd, 0, SEEK_SET);
292
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700293 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;
Fred Oh144d8742013-11-11 14:26:21 -0800310 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700311 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 }
Fred Oh144d8742013-11-11 14:26:21 -0800322
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700323 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 }
Fred Oh144d8742013-11-11 14:26:21 -0800329 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700330 }
331 }
Fred Oh144d8742013-11-11 14:26:21 -0800332
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700333 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
Fred Oh144d8742013-11-11 14:26:21 -0800338 while (1) {
339 ALOGD("poll() for sound card state change ");
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700340 if (poll(pfd, (mSndCardFd.size() + mAudioEvents.size()), -1) < 0) {
Fred Oh144d8742013-11-11 14:26:21 -0800341 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)) {
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700350 ALOGE("Error receiving sound card %d state event (%s)",
351 mSndCardFd[i].first, strerror(errno));
Fred Oh144d8742013-11-11 14:26:21 -0800352 ret = false;
353 } else {
354 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800355 lseek(pfd[i].fd, 0, SEEK_SET);
356
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700357 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);
Fred Oh144d8742013-11-11 14:26:21 -0800364
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700365 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;
Fred Oh144d8742013-11-11 14:26:21 -0800374 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700375 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 }
Fred Oh144d8742013-11-11 14:26:21 -0800382
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700383 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 }
Fred Oh144d8742013-11-11 14:26:21 -0800391 }
392 }
393 }
394 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700395 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 }
Fred Oh144d8742013-11-11 14:26:21 -0800404 }
405
406 putStateFDs(mSndCardFd);
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700407 putDeviceEventFDs();
Fred Oh144d8742013-11-11 14:26:21 -0800408 delete [] pfd;
409
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700410 thread_exit:
Fred Oh144d8742013-11-11 14:26:21 -0800411 ALOGV("Exiting Poll ThreadLoop");
412 return ret;
413 }
414
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700415 void AudioDaemon::notifyAudioSystem(int snd_card,
416 notify_status status,
417 notify_status_type type)
418 {
Fred Oh144d8742013-11-11 14:26:21 -0800419
420 String8 str;
421 char buf[4] = {0,};
422
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700423 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 }
Fred Oh144d8742013-11-11 14:26:21 -0800441 ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
442 AudioSystem::setParameters(0, str);
443 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700444
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 }
Fred Oh144d8742013-11-11 14:26:21 -0800460}