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