blob: b4857c46422bf50af02a2ba7c101084581d306e9 [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;
128
129 if ((dp = opendir(events_dir)) == NULL) {
130 ALOGE("Cannot open switch directory to get list of audio events %s", events_dir);
131 return false;
132 }
133
134 mAudioEvents.clear();
135 mAudioEventsStatus.clear();
136
137 while ((in_file = readdir(dp)) != NULL) {
138
139 if (!strstr(in_file->d_name, "qc_"))
140 continue;
141 ALOGD(" Found event file = %s", in_file->d_name);
142 path = "/sys/class/switch/";
143 path += in_file->d_name;
144 path += "/state";
145
146 ALOGE("Opening audio event state : %s ", path.string());
147 fd = open(path.string(), O_RDONLY);
148 if (fd == -1) {
149 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
150 } else {
151 mAudioEvents.push_back(std::make_pair(in_file->d_name, fd));
152 mAudioEventsStatus.push_back(std::make_pair(in_file->d_name, 0));
153 ALOGD("event status mAudioEventsStatus= %s",
154 mAudioEventsStatus[0].first.string());
155 }
156 }
157
158 ALOGV("%s: %d audio device event detected",
159 __func__,
160 mAudioEvents.size());
161
162 closedir(dp);
163 return mAudioEvents.size() > 0 ? true : false;
164
165 }
166
167 void AudioDaemon::putDeviceEventFDs()
168 {
169 unsigned int i;
170 for (i = 0; i < mAudioEvents.size(); i++) {
171 close(mAudioEvents[i].second);
172 delete(mAudioEvents[i].first);
173 }
174 mAudioEvents.clear();
175 mAudioEventsStatus.clear();
176 }
177
178 void AudioDaemon::checkEventState(int fd, int index)
179 {
180 char state_buf[2];
181 audio_event_status event_cur_state = audio_event_off;
182
183 if (!read(fd, (void *)state_buf, 1)) {
184 ALOGE("Error receiving device state event (%s)", strerror(errno));
185 } else {
186 state_buf[1] = '\0';
187 if (atoi(state_buf) != mAudioEventsStatus[index].second) {
188 ALOGD("notify audio HAL %s",
189 mAudioEvents[index].first.string());
190 mAudioEventsStatus[index].second = atoi(state_buf);
191
192 if (mAudioEventsStatus[index].second == 1)
193 event_cur_state = audio_event_on;
194 else
195 event_cur_state = audio_event_off;
196 notifyAudioSystemEventStatus(
197 mAudioEventsStatus[index].first.string(),
198 event_cur_state);
199 }
200 }
201 lseek(fd, 0, SEEK_SET);
202 }
203
Fred Oh144d8742013-11-11 14:26:21 -0800204 status_t AudioDaemon::readyToRun() {
205
206 ALOGV("readyToRun: open snd card state node files");
207 return NO_ERROR;
208 }
209
Fred Oh144d8742013-11-11 14:26:21 -0800210 bool AudioDaemon::threadLoop()
211 {
212 int max = -1;
213 unsigned int i;
214 bool ret = true;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700215 notify_status cur_state = snd_card_offline;
Fred Oh144d8742013-11-11 14:26:21 -0800216 struct pollfd *pfd = NULL;
217 char rd_buf[9];
218 unsigned int sleepRetry = 0;
219 bool audioInitDone = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700220 int fd = 0;
221 char path[50];
222 notify_status cur_cpe_state = cpe_offline;
223 notify_status prev_cpe_state = cpe_offline;
224 unsigned int cpe_cnt = CPE_MAGIC_NUM;
225 unsigned int num_snd_cards = 0;
Fred Oh144d8742013-11-11 14:26:21 -0800226
227 ALOGV("Start threadLoop()");
228 while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) {
229 if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) {
230 ALOGE("Sleeping for 100 ms");
231 usleep(AUDIO_INIT_SLEEP_WAIT*1000);
232 sleepRetry++;
233 } else {
234 audioInitDone = true;
235 }
236 }
237
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700238 if (!getDeviceEventFDs()) {
239 ALOGE("No audio device events detected");
240 }
241
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700242 if (audioInitDone == false) {
Fred Oh144d8742013-11-11 14:26:21 -0800243 ALOGE("Sound Card is empty!!!");
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700244 goto thread_exit;
245 }
246
247 /* soundcards are opened, now get the cpe state nodes */
248 num_snd_cards = mSndCardFd.size();
249 for (i = 0; i < num_snd_cards; i++) {
250 snprintf(path, sizeof(path), "/proc/asound/card%d/cpe0_state", mSndCardFd[i].first);
251 ALOGD("Opening cpe0_state : %s", path);
252 sleepRetry = 0;
253 do {
254 fd = open(path, O_RDONLY);
255 if (fd == -1) {
256 sleepRetry++;
257 ALOGE("CPE state open %s failed %s, Retrying %d",
258 path, strerror(errno), sleepRetry);
259 usleep(CPE_SLEEP_WAIT*1000);
260 } else {
261 ALOGD("cpe state opened: %s", path);
262 mSndCardFd.push_back(std::make_pair(cpe_cnt++, fd));
263 }
264 }while ((fd == -1) && sleepRetry < MAX_CPE_SLEEP_RETRY);
265 }
266 ALOGD("number of sndcards %d CPEs %d", i, cpe_cnt - CPE_MAGIC_NUM);
Fred Oh144d8742013-11-11 14:26:21 -0800267
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700268 pfd = new pollfd[mSndCardFd.size() + mAudioEvents.size()];
269 bzero(pfd, (sizeof(*pfd) * mSndCardFd.size() +
270 sizeof(*pfd) * mAudioEvents.size()));
Fred Oh144d8742013-11-11 14:26:21 -0800271 for (i = 0; i < mSndCardFd.size(); i++) {
272 pfd[i].fd = mSndCardFd[i].second;
273 pfd[i].events = POLLPRI;
274 }
275
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700276 /*insert all audio events*/
277 for(i = 0; i < mAudioEvents.size(); i++) {
278 pfd[i+mSndCardFd.size()].fd = mAudioEvents[i].second;
279 pfd[i+mSndCardFd.size()].events = POLLPRI;
280 }
281
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700282 ALOGD("read for sound card state change before while");
283 for (i = 0; i < mSndCardFd.size(); i++) {
284 if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
Fred Oh144d8742013-11-11 14:26:21 -0800285 ALOGE("Error receiving sound card state event (%s)", strerror(errno));
286 ret = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700287 } else {
Fred Oh144d8742013-11-11 14:26:21 -0800288 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800289 lseek(pfd[i].fd, 0, SEEK_SET);
290
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700291 if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
292 ALOGD("CPE %d state file content: %s before while",
293 mSndCardFd[i].first - CPE_MAGIC_NUM, rd_buf);
294 if (strstr(rd_buf, "OFFLINE")) {
295 ALOGD("CPE state offline");
296 cur_cpe_state = cpe_offline;
297 } else if (strstr(rd_buf, "ONLINE")){
298 ALOGD("CPE state online");
299 cur_cpe_state = cpe_online;
300 } else {
301 ALOGE("ERROR CPE rd_buf %s", rd_buf);
302 }
303 if (cur_cpe_state == cpe_online && !cpe_bootup_complete) {
304 cpe_bootup_complete = true;
305 ALOGD("CPE boot up completed before polling");
306 }
307 prev_cpe_state = cur_cpe_state;
Fred Oh144d8742013-11-11 14:26:21 -0800308 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700309 else {
310 ALOGD("sound card state file content: %s before while",rd_buf);
311 if (strstr(rd_buf, "OFFLINE")) {
312 ALOGE("put cur_state to offline");
313 cur_state = snd_card_offline;
314 } else if (strstr(rd_buf, "ONLINE")){
315 ALOGE("put cur_state to online");
316 cur_state = snd_card_online;
317 } else {
318 ALOGE("ERROR rd_buf %s", rd_buf);
319 }
Fred Oh144d8742013-11-11 14:26:21 -0800320
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700321 ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state );
322 if (cur_state == snd_card_online && !bootup_complete) {
323 bootup_complete = 1;
324 ALOGE("sound card up is deteced before while");
325 ALOGE("bootup_complete set to 1");
326 }
Fred Oh144d8742013-11-11 14:26:21 -0800327 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700328 }
329 }
Fred Oh144d8742013-11-11 14:26:21 -0800330
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700331 ALOGE("read for event state change before while");
332 for (i = 0; i < mAudioEvents.size(); i++){
333 checkEventState(pfd[i+mSndCardFd.size()].fd, i);
334 }
335
Fred Oh144d8742013-11-11 14:26:21 -0800336 while (1) {
337 ALOGD("poll() for sound card state change ");
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700338 if (poll(pfd, (mSndCardFd.size() + mAudioEvents.size()), -1) < 0) {
Fred Oh144d8742013-11-11 14:26:21 -0800339 ALOGE("poll() failed (%s)", strerror(errno));
340 ret = false;
341 break;
342 }
343
344 ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size());
345 for (i = 0; i < mSndCardFd.size(); i++) {
346 if (pfd[i].revents & POLLPRI) {
347 if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700348 ALOGE("Error receiving sound card %d state event (%s)",
349 mSndCardFd[i].first, strerror(errno));
Fred Oh144d8742013-11-11 14:26:21 -0800350 ret = false;
351 } else {
352 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800353 lseek(pfd[i].fd, 0, SEEK_SET);
354
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700355 if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
356 if (strstr(rd_buf, "OFFLINE"))
357 cur_cpe_state = cpe_offline;
358 else if (strstr(rd_buf, "ONLINE"))
359 cur_cpe_state = cpe_online;
360 else
361 ALOGE("ERROR CPE rd_buf %s", rd_buf);
Fred Oh144d8742013-11-11 14:26:21 -0800362
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700363 if (cpe_bootup_complete && (prev_cpe_state != cur_cpe_state)) {
364 ALOGD("CPE state is %d, nofity AudioSystem", cur_cpe_state);
365 notifyAudioSystem(mSndCardFd[i].first, cur_cpe_state, CPE_STATE);
366 }
367 if (!cpe_bootup_complete && (cur_cpe_state == cpe_online)) {
368 cpe_bootup_complete = true;
369 ALOGD("CPE boot up completed");
370 }
371 prev_cpe_state = cur_cpe_state;
Fred Oh144d8742013-11-11 14:26:21 -0800372 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700373 else {
374 ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete);
375 if (strstr(rd_buf, "OFFLINE")) {
376 cur_state = snd_card_offline;
377 } else if (strstr(rd_buf, "ONLINE")){
378 cur_state = snd_card_online;
379 }
Fred Oh144d8742013-11-11 14:26:21 -0800380
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700381 if (bootup_complete) {
382 ALOGV("bootup_complete, so NofityAudioSystem");
383 notifyAudioSystem(mSndCardFd[i].first, cur_state, SND_CARD_STATE);
384 }
385
386 if (cur_state == snd_card_online && !bootup_complete) {
387 bootup_complete = 1;
388 }
Fred Oh144d8742013-11-11 14:26:21 -0800389 }
390 }
391 }
392 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700393 for (i = 0; i < mAudioEvents.size(); i++) {
394 if (pfd[i + mSndCardFd.size()].revents & POLLPRI) {
395 ALOGE("EVENT recieved pfd[i].revents= 0x%x %d",
396 pfd[i + mSndCardFd.size()].revents,
397 mAudioEvents[i].second);
398
399 checkEventState(pfd[i + mSndCardFd.size()].fd, i);
400 }
401 }
Fred Oh144d8742013-11-11 14:26:21 -0800402 }
403
404 putStateFDs(mSndCardFd);
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700405 putDeviceEventFDs();
Fred Oh144d8742013-11-11 14:26:21 -0800406 delete [] pfd;
407
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700408 thread_exit:
Fred Oh144d8742013-11-11 14:26:21 -0800409 ALOGV("Exiting Poll ThreadLoop");
410 return ret;
411 }
412
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700413 void AudioDaemon::notifyAudioSystem(int snd_card,
414 notify_status status,
415 notify_status_type type)
416 {
Fred Oh144d8742013-11-11 14:26:21 -0800417
418 String8 str;
419 char buf[4] = {0,};
420
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700421 if (type == CPE_STATE) {
422 str = "CPE_STATUS=";
423 snprintf(buf, sizeof(buf), "%d", snd_card - CPE_MAGIC_NUM);
424 str += buf;
425 if (status == cpe_online)
426 str += ",ONLINE";
427 else
428 str += ",OFFLINE";
429 }
430 else {
431 str = "SND_CARD_STATUS=";
432 snprintf(buf, sizeof(buf), "%d", snd_card);
433 str += buf;
434 if (status == snd_card_online)
435 str += ",ONLINE";
436 else
437 str += ",OFFLINE";
438 }
Fred Oh144d8742013-11-11 14:26:21 -0800439 ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
440 AudioSystem::setParameters(0, str);
441 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700442
443 void AudioDaemon::notifyAudioSystemEventStatus(const char* event,
444 audio_event_status status) {
445
446 String8 str;
447 str += AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE;
448 str += "=";
449 str += event;
450
451 if (status == audio_event_on)
452 str += ",ON";
453 else
454 str += ",OFF";
455 ALOGD("%s: notifyAudioSystemEventStatus : %s", __func__, str.string());
456 AudioSystem::setParameters(0, str);
457 }
Fred Oh144d8742013-11-11 14:26:21 -0800458}