blob: 53699ffba4aa0230e43a2b402d3f5a7fc8d352d2 [file] [log] [blame]
Fred Oh144d8742013-11-11 14:26:21 -08001/* AudioDaemon.cpp
Satya Krishna Pindiproli486ddb12016-11-17 14:29:07 +05302Copyright (c) 2012-2016, 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;
Satya Krishna Pindiproli486ddb12016-11-17 14:29:07 +053072 char *ptr, *saveptr, *card_id = NULL;
Fred Oh144d8742013-11-11 14:26:21 -080073 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)) {
Satya Krishna Pindiproli486ddb12016-11-17 14:29:07 +053087 if (line++ % 2)
Fred Oh144d8742013-11-11 14:26:21 -080088 continue;
89 ptr = strtok_r(buffer, " [", &saveptr);
Satya Krishna Pindiproli486ddb12016-11-17 14:29:07 +053090 if (!ptr)
91 continue;
92
93 card_id = strtok_r(saveptr+1, "]", &saveptr);
94 if (!card_id)
95 continue;
96 //Only consider sound cards associated with ADSP
97 if ((strncasecmp(card_id, "msm", 3) != 0) &&
Arusha Goyalfda29152016-12-26 10:53:39 +053098 (strncasecmp(card_id, "sdm", 3) != 0) &&
99 (strncasecmp(card_id, "sdc", 3) != 0) &&
Satya Krishna Pindiproli486ddb12016-11-17 14:29:07 +0530100 (strncasecmp(card_id, "apq", 3) != 0)) {
101 ALOGD("Skipping non-ADSP sound card %s", card_id);
102 continue;
103 }
Fred Oh144d8742013-11-11 14:26:21 -0800104 if (ptr) {
105 path = "/proc/asound/card";
106 path += ptr;
107 path += "/state";
108 ALOGD("Opening sound card state : %s", path.string());
109 fd = open(path.string(), O_RDONLY);
110 if (fd == -1) {
111 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
112 } else {
113 /* returns vector of pair<sndcard, fd> */
114 sndcard = atoi(ptr);
115 sndcardFdPair.push_back(std::make_pair(sndcard, fd));
116 }
117 }
Fred Oh144d8742013-11-11 14:26:21 -0800118 }
119
120 ALOGV("%s: %d sound cards detected", __func__, sndcardFdPair.size());
121 fclose(fp);
122
123 return sndcardFdPair.size() > 0 ? true : false;
124 }
125
126 void AudioDaemon::putStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
127 {
128 unsigned int i;
129 for (i = 0; i < sndcardFdPair.size(); i++)
130 close(sndcardFdPair[i].second);
131 sndcardFdPair.clear();
132 }
133
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700134 bool AudioDaemon::getDeviceEventFDs()
135 {
136 const char* events_dir = "/sys/class/switch/";
137 DIR *dp;
138 struct dirent* in_file;
139 int fd;
140 String8 path;
Mingming Yin35844e52015-06-02 18:40:13 -0700141 String8 d_name;
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700142
143 if ((dp = opendir(events_dir)) == NULL) {
144 ALOGE("Cannot open switch directory to get list of audio events %s", events_dir);
145 return false;
146 }
147
148 mAudioEvents.clear();
149 mAudioEventsStatus.clear();
150
151 while ((in_file = readdir(dp)) != NULL) {
152
153 if (!strstr(in_file->d_name, "qc_"))
154 continue;
155 ALOGD(" Found event file = %s", in_file->d_name);
156 path = "/sys/class/switch/";
157 path += in_file->d_name;
158 path += "/state";
159
160 ALOGE("Opening audio event state : %s ", path.string());
161 fd = open(path.string(), O_RDONLY);
162 if (fd == -1) {
163 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
164 } else {
Mingming Yin35844e52015-06-02 18:40:13 -0700165 d_name = in_file->d_name;
166 mAudioEvents.push_back(std::make_pair(d_name, fd));
167 mAudioEventsStatus.push_back(std::make_pair(d_name, 0));
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700168 ALOGD("event status mAudioEventsStatus= %s",
169 mAudioEventsStatus[0].first.string());
170 }
171 }
172
173 ALOGV("%s: %d audio device event detected",
174 __func__,
175 mAudioEvents.size());
176
177 closedir(dp);
178 return mAudioEvents.size() > 0 ? true : false;
179
180 }
181
182 void AudioDaemon::putDeviceEventFDs()
183 {
184 unsigned int i;
185 for (i = 0; i < mAudioEvents.size(); i++) {
186 close(mAudioEvents[i].second);
187 delete(mAudioEvents[i].first);
188 }
189 mAudioEvents.clear();
190 mAudioEventsStatus.clear();
191 }
192
193 void AudioDaemon::checkEventState(int fd, int index)
194 {
195 char state_buf[2];
196 audio_event_status event_cur_state = audio_event_off;
197
198 if (!read(fd, (void *)state_buf, 1)) {
199 ALOGE("Error receiving device state event (%s)", strerror(errno));
200 } else {
201 state_buf[1] = '\0';
202 if (atoi(state_buf) != mAudioEventsStatus[index].second) {
203 ALOGD("notify audio HAL %s",
204 mAudioEvents[index].first.string());
205 mAudioEventsStatus[index].second = atoi(state_buf);
206
207 if (mAudioEventsStatus[index].second == 1)
208 event_cur_state = audio_event_on;
209 else
210 event_cur_state = audio_event_off;
211 notifyAudioSystemEventStatus(
212 mAudioEventsStatus[index].first.string(),
213 event_cur_state);
214 }
215 }
216 lseek(fd, 0, SEEK_SET);
217 }
218
Fred Oh144d8742013-11-11 14:26:21 -0800219 status_t AudioDaemon::readyToRun() {
220
221 ALOGV("readyToRun: open snd card state node files");
222 return NO_ERROR;
223 }
224
Fred Oh144d8742013-11-11 14:26:21 -0800225 bool AudioDaemon::threadLoop()
226 {
227 int max = -1;
228 unsigned int i;
229 bool ret = true;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700230 notify_status cur_state = snd_card_offline;
Fred Oh144d8742013-11-11 14:26:21 -0800231 struct pollfd *pfd = NULL;
232 char rd_buf[9];
233 unsigned int sleepRetry = 0;
234 bool audioInitDone = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700235 int fd = 0;
236 char path[50];
237 notify_status cur_cpe_state = cpe_offline;
238 notify_status prev_cpe_state = cpe_offline;
239 unsigned int cpe_cnt = CPE_MAGIC_NUM;
240 unsigned int num_snd_cards = 0;
Fred Oh144d8742013-11-11 14:26:21 -0800241
242 ALOGV("Start threadLoop()");
243 while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) {
244 if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) {
245 ALOGE("Sleeping for 100 ms");
246 usleep(AUDIO_INIT_SLEEP_WAIT*1000);
247 sleepRetry++;
248 } else {
249 audioInitDone = true;
250 }
251 }
252
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700253 if (!getDeviceEventFDs()) {
254 ALOGE("No audio device events detected");
255 }
256
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700257 if (audioInitDone == false) {
Fred Oh144d8742013-11-11 14:26:21 -0800258 ALOGE("Sound Card is empty!!!");
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700259 goto thread_exit;
260 }
261
262 /* soundcards are opened, now get the cpe state nodes */
263 num_snd_cards = mSndCardFd.size();
264 for (i = 0; i < num_snd_cards; i++) {
265 snprintf(path, sizeof(path), "/proc/asound/card%d/cpe0_state", mSndCardFd[i].first);
266 ALOGD("Opening cpe0_state : %s", path);
267 sleepRetry = 0;
268 do {
269 fd = open(path, O_RDONLY);
270 if (fd == -1) {
271 sleepRetry++;
272 ALOGE("CPE state open %s failed %s, Retrying %d",
273 path, strerror(errno), sleepRetry);
274 usleep(CPE_SLEEP_WAIT*1000);
275 } else {
276 ALOGD("cpe state opened: %s", path);
277 mSndCardFd.push_back(std::make_pair(cpe_cnt++, fd));
278 }
279 }while ((fd == -1) && sleepRetry < MAX_CPE_SLEEP_RETRY);
280 }
281 ALOGD("number of sndcards %d CPEs %d", i, cpe_cnt - CPE_MAGIC_NUM);
Fred Oh144d8742013-11-11 14:26:21 -0800282
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700283 pfd = new pollfd[mSndCardFd.size() + mAudioEvents.size()];
284 bzero(pfd, (sizeof(*pfd) * mSndCardFd.size() +
285 sizeof(*pfd) * mAudioEvents.size()));
Fred Oh144d8742013-11-11 14:26:21 -0800286 for (i = 0; i < mSndCardFd.size(); i++) {
287 pfd[i].fd = mSndCardFd[i].second;
288 pfd[i].events = POLLPRI;
289 }
290
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700291 /*insert all audio events*/
292 for(i = 0; i < mAudioEvents.size(); i++) {
293 pfd[i+mSndCardFd.size()].fd = mAudioEvents[i].second;
294 pfd[i+mSndCardFd.size()].events = POLLPRI;
295 }
296
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700297 ALOGD("read for sound card state change before while");
298 for (i = 0; i < mSndCardFd.size(); i++) {
299 if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
Fred Oh144d8742013-11-11 14:26:21 -0800300 ALOGE("Error receiving sound card state event (%s)", strerror(errno));
301 ret = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700302 } else {
Fred Oh144d8742013-11-11 14:26:21 -0800303 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800304 lseek(pfd[i].fd, 0, SEEK_SET);
305
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700306 if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
307 ALOGD("CPE %d state file content: %s before while",
308 mSndCardFd[i].first - CPE_MAGIC_NUM, rd_buf);
309 if (strstr(rd_buf, "OFFLINE")) {
310 ALOGD("CPE state offline");
311 cur_cpe_state = cpe_offline;
312 } else if (strstr(rd_buf, "ONLINE")){
313 ALOGD("CPE state online");
314 cur_cpe_state = cpe_online;
315 } else {
316 ALOGE("ERROR CPE rd_buf %s", rd_buf);
317 }
318 if (cur_cpe_state == cpe_online && !cpe_bootup_complete) {
319 cpe_bootup_complete = true;
320 ALOGD("CPE boot up completed before polling");
321 }
322 prev_cpe_state = cur_cpe_state;
Fred Oh144d8742013-11-11 14:26:21 -0800323 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700324 else {
325 ALOGD("sound card state file content: %s before while",rd_buf);
326 if (strstr(rd_buf, "OFFLINE")) {
327 ALOGE("put cur_state to offline");
328 cur_state = snd_card_offline;
329 } else if (strstr(rd_buf, "ONLINE")){
330 ALOGE("put cur_state to online");
331 cur_state = snd_card_online;
332 } else {
333 ALOGE("ERROR rd_buf %s", rd_buf);
334 }
Fred Oh144d8742013-11-11 14:26:21 -0800335
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700336 ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state );
337 if (cur_state == snd_card_online && !bootup_complete) {
338 bootup_complete = 1;
339 ALOGE("sound card up is deteced before while");
340 ALOGE("bootup_complete set to 1");
341 }
Fred Oh144d8742013-11-11 14:26:21 -0800342 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700343 }
344 }
Fred Oh144d8742013-11-11 14:26:21 -0800345
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700346 ALOGE("read for event state change before while");
347 for (i = 0; i < mAudioEvents.size(); i++){
348 checkEventState(pfd[i+mSndCardFd.size()].fd, i);
349 }
350
Fred Oh144d8742013-11-11 14:26:21 -0800351 while (1) {
352 ALOGD("poll() for sound card state change ");
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700353 if (poll(pfd, (mSndCardFd.size() + mAudioEvents.size()), -1) < 0) {
Fred Oh144d8742013-11-11 14:26:21 -0800354 ALOGE("poll() failed (%s)", strerror(errno));
355 ret = false;
356 break;
357 }
358
359 ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size());
360 for (i = 0; i < mSndCardFd.size(); i++) {
361 if (pfd[i].revents & POLLPRI) {
362 if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700363 ALOGE("Error receiving sound card %d state event (%s)",
364 mSndCardFd[i].first, strerror(errno));
Fred Oh144d8742013-11-11 14:26:21 -0800365 ret = false;
366 } else {
367 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800368 lseek(pfd[i].fd, 0, SEEK_SET);
369
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700370 if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
371 if (strstr(rd_buf, "OFFLINE"))
372 cur_cpe_state = cpe_offline;
373 else if (strstr(rd_buf, "ONLINE"))
374 cur_cpe_state = cpe_online;
375 else
376 ALOGE("ERROR CPE rd_buf %s", rd_buf);
Fred Oh144d8742013-11-11 14:26:21 -0800377
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700378 if (cpe_bootup_complete && (prev_cpe_state != cur_cpe_state)) {
379 ALOGD("CPE state is %d, nofity AudioSystem", cur_cpe_state);
380 notifyAudioSystem(mSndCardFd[i].first, cur_cpe_state, CPE_STATE);
381 }
382 if (!cpe_bootup_complete && (cur_cpe_state == cpe_online)) {
383 cpe_bootup_complete = true;
384 ALOGD("CPE boot up completed");
385 }
386 prev_cpe_state = cur_cpe_state;
Fred Oh144d8742013-11-11 14:26:21 -0800387 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700388 else {
389 ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete);
390 if (strstr(rd_buf, "OFFLINE")) {
391 cur_state = snd_card_offline;
392 } else if (strstr(rd_buf, "ONLINE")){
393 cur_state = snd_card_online;
394 }
Fred Oh144d8742013-11-11 14:26:21 -0800395
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700396 if (bootup_complete) {
397 ALOGV("bootup_complete, so NofityAudioSystem");
398 notifyAudioSystem(mSndCardFd[i].first, cur_state, SND_CARD_STATE);
399 }
400
401 if (cur_state == snd_card_online && !bootup_complete) {
402 bootup_complete = 1;
403 }
Fred Oh144d8742013-11-11 14:26:21 -0800404 }
405 }
406 }
407 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700408 for (i = 0; i < mAudioEvents.size(); i++) {
409 if (pfd[i + mSndCardFd.size()].revents & POLLPRI) {
410 ALOGE("EVENT recieved pfd[i].revents= 0x%x %d",
411 pfd[i + mSndCardFd.size()].revents,
412 mAudioEvents[i].second);
413
414 checkEventState(pfd[i + mSndCardFd.size()].fd, i);
415 }
416 }
Fred Oh144d8742013-11-11 14:26:21 -0800417 }
418
419 putStateFDs(mSndCardFd);
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700420 putDeviceEventFDs();
Fred Oh144d8742013-11-11 14:26:21 -0800421 delete [] pfd;
422
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700423 thread_exit:
Fred Oh144d8742013-11-11 14:26:21 -0800424 ALOGV("Exiting Poll ThreadLoop");
425 return ret;
426 }
427
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700428 void AudioDaemon::notifyAudioSystem(int snd_card,
429 notify_status status,
430 notify_status_type type)
431 {
Fred Oh144d8742013-11-11 14:26:21 -0800432
433 String8 str;
434 char buf[4] = {0,};
435
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700436 if (type == CPE_STATE) {
437 str = "CPE_STATUS=";
438 snprintf(buf, sizeof(buf), "%d", snd_card - CPE_MAGIC_NUM);
439 str += buf;
440 if (status == cpe_online)
441 str += ",ONLINE";
442 else
443 str += ",OFFLINE";
444 }
445 else {
446 str = "SND_CARD_STATUS=";
447 snprintf(buf, sizeof(buf), "%d", snd_card);
448 str += buf;
449 if (status == snd_card_online)
450 str += ",ONLINE";
451 else
452 str += ",OFFLINE";
453 }
Fred Oh144d8742013-11-11 14:26:21 -0800454 ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
455 AudioSystem::setParameters(0, str);
456 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700457
458 void AudioDaemon::notifyAudioSystemEventStatus(const char* event,
459 audio_event_status status) {
460
461 String8 str;
462 str += AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE;
463 str += "=";
464 str += event;
465
466 if (status == audio_event_on)
467 str += ",ON";
468 else
469 str += ",OFF";
470 ALOGD("%s: notifyAudioSystemEventStatus : %s", __func__, str.string());
471 AudioSystem::setParameters(0, str);
472 }
Fred Oh144d8742013-11-11 14:26:21 -0800473}