Fix issue 2194140, Part 1.
Submitted on behalf of HK Chen <hk_chen@htc.com>
1) implement ACDB dynamic update for 1) audio playback, 2) audio recording, 3) BT headsets.
2) implement A1026 hard reset recovery mechanism
diff --git a/libaudio-qsd8k/AudioHardware.cpp b/libaudio-qsd8k/AudioHardware.cpp
index 2b3790a..f12a7a8 100644
--- a/libaudio-qsd8k/AudioHardware.cpp
+++ b/libaudio-qsd8k/AudioHardware.cpp
@@ -40,19 +40,6 @@
#include "a1026.h"
}
-enum audio_routes {
- ROUTE_EARPIECE = (1 << 0),
- ROUTE_SPEAKER = (1 << 1),
- ROUTE_BLUETOOTH_SCO = (1 << 2),
- ROUTE_HEADSET = (1 << 3),
- ROUTE_BLUETOOTH_A2DP = (1 << 4),
- ROUTE_NO_MIC_HEADSET = (1 << 5),
- ROUTE_TTY = (1 << 6),
- ROUTE_FM_HEADSET = (1 << 7),
- ROUTE_FM_SPEAKER = (1 << 8),
- ROUTE_ALL = -1UL,
-};
-
#define LOG_SND_RPC 0 // Set to 1 to log sound RPC's
#define TX_PATH (1)
@@ -73,11 +60,12 @@
static int fd_a1026 = -1;
static int old_pathid = -1;
static int new_pathid = -1;
-static int cur_rx_device = 0;
-static int cur_tx_device = 0;
+static int curr_out_device = -1;
+static int curr_mic_device = -1;
static int voice_started = 0;
static int fd_fm_device = -1;
int errCount = 0;
+static void * acoustic;
const uint32_t AudioHardware::inputSamplingRates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};
@@ -88,11 +76,59 @@
// ----------------------------------------------------------------------------
AudioHardware::AudioHardware() :
- mInit(false), mMicMute(true), mBluetoothNrec(true), mBluetoothId(0),
- mA1026Init(false),
- mOutput(0)
+ mA1026Init(false), mInit(false), mMicMute(true),
+ mBluetoothNrec(true), mBluetoothIdTx(0),
+ mBluetoothIdRx(0), mOutput(0)
{
+ int (*snd_get_num)();
+ int (*snd_get_bt_endpoint)(msm_bt_endpoint *);
+ int (*set_acoustic_parameters)();
+
+ struct msm_bt_endpoint *ept;
+
doA1026_init();
+
+ acoustic =:: dlopen("/system/lib/libhtc_acoustic.so", RTLD_NOW);
+ if (acoustic == NULL ) {
+ LOGE("Could not open libhtc_acoustic.so");
+ /* this is not really an error on non-htc devices... */
+ mNumBTEndpoints = 0;
+ mInit = true;
+ return;
+ }
+ set_acoustic_parameters = (int (*)(void))::dlsym(acoustic, "set_acoustic_parameters");
+ if ((*set_acoustic_parameters) == 0 ) {
+ LOGE("Could not open set_acoustic_parameters()");
+ return;
+ }
+
+ int rc = set_acoustic_parameters();
+ if (rc < 0) {
+ LOGE("Could not set acoustic parameters to share memory: %d", rc);
+ }
+
+ snd_get_num = (int (*)(void))::dlsym(acoustic, "snd_get_num");
+ if ((*snd_get_num) == 0 ) {
+ LOGE("Could not open snd_get_num()");
+ }
+
+ mNumBTEndpoints = snd_get_num();
+ LOGD("mNumBTEndpoints = %d", mNumBTEndpoints);
+ mBTEndpoints = new msm_bt_endpoint[mNumBTEndpoints];
+ mInit = true;
+ LOGV("constructed %d SND endpoints)", mNumBTEndpoints);
+ ept = mBTEndpoints;
+ snd_get_bt_endpoint = (int (*)(msm_bt_endpoint *))::dlsym(acoustic, "snd_get_bt_endpoint");
+ if ((*snd_get_bt_endpoint) == 0 ) {
+ LOGE("Could not open snd_get_bt_endpoint()");
+ return;
+ }
+ snd_get_bt_endpoint(mBTEndpoints);
+
+ for (int i = 0; i < mNumBTEndpoints; i++) {
+ LOGE("BT name %s (tx,rx)=(%d,%d)", mBTEndpoints[i].name, mBTEndpoints[i].tx, mBTEndpoints[i].rx);
+ }
+
mInit = true;
}
@@ -279,21 +315,21 @@
}
key = String8(BT_NAME_KEY);
if (param.get(key, value) == NO_ERROR) {
- mBluetoothId = 0;
-#if 0
- for (int i = 0; i < mNumSndEndpoints; i++) {
- if (!strcasecmp(value.string(), mSndEndpoints[i].name)) {
- mBluetoothId = mSndEndpoints[i].id;
+ mBluetoothIdTx = 0;
+ mBluetoothIdRx = 0;
+ for (int i = 0; i < mNumBTEndpoints; i++) {
+ if (!strcasecmp(value.string(), mBTEndpoints[i].name)) {
+ mBluetoothIdTx = mBTEndpoints[i].tx;
+ mBluetoothIdRx = mBTEndpoints[i].rx;
LOGI("Using custom acoustic parameters for %s", value.string());
break;
}
}
-#endif
- if (mBluetoothId == 0) {
+ if (mBluetoothIdTx == 0) {
LOGI("Using default acoustic parameters "
"(%s not in acoustic database)", value.string());
- doRouting(NULL);
}
+ doRouting(NULL);
}
return NO_ERROR;
}
@@ -462,6 +498,8 @@
close(fd);
return -1;
}
+ curr_out_device = out_device;
+ curr_mic_device = mic_device;
Incall:
if (inCall == true && !voice_started) {
@@ -511,9 +549,7 @@
doAudience_A1026_Control(mMode, mRecordState, device);
if (device == (uint32_t)SND_DEVICE_BT || device == (uint32_t)SND_DEVICE_CARKIT) {
- if (mBluetoothId) {
- device = mBluetoothId;
- } else if (!mBluetoothNrec) {
+ if (!mBluetoothNrec) {
device = SND_DEVICE_BT_EC_OFF;
}
}
@@ -596,9 +632,131 @@
return mCurSndDevice;
}
+status_t AudioHardware::updateBT(void)
+{
+ int fd = 0;
+ uint32_t id[2];
+
+ fd = open("/dev/msm_audio_ctl", O_RDWR);
+ if (fd < 0) {
+ LOGE("Cannot open msm_audio_ctl");
+ return -1;
+ }
+ int rc = 0;
+ if (mBluetoothIdRx != -1) {
+ id[0] = mBluetoothIdRx;
+ id[1] = curr_out_device;
+ LOGE("(mBluetoothIdRx, curr_out_device) = (%d, %d)", mBluetoothIdRx, curr_out_device);
+ rc = ioctl(fd, AUDIO_UPDATE_ACDB, &id);
+ if (rc) {
+ LOGE("Cannot update RX ACDB %d, rc=%d", mBluetoothIdRx, rc);
+ close(fd);
+ return -1;
+ } else
+ LOGD("update TX ACDB %d success", mBluetoothIdRx);
+ }
+
+ if (mBluetoothIdTx != -1) {
+ id[0] = mBluetoothIdTx;
+ id[1] = curr_mic_device;
+ LOGE("(mBluetoothIdTx, curr_out_device) = (%d, %d)", mBluetoothIdTx, curr_out_device);
+ rc = ioctl(fd, AUDIO_UPDATE_ACDB, &id);
+ if (rc) {
+ LOGE("Cannot update TX ACDB %d, rc = %d", mBluetoothIdTx, rc);
+ close(fd);
+ return -1;
+ } else
+ LOGD("update TX ACDB %d success", mBluetoothIdTx);
+ }
+ close(fd);
+ return 0;
+}
+
+// always call with mutex held
+status_t AudioHardware::updateACDB(void)
+{
+ int fd = 0;
+ int acdb_id = -1;
+ uint32_t id[2];
+
+ fd = open("/dev/msm_audio_ctl", O_RDWR);
+ if (fd < 0) {
+ LOGE("Cannot open msm_audio_ctl");
+ return -1;
+ }
+
+ if (mMode == AudioSystem::MODE_IN_CALL) {
+ LOGD("skip update ACDB due to in-call");
+ close(fd);
+ return 0;
+ }
+
+ //update RX acdb parameters.
+ if (!checkOutputStandby()) {
+ switch (mCurSndDevice) {
+ case SND_DEVICE_HEADSET:
+ case SND_DEVICE_NO_MIC_HEADSET:
+ case SND_DEVICE_FM_HEADSET:
+ acdb_id = ACDB_ID_HEADSET_PLAYBACK;
+ break;
+ case SND_DEVICE_SPEAKER:
+ case SND_DEVICE_FM_SPEAKER:
+ acdb_id = ACDB_ID_SPKR_PLAYBACK;
+ break;
+ case SND_DEVICE_HEADSET_AND_SPEAKER:
+ acdb_id = ACDB_ID_HEADSET_RINGTONE_PLAYBACK;
+ break;
+ default:
+ break;
+ }
+ }
+ if (acdb_id != -1) {
+ id[0] = acdb_id;
+ id[1] = curr_out_device;
+ if (ioctl(fd, AUDIO_UPDATE_ACDB, &id)) {
+ LOGE("Cannot update RX ACDB %d", acdb_id);
+ close(fd);
+ return -1;
+ } else
+ LOGD("update RX ACDB %d success", acdb_id);
+ }
+
+ //update TX acdb parameters.
+ acdb_id = -1;
+ if (mRecordState) {
+ switch (mCurSndDevice) {
+ case SND_DEVICE_HEADSET:
+ case SND_DEVICE_FM_HEADSET:
+ case SND_DEVICE_FM_SPEAKER:
+ acdb_id = ACDB_ID_EXT_MIC_REC;
+ break;
+ case SND_DEVICE_HANDSET:
+ case SND_DEVICE_NO_MIC_HEADSET:
+ case SND_DEVICE_SPEAKER:
+ acdb_id = ACDB_ID_INT_MIC_REC;
+ break;
+ default:
+ break;
+ }
+ }
+ if (acdb_id != -1) {
+ id[0] = acdb_id;
+ id[1] = curr_mic_device;
+ if (ioctl(fd, AUDIO_UPDATE_ACDB, &id)) {
+ LOGE("Cannot update TX ACDB %d", acdb_id);
+ close(fd);
+ return -1;
+ } else
+ LOGD("update TX ACDB %d success", acdb_id);
+ }
+ close(fd);
+ return 0;
+}
+
status_t AudioHardware::doAudience_A1026_Control(int Mode, bool Record, uint32_t Routes)
{
int rc = 0;
+ int retry = 4;
if (!mA1026Init) {
LOGW("Audience A1026 not initialized.\n");
@@ -696,14 +854,28 @@
if (old_pathid != new_pathid) {
//LOGI("A1026: do ioctl(A1026_SET_CONFIG) to %d\n", new_pathid);
+ do {
+ rc = ioctl(fd_a1026, A1026_SET_CONFIG, &new_pathid);
+ if (!rc) {
+ old_pathid = new_pathid;
+ break;
+ }
+ } while (--retry);
+
+ if (rc < 0) {
+ LOGE("A1026 do hard reset to recover from error!\n");
+ rc = doA1026_init(); /* A1026 needs to do hard reset! */
+ if (!rc) {
rc = ioctl(fd_a1026, A1026_SET_CONFIG, &new_pathid);
if (!rc)
old_pathid = new_pathid;
else
- goto Error;
+ LOGE("A1026 Fatal Error!\n");
+ } else
+ LOGE("A1026 Fatal Error: Re-init A1026 Failed\n");
+ }
}
-Error:
mA1026Lock.unlock();
close(fd_a1026);
fd_a1026 = -1;
@@ -812,6 +984,10 @@
if (sndDevice != -1 && sndDevice != mCurSndDevice) {
ret = doAudioRouteOrMute(sndDevice);
mCurSndDevice = sndDevice;
+ if (mMode == AudioSystem::MODE_IN_CALL && mBluetoothIdTx != 0
+ && sndDevice == SND_DEVICE_BT) {
+ ret = updateBT();
+ } else if (!ret) ret = updateACDB();
}
return ret;
@@ -839,7 +1015,9 @@
result.append(buffer);
snprintf(buffer, SIZE, "\tmBluetoothNrec: %s\n", mBluetoothNrec? "true": "false");
result.append(buffer);
- snprintf(buffer, SIZE, "\tmBluetoothId: %d\n", mBluetoothId);
+ snprintf(buffer, SIZE, "\tmBluetoothIdtx: %d\n", mBluetoothIdTx);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmBluetoothIdrx: %d\n", mBluetoothIdRx);
result.append(buffer);
::write(fd, result.string(), result.size());
return NO_ERROR;
@@ -971,6 +1149,8 @@
LOGV("acquire wakelock");
acquire_wake_lock(PARTIAL_WAKE_LOCK, kOutputWakelockStr);
mStandby = false;
+ Mutex::Autolock lock(mHardware->mLock);
+ mHardware->updateACDB();
}
while (count) {
@@ -1212,20 +1392,19 @@
}
}
- if (support_a1026 == 1) {
- if (mHardware) {
+ if (mState < AUDIO_INPUT_STARTED) {
mHardware->set_mRecordState(1);
+ if (support_a1026 == 1) {
mHardware->doAudience_A1026_Control(mHardware->get_mMode(), 1, mHardware->get_snd_dev());
}
- }
-
- if (mState < AUDIO_INPUT_STARTED) {
if (ioctl(mFd, AUDIO_START, 0)) {
LOGE("Error starting record");
return -1;
}
LOGI("AUDIO_START: start kernel pcm_in driver.");
mState = AUDIO_INPUT_STARTED;
+ Mutex::Autolock lock(mHardware->mLock);
+ mHardware->updateACDB();
}
while (count) {
@@ -1244,9 +1423,9 @@
status_t AudioHardware::AudioStreamInMSM72xx::standby()
{
- if (support_a1026 == 1) {
if (mHardware) {
mHardware->set_mRecordState(0);
+ if (support_a1026 == 1) {
mHardware->doAudience_A1026_Control(mHardware->get_mMode(), 0, mHardware->get_snd_dev());
}
}
diff --git a/libaudio-qsd8k/AudioHardware.h b/libaudio-qsd8k/AudioHardware.h
index 587dbaa..14a2b35 100644
--- a/libaudio-qsd8k/AudioHardware.h
+++ b/libaudio-qsd8k/AudioHardware.h
@@ -73,6 +73,12 @@
#define FM_SPKR ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO
#define SPKR_PHONE_HEADSET_STEREO ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET
+#define ACDB_ID_EXT_MIC_REC 307
+#define ACDB_ID_HEADSET_PLAYBACK 407
+#define ACDB_ID_HEADSET_RINGTONE_PLAYBACK 408
+#define ACDB_ID_INT_MIC_REC 507
+#define ACDB_ID_SPKR_PLAYBACK 607
+
#define SAMP_RATE_INDX_8000 0
#define SAMP_RATE_INDX_11025 1
#define SAMP_RATE_INDX_12000 2
@@ -92,6 +98,12 @@
#define RX_IIR_ENABLE 0x0004
#define RX_IIR_DISABLE 0x0000
+struct msm_bt_endpoint {
+ int tx;
+ int rx;
+ char name[64];
+};
+
struct eq_filter_type {
int16_t gain;
uint16_t freq;
@@ -199,6 +211,8 @@
status_t get_snd_dev();
status_t doAudience_A1026_Control(int Mode, bool Record, uint32_t Routes);
status_t doRouting(AudioStreamInMSM72xx *input);
+ status_t updateACDB();
+ status_t updateBT();
class AudioStreamOutMSM72xx : public AudioStreamOut {
public:
@@ -281,11 +295,13 @@
bool mInit;
bool mMicMute;
bool mBluetoothNrec;
- uint32_t mBluetoothId;
+ uint32_t mBluetoothIdTx;
+ uint32_t mBluetoothIdRx;
AudioStreamOutMSM72xx* mOutput;
SortedVector <AudioStreamInMSM72xx*> mInputs;
- int mNumSndEndpoints;
+ msm_bt_endpoint *mBTEndpoints;
+ int mNumBTEndpoints;
int mCurSndDevice;
friend class AudioStreamInMSM72xx;