2013-11-11 22:26:21 +00:00
|
|
|
/* AudioDaemon.cpp
|
2014-06-24 20:20:50 +00:00
|
|
|
Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
2013-11-11 22:26:21 +00:00
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are
|
|
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
|
|
copyright notice, this list of conditions and the following
|
|
|
|
disclaimer in the documentation and/or other materials provided
|
|
|
|
with the distribution.
|
|
|
|
* Neither the name of The Linux Foundation nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
|
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
|
|
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
|
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
|
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
|
|
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
|
|
|
|
|
|
|
|
#define LOG_TAG "AudioDaemon"
|
|
|
|
#define LOG_NDEBUG 0
|
|
|
|
#define LOG_NDDEBUG 0
|
|
|
|
|
|
|
|
#include <media/AudioSystem.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
|
|
|
|
#include "AudioDaemon.h"
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
#define CPE_MAGIC_NUM 0x2000
|
|
|
|
#define MAX_CPE_SLEEP_RETRY 2
|
|
|
|
#define CPE_SLEEP_WAIT 100
|
|
|
|
|
|
|
|
#define MAX_SLEEP_RETRY 100
|
|
|
|
#define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */
|
|
|
|
|
2013-11-11 22:26:21 +00:00
|
|
|
int bootup_complete = 0;
|
2014-06-24 20:20:50 +00:00
|
|
|
bool cpe_bootup_complete = false;
|
2013-11-11 22:26:21 +00:00
|
|
|
|
|
|
|
namespace android {
|
|
|
|
|
|
|
|
AudioDaemon::AudioDaemon() : Thread(false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioDaemon::~AudioDaemon() {
|
|
|
|
putStateFDs(mSndCardFd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioDaemon::onFirstRef() {
|
|
|
|
ALOGV("Start audiod daemon");
|
2014-05-02 10:22:46 +00:00
|
|
|
run("AudioDaemon", PRIORITY_URGENT_AUDIO);
|
2013-11-11 22:26:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AudioDaemon::binderDied(const wp<IBinder>& who)
|
|
|
|
{
|
|
|
|
requestExit();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AudioDaemon::getStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
int fd;
|
|
|
|
char *ptr, *saveptr;
|
|
|
|
char buffer[128];
|
|
|
|
int line = 0;
|
|
|
|
String8 path;
|
|
|
|
int sndcard;
|
|
|
|
const char* cards = "/proc/asound/cards";
|
|
|
|
|
|
|
|
if ((fp = fopen(cards, "r")) == NULL) {
|
|
|
|
ALOGE("Cannot open %s file to get list of sound cars", cards);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
sndcardFdPair.clear();
|
|
|
|
memset(buffer, 0x0, sizeof(buffer));
|
|
|
|
while ((fgets(buffer, sizeof(buffer), fp) != NULL)) {
|
|
|
|
if (line % 2)
|
|
|
|
continue;
|
|
|
|
ptr = strtok_r(buffer, " [", &saveptr);
|
|
|
|
if (ptr) {
|
|
|
|
path = "/proc/asound/card";
|
|
|
|
path += ptr;
|
|
|
|
path += "/state";
|
|
|
|
ALOGD("Opening sound card state : %s", path.string());
|
|
|
|
fd = open(path.string(), O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
ALOGE("Open %s failed : %s", path.string(), strerror(errno));
|
|
|
|
} else {
|
|
|
|
/* returns vector of pair<sndcard, fd> */
|
|
|
|
sndcard = atoi(ptr);
|
|
|
|
sndcardFdPair.push_back(std::make_pair(sndcard, fd));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALOGV("%s: %d sound cards detected", __func__, sndcardFdPair.size());
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return sndcardFdPair.size() > 0 ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioDaemon::putStateFDs(std::vector<std::pair<int,int> > &sndcardFdPair)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < sndcardFdPair.size(); i++)
|
|
|
|
close(sndcardFdPair[i].second);
|
|
|
|
sndcardFdPair.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t AudioDaemon::readyToRun() {
|
|
|
|
|
|
|
|
ALOGV("readyToRun: open snd card state node files");
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AudioDaemon::threadLoop()
|
|
|
|
{
|
|
|
|
int max = -1;
|
|
|
|
unsigned int i;
|
|
|
|
bool ret = true;
|
2014-06-24 20:20:50 +00:00
|
|
|
notify_status cur_state = snd_card_offline;
|
2013-11-11 22:26:21 +00:00
|
|
|
struct pollfd *pfd = NULL;
|
|
|
|
char rd_buf[9];
|
|
|
|
unsigned int sleepRetry = 0;
|
|
|
|
bool audioInitDone = false;
|
2014-06-24 20:20:50 +00:00
|
|
|
int fd = 0;
|
|
|
|
char path[50];
|
|
|
|
notify_status cur_cpe_state = cpe_offline;
|
|
|
|
notify_status prev_cpe_state = cpe_offline;
|
|
|
|
unsigned int cpe_cnt = CPE_MAGIC_NUM;
|
|
|
|
unsigned int num_snd_cards = 0;
|
2013-11-11 22:26:21 +00:00
|
|
|
|
|
|
|
ALOGV("Start threadLoop()");
|
|
|
|
while (audioInitDone == false && sleepRetry < MAX_SLEEP_RETRY) {
|
|
|
|
if (mSndCardFd.empty() && !getStateFDs(mSndCardFd)) {
|
|
|
|
ALOGE("Sleeping for 100 ms");
|
|
|
|
usleep(AUDIO_INIT_SLEEP_WAIT*1000);
|
|
|
|
sleepRetry++;
|
|
|
|
} else {
|
|
|
|
audioInitDone = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
if (audioInitDone == false) {
|
2013-11-11 22:26:21 +00:00
|
|
|
ALOGE("Sound Card is empty!!!");
|
2014-06-24 20:20:50 +00:00
|
|
|
goto thread_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* soundcards are opened, now get the cpe state nodes */
|
|
|
|
num_snd_cards = mSndCardFd.size();
|
|
|
|
for (i = 0; i < num_snd_cards; i++) {
|
|
|
|
snprintf(path, sizeof(path), "/proc/asound/card%d/cpe0_state", mSndCardFd[i].first);
|
|
|
|
ALOGD("Opening cpe0_state : %s", path);
|
|
|
|
sleepRetry = 0;
|
|
|
|
do {
|
|
|
|
fd = open(path, O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
sleepRetry++;
|
|
|
|
ALOGE("CPE state open %s failed %s, Retrying %d",
|
|
|
|
path, strerror(errno), sleepRetry);
|
|
|
|
usleep(CPE_SLEEP_WAIT*1000);
|
|
|
|
} else {
|
|
|
|
ALOGD("cpe state opened: %s", path);
|
|
|
|
mSndCardFd.push_back(std::make_pair(cpe_cnt++, fd));
|
|
|
|
}
|
|
|
|
}while ((fd == -1) && sleepRetry < MAX_CPE_SLEEP_RETRY);
|
|
|
|
}
|
|
|
|
ALOGD("number of sndcards %d CPEs %d", i, cpe_cnt - CPE_MAGIC_NUM);
|
2013-11-11 22:26:21 +00:00
|
|
|
|
|
|
|
pfd = new pollfd[mSndCardFd.size()];
|
|
|
|
bzero(pfd, sizeof(*pfd) * mSndCardFd.size());
|
|
|
|
for (i = 0; i < mSndCardFd.size(); i++) {
|
|
|
|
pfd[i].fd = mSndCardFd[i].second;
|
|
|
|
pfd[i].events = POLLPRI;
|
|
|
|
}
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
ALOGD("read for sound card state change before while");
|
|
|
|
for (i = 0; i < mSndCardFd.size(); i++) {
|
|
|
|
if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
|
2013-11-11 22:26:21 +00:00
|
|
|
ALOGE("Error receiving sound card state event (%s)", strerror(errno));
|
|
|
|
ret = false;
|
2014-06-24 20:20:50 +00:00
|
|
|
} else {
|
2013-11-11 22:26:21 +00:00
|
|
|
rd_buf[8] = '\0';
|
|
|
|
lseek(pfd[i].fd, 0, SEEK_SET);
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
|
|
|
|
ALOGD("CPE %d state file content: %s before while",
|
|
|
|
mSndCardFd[i].first - CPE_MAGIC_NUM, rd_buf);
|
|
|
|
if (strstr(rd_buf, "OFFLINE")) {
|
|
|
|
ALOGD("CPE state offline");
|
|
|
|
cur_cpe_state = cpe_offline;
|
|
|
|
} else if (strstr(rd_buf, "ONLINE")){
|
|
|
|
ALOGD("CPE state online");
|
|
|
|
cur_cpe_state = cpe_online;
|
|
|
|
} else {
|
|
|
|
ALOGE("ERROR CPE rd_buf %s", rd_buf);
|
|
|
|
}
|
|
|
|
if (cur_cpe_state == cpe_online && !cpe_bootup_complete) {
|
|
|
|
cpe_bootup_complete = true;
|
|
|
|
ALOGD("CPE boot up completed before polling");
|
|
|
|
}
|
|
|
|
prev_cpe_state = cur_cpe_state;
|
2013-11-11 22:26:21 +00:00
|
|
|
}
|
2014-06-24 20:20:50 +00:00
|
|
|
else {
|
|
|
|
ALOGD("sound card state file content: %s before while",rd_buf);
|
|
|
|
if (strstr(rd_buf, "OFFLINE")) {
|
|
|
|
ALOGE("put cur_state to offline");
|
|
|
|
cur_state = snd_card_offline;
|
|
|
|
} else if (strstr(rd_buf, "ONLINE")){
|
|
|
|
ALOGE("put cur_state to online");
|
|
|
|
cur_state = snd_card_online;
|
|
|
|
} else {
|
|
|
|
ALOGE("ERROR rd_buf %s", rd_buf);
|
|
|
|
}
|
2013-11-11 22:26:21 +00:00
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
ALOGD("cur_state=%d, bootup_complete=%d", cur_state, cur_state );
|
|
|
|
if (cur_state == snd_card_online && !bootup_complete) {
|
|
|
|
bootup_complete = 1;
|
|
|
|
ALOGE("sound card up is deteced before while");
|
|
|
|
ALOGE("bootup_complete set to 1");
|
|
|
|
}
|
2013-11-11 22:26:21 +00:00
|
|
|
}
|
2014-06-24 20:20:50 +00:00
|
|
|
}
|
|
|
|
}
|
2013-11-11 22:26:21 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
ALOGD("poll() for sound card state change ");
|
|
|
|
if (poll(pfd, mSndCardFd.size(), -1) < 0) {
|
|
|
|
ALOGE("poll() failed (%s)", strerror(errno));
|
|
|
|
ret = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALOGD("out of poll() for sound card state change, SNDCARD size=%d", mSndCardFd.size());
|
|
|
|
for (i = 0; i < mSndCardFd.size(); i++) {
|
|
|
|
if (pfd[i].revents & POLLPRI) {
|
|
|
|
if (!read(pfd[i].fd, (void *)rd_buf, 8)) {
|
2014-06-24 20:20:50 +00:00
|
|
|
ALOGE("Error receiving sound card %d state event (%s)",
|
|
|
|
mSndCardFd[i].first, strerror(errno));
|
2013-11-11 22:26:21 +00:00
|
|
|
ret = false;
|
|
|
|
} else {
|
|
|
|
rd_buf[8] = '\0';
|
|
|
|
lseek(pfd[i].fd, 0, SEEK_SET);
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
if(mSndCardFd[i].first >= CPE_MAGIC_NUM) {
|
|
|
|
if (strstr(rd_buf, "OFFLINE"))
|
|
|
|
cur_cpe_state = cpe_offline;
|
|
|
|
else if (strstr(rd_buf, "ONLINE"))
|
|
|
|
cur_cpe_state = cpe_online;
|
|
|
|
else
|
|
|
|
ALOGE("ERROR CPE rd_buf %s", rd_buf);
|
|
|
|
|
|
|
|
if (cpe_bootup_complete && (prev_cpe_state != cur_cpe_state)) {
|
|
|
|
ALOGD("CPE state is %d, nofity AudioSystem", cur_cpe_state);
|
|
|
|
notifyAudioSystem(mSndCardFd[i].first, cur_cpe_state, CPE_STATE);
|
|
|
|
}
|
|
|
|
if (!cpe_bootup_complete && (cur_cpe_state == cpe_online)) {
|
|
|
|
cpe_bootup_complete = true;
|
|
|
|
ALOGD("CPE boot up completed");
|
|
|
|
}
|
|
|
|
prev_cpe_state = cur_cpe_state;
|
2013-11-11 22:26:21 +00:00
|
|
|
}
|
2014-06-24 20:20:50 +00:00
|
|
|
else {
|
|
|
|
ALOGV("sound card state file content: %s, bootup_complete=%d",rd_buf, bootup_complete);
|
|
|
|
if (strstr(rd_buf, "OFFLINE")) {
|
|
|
|
cur_state = snd_card_offline;
|
|
|
|
} else if (strstr(rd_buf, "ONLINE")){
|
|
|
|
cur_state = snd_card_online;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bootup_complete) {
|
|
|
|
ALOGV("bootup_complete, so NofityAudioSystem");
|
|
|
|
notifyAudioSystem(mSndCardFd[i].first, cur_state, SND_CARD_STATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur_state == snd_card_online && !bootup_complete) {
|
|
|
|
bootup_complete = 1;
|
|
|
|
}
|
2013-11-11 22:26:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
putStateFDs(mSndCardFd);
|
|
|
|
delete [] pfd;
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
thread_exit:
|
2013-11-11 22:26:21 +00:00
|
|
|
ALOGV("Exiting Poll ThreadLoop");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
void AudioDaemon::notifyAudioSystem(int snd_card,
|
|
|
|
notify_status status,
|
|
|
|
notify_status_type type)
|
|
|
|
{
|
2013-11-11 22:26:21 +00:00
|
|
|
|
|
|
|
String8 str;
|
|
|
|
char buf[4] = {0,};
|
|
|
|
|
2014-06-24 20:20:50 +00:00
|
|
|
if (type == CPE_STATE) {
|
|
|
|
str = "CPE_STATUS=";
|
|
|
|
snprintf(buf, sizeof(buf), "%d", snd_card - CPE_MAGIC_NUM);
|
|
|
|
str += buf;
|
|
|
|
if (status == cpe_online)
|
|
|
|
str += ",ONLINE";
|
|
|
|
else
|
|
|
|
str += ",OFFLINE";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
str = "SND_CARD_STATUS=";
|
|
|
|
snprintf(buf, sizeof(buf), "%d", snd_card);
|
|
|
|
str += buf;
|
|
|
|
if (status == snd_card_online)
|
|
|
|
str += ",ONLINE";
|
|
|
|
else
|
|
|
|
str += ",OFFLINE";
|
|
|
|
}
|
2013-11-11 22:26:21 +00:00
|
|
|
ALOGV("%s: notifyAudioSystem : %s", __func__, str.string());
|
|
|
|
AudioSystem::setParameters(0, str);
|
|
|
|
}
|
|
|
|
}
|