blob: 1a4033002d42783b504352798e26e6a39e367b51 [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) &&
98 (strncasecmp(card_id, "apq", 3) != 0)) {
99 ALOGD("Skipping non-ADSP sound card %s", card_id);
100 continue;
101 }
Fred Oh144d8742013-11-11 14:26:21 -0800102 if (ptr) {
103 path = "/proc/asound/card";
104 path += ptr;
105 path += "/state";
106 ALOGD("Opening sound card state : %s", path.string());
107 fd = open(path.string(), O_RDONLY);
108 if (fd == -1) {
109 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
110 } else {
111 /* returns vector of pair<sndcard, fd> */
112 sndcard = atoi(ptr);
113 sndcardFdPair.push_back(std::make_pair(sndcard, fd));
114 }
115 }
Fred Oh144d8742013-11-11 14:26:21 -0800116 }
117
118 ALOGV("%s: %d sound cards detected", __func__, sndcardFdPair.size());
119 fclose(fp);
120
121 return sndcardFdPair.size() > 0 ? true : false;
122 }
123
124 void AudioDaemon::putStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
125 {
126 unsigned int i;
127 for (i = 0; i < sndcardFdPair.size(); i++)
128 close(sndcardFdPair[i].second);
129 sndcardFdPair.clear();
130 }
131
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700132 bool AudioDaemon::getDeviceEventFDs()
133 {
134 const char* events_dir = "/sys/class/switch/";
135 DIR *dp;
136 struct dirent* in_file;
137 int fd;
138 String8 path;
Mingming Yin35844e52015-06-02 18:40:13 -0700139 String8 d_name;
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700140
141 if ((dp = opendir(events_dir)) == NULL) {
142 ALOGE("Cannot open switch directory to get list of audio events %s", events_dir);
143 return false;
144 }
145
146 mAudioEvents.clear();
147 mAudioEventsStatus.clear();
148
149 while ((in_file = readdir(dp)) != NULL) {
150
151 if (!strstr(in_file->d_name, "qc_"))
152 continue;
153 ALOGD(" Found event file = %s", in_file->d_name);
154 path = "/sys/class/switch/";
155 path += in_file->d_name;
156 path += "/state";
157
158 ALOGE("Opening audio event state : %s ", path.string());
159 fd = open(path.string(), O_RDONLY);
160 if (fd == -1) {
161 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
162 } else {
Mingming Yin35844e52015-06-02 18:40:13 -0700163 d_name = in_file->d_name;
164 mAudioEvents.push_back(std::make_pair(d_name, fd));
165 mAudioEventsStatus.push_back(std::make_pair(d_name, 0));
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700166 ALOGD("event status mAudioEventsStatus= %s",
167 mAudioEventsStatus[0].first.string());
168 }
169 }
170
171 ALOGV("%s: %d audio device event detected",
172 __func__,
173 mAudioEvents.size());
174
175 closedir(dp);
176 return mAudioEvents.size() > 0 ? true : false;
177
178 }
179
180 void AudioDaemon::putDeviceEventFDs()
181 {
182 unsigned int i;
183 for (i = 0; i < mAudioEvents.size(); i++) {
184 close(mAudioEvents[i].second);
185 delete(mAudioEvents[i].first);
186 }
187 mAudioEvents.clear();
188 mAudioEventsStatus.clear();
189 }
190
191 void AudioDaemon::checkEventState(int fd, int index)
192 {
193 char state_buf[2];
194 audio_event_status event_cur_state = audio_event_off;
195
196 if (!read(fd, (void *)state_buf, 1)) {
197 ALOGE("Error receiving device state event (%s)", strerror(errno));
198 } else {
199 state_buf[1] = '\0';
200 if (atoi(state_buf) != mAudioEventsStatus[index].second) {
201 ALOGD("notify audio HAL %s",
202 mAudioEvents[index].first.string());
203 mAudioEventsStatus[index].second = atoi(state_buf);
204
205 if (mAudioEventsStatus[index].second == 1)
206 event_cur_state = audio_event_on;
207 else
208 event_cur_state = audio_event_off;
209 notifyAudioSystemEventStatus(
210 mAudioEventsStatus[index].first.string(),
211 event_cur_state);
212 }
213 }
214 lseek(fd, 0, SEEK_SET);
215 }
216
Fred Oh144d8742013-11-11 14:26:21 -0800217 status_t AudioDaemon::readyToRun() {
218
219 ALOGV("readyToRun: open snd card state node files");
220 return NO_ERROR;
221 }
222
Fred Oh144d8742013-11-11 14:26:21 -0800223 bool AudioDaemon::threadLoop()
224 {
225 int max = -1;
226 unsigned int i;
227 bool ret = true;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700228 notify_status cur_state = snd_card_offline;
Fred Oh144d8742013-11-11 14:26:21 -0800229 struct pollfd *pfd = NULL;
230 char rd_buf[9];
231 unsigned int sleepRetry = 0;
232 bool audioInitDone = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700233 int fd = 0;
234 char path[50];
235 notify_status cur_cpe_state = cpe_offline;
236 notify_status prev_cpe_state = cpe_offline;
237 unsigned int cpe_cnt = CPE_MAGIC_NUM;
238 unsigned int num_snd_cards = 0;
Fred Oh144d8742013-11-11 14:26:21 -0800239
240 ALOGV("Start threadLoop()");
241 while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) {
242 if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) {
243 ALOGE("Sleeping for 100 ms");
244 usleep(AUDIO_INIT_SLEEP_WAIT*1000);
245 sleepRetry++;
246 } else {
247 audioInitDone = true;
248 }
249 }
250
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700251 if (!getDeviceEventFDs()) {
252 ALOGE("No audio device events detected");
253 }
254
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700255 if (audioInitDone == false) {
Fred Oh144d8742013-11-11 14:26:21 -0800256 ALOGE("Sound Card is empty!!!");
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700257 goto thread_exit;
258 }
259
260 /* soundcards are opened, now get the cpe state nodes */
261 num_snd_cards = mSndCardFd.size();
262 for (i = 0; i < num_snd_cards; i++) {
263 snprintf(path, sizeof(path), "/proc/asound/card%d/cpe0_state", mSndCardFd[i].first);
264 ALOGD("Opening cpe0_state : %s", path);
265 sleepRetry = 0;
266 do {
267 fd = open(path, O_RDONLY);
268 if (fd == -1) {
269 sleepRetry++;
270 ALOGE("CPE state open %s failed %s, Retrying %d",
271 path, strerror(errno), sleepRetry);
272 usleep(CPE_SLEEP_WAIT*1000);
273 } else {
274 ALOGD("cpe state opened: %s", path);
275 mSndCardFd.push_back(std::make_pair(cpe_cnt++, fd));
276 }
277 }while ((fd == -1) && sleepRetry < MAX_CPE_SLEEP_RETRY);
278 }
279 ALOGD("number of sndcards %d CPEs %d", i, cpe_cnt - CPE_MAGIC_NUM);
Fred Oh144d8742013-11-11 14:26:21 -0800280
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700281 pfd = new pollfd[mSndCardFd.size() + mAudioEvents.size()];
282 bzero(pfd, (sizeof(*pfd) * mSndCardFd.size() +
283 sizeof(*pfd) * mAudioEvents.size()));
Fred Oh144d8742013-11-11 14:26:21 -0800284 for (i = 0; i < mSndCardFd.size(); i++) {
285 pfd[i].fd = mSndCardFd[i].second;
286 pfd[i].events = POLLPRI;
287 }
288
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700289 /*insert all audio events*/
290 for(i = 0; i < mAudioEvents.size(); i++) {
291 pfd[i+mSndCardFd.size()].fd = mAudioEvents[i].second;
292 pfd[i+mSndCardFd.size()].events = POLLPRI;
293 }
294
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700295 ALOGD("read for sound card state change before while");
296 for (i = 0; i < mSndCardFd.size(); i++) {
297 if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
Fred Oh144d8742013-11-11 14:26:21 -0800298 ALOGE("Error receiving sound card state event (%s)", strerror(errno));
299 ret = false;
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700300 } else {
Fred Oh144d8742013-11-11 14:26:21 -0800301 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800302 lseek(pfd[i].fd, 0, SEEK_SET);
303
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700304 if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
305 ALOGD("CPE %d state file content: %s before while",
306 mSndCardFd[i].first - CPE_MAGIC_NUM, rd_buf);
307 if (strstr(rd_buf, "OFFLINE")) {
308 ALOGD("CPE state offline");
309 cur_cpe_state = cpe_offline;
310 } else if (strstr(rd_buf, "ONLINE")){
311 ALOGD("CPE state online");
312 cur_cpe_state = cpe_online;
313 } else {
314 ALOGE("ERROR CPE rd_buf %s", rd_buf);
315 }
316 if (cur_cpe_state == cpe_online && !cpe_bootup_complete) {
317 cpe_bootup_complete = true;
318 ALOGD("CPE boot up completed before polling");
319 }
320 prev_cpe_state = cur_cpe_state;
Fred Oh144d8742013-11-11 14:26:21 -0800321 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700322 else {
323 ALOGD("sound card state file content: %s before while",rd_buf);
324 if (strstr(rd_buf, "OFFLINE")) {
325 ALOGE("put cur_state to offline");
326 cur_state = snd_card_offline;
327 } else if (strstr(rd_buf, "ONLINE")){
328 ALOGE("put cur_state to online");
329 cur_state = snd_card_online;
330 } else {
331 ALOGE("ERROR rd_buf %s", rd_buf);
332 }
Fred Oh144d8742013-11-11 14:26:21 -0800333
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700334 ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state );
335 if (cur_state == snd_card_online && !bootup_complete) {
336 bootup_complete = 1;
337 ALOGE("sound card up is deteced before while");
338 ALOGE("bootup_complete set to 1");
339 }
Fred Oh144d8742013-11-11 14:26:21 -0800340 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700341 }
342 }
Fred Oh144d8742013-11-11 14:26:21 -0800343
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700344 ALOGE("read for event state change before while");
345 for (i = 0; i < mAudioEvents.size(); i++){
346 checkEventState(pfd[i+mSndCardFd.size()].fd, i);
347 }
348
Fred Oh144d8742013-11-11 14:26:21 -0800349 while (1) {
350 ALOGD("poll() for sound card state change ");
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700351 if (poll(pfd, (mSndCardFd.size() + mAudioEvents.size()), -1) < 0) {
Fred Oh144d8742013-11-11 14:26:21 -0800352 ALOGE("poll() failed (%s)", strerror(errno));
353 ret = false;
354 break;
355 }
356
357 ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size());
358 for (i = 0; i < mSndCardFd.size(); i++) {
359 if (pfd[i].revents & POLLPRI) {
360 if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700361 ALOGE("Error receiving sound card %d state event (%s)",
362 mSndCardFd[i].first, strerror(errno));
Fred Oh144d8742013-11-11 14:26:21 -0800363 ret = false;
364 } else {
365 rd_buf[8] = '\0';
Fred Oh144d8742013-11-11 14:26:21 -0800366 lseek(pfd[i].fd, 0, SEEK_SET);
367
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700368 if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
369 if (strstr(rd_buf, "OFFLINE"))
370 cur_cpe_state = cpe_offline;
371 else if (strstr(rd_buf, "ONLINE"))
372 cur_cpe_state = cpe_online;
373 else
374 ALOGE("ERROR CPE rd_buf %s", rd_buf);
Fred Oh144d8742013-11-11 14:26:21 -0800375
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700376 if (cpe_bootup_complete && (prev_cpe_state != cur_cpe_state)) {
377 ALOGD("CPE state is %d, nofity AudioSystem", cur_cpe_state);
378 notifyAudioSystem(mSndCardFd[i].first, cur_cpe_state, CPE_STATE);
379 }
380 if (!cpe_bootup_complete && (cur_cpe_state == cpe_online)) {
381 cpe_bootup_complete = true;
382 ALOGD("CPE boot up completed");
383 }
384 prev_cpe_state = cur_cpe_state;
Fred Oh144d8742013-11-11 14:26:21 -0800385 }
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700386 else {
387 ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete);
388 if (strstr(rd_buf, "OFFLINE")) {
389 cur_state = snd_card_offline;
390 } else if (strstr(rd_buf, "ONLINE")){
391 cur_state = snd_card_online;
392 }
Fred Oh144d8742013-11-11 14:26:21 -0800393
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700394 if (bootup_complete) {
395 ALOGV("bootup_complete, so NofityAudioSystem");
396 notifyAudioSystem(mSndCardFd[i].first, cur_state, SND_CARD_STATE);
397 }
398
399 if (cur_state == snd_card_online && !bootup_complete) {
400 bootup_complete = 1;
401 }
Fred Oh144d8742013-11-11 14:26:21 -0800402 }
403 }
404 }
405 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700406 for (i = 0; i < mAudioEvents.size(); i++) {
407 if (pfd[i + mSndCardFd.size()].revents & POLLPRI) {
408 ALOGE("EVENT recieved pfd[i].revents= 0x%x %d",
409 pfd[i + mSndCardFd.size()].revents,
410 mAudioEvents[i].second);
411
412 checkEventState(pfd[i + mSndCardFd.size()].fd, i);
413 }
414 }
Fred Oh144d8742013-11-11 14:26:21 -0800415 }
416
417 putStateFDs(mSndCardFd);
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700418 putDeviceEventFDs();
Fred Oh144d8742013-11-11 14:26:21 -0800419 delete [] pfd;
420
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700421 thread_exit:
Fred Oh144d8742013-11-11 14:26:21 -0800422 ALOGV("Exiting Poll ThreadLoop");
423 return ret;
424 }
425
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700426 void AudioDaemon::notifyAudioSystem(int snd_card,
427 notify_status status,
428 notify_status_type type)
429 {
Fred Oh144d8742013-11-11 14:26:21 -0800430
431 String8 str;
432 char buf[4] = {0,};
433
Bharath Ramachandramurthy2b4f0c42014-06-24 13:20:50 -0700434 if (type == CPE_STATE) {
435 str = "CPE_STATUS=";
436 snprintf(buf, sizeof(buf), "%d", snd_card - CPE_MAGIC_NUM);
437 str += buf;
438 if (status == cpe_online)
439 str += ",ONLINE";
440 else
441 str += ",OFFLINE";
442 }
443 else {
444 str = "SND_CARD_STATUS=";
445 snprintf(buf, sizeof(buf), "%d", snd_card);
446 str += buf;
447 if (status == snd_card_online)
448 str += ",ONLINE";
449 else
450 str += ",OFFLINE";
451 }
Fred Oh144d8742013-11-11 14:26:21 -0800452 ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
453 AudioSystem::setParameters(0, str);
454 }
Tanya Finkelf8d52aa2014-07-16 07:03:15 -0700455
456 void AudioDaemon::notifyAudioSystemEventStatus(const char* event,
457 audio_event_status status) {
458
459 String8 str;
460 str += AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE;
461 str += "=";
462 str += event;
463
464 if (status == audio_event_on)
465 str += ",ON";
466 else
467 str += ",OFF";
468 ALOGD("%s: notifyAudioSystemEventStatus : %s", __func__, str.string());
469 AudioSystem::setParameters(0, str);
470 }
Fred Oh144d8742013-11-11 14:26:21 -0800471}