unplugged-vendor/frameworks/av/media/libaudioutilmtk/AudioUtilmtk.cpp

1073 lines
41 KiB
C++

/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* MediaTek Inc. (C) 2010. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#define LOG_TAG "AudioUtilmtk"
#include <media/AudioUtilmtk.h>
#include <media/AudioParameter.h>
#include "AudioParamParser.h"
#define MTK_LOG_ENABLE 1
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <mediautils/BatteryNotifier.h>
namespace android {
KeyedVector<AudioDump::PROP_AUDIO_DUMP, int> mAudioDumpKeyEnableVector;
Mutex mAudioDumpKeyMutex;
static const char * af_dump_log = "vendor.af.dumplog";
const char * const AudioDump::keyAudioDumpMixer = "vendor.af.mixer.pcm";
const char * const AudioDump::keyAudioDumpTrack = "vendor.af.track.pcm";
const char * const AudioDump::keyAudioDumpOffload = "vendor.af.offload.write.raw";
const char * const AudioDump::keyAudioDumpResampler = "vendor.af.resampler.pcm";
const char * const AudioDump::keyAudioDumpMixerEnd = "vendor.af.mixer.end.pcm";
const char * const AudioDump::keyAudioDumpRecord = "vendor.af.record.dump.pcm";
const char * const AudioDump::keyAudioDumpEffect = "vendor.af.effect.pcm";
const char * const AudioDump::keyAudioDumpDrc = "vendor.af.mixer.drc.pcm";
const char * const AudioDump::keyAudioDumpLog = "vendor.af.dumplog";
const char * const AudioDump::keyAudioDumpAAudio = "vendor.aaudio.pcm";
const char * AudioDump::audioDumpPropertyStr[] = {
AudioDump::keyAudioDumpMixer,
AudioDump::keyAudioDumpTrack,
AudioDump::keyAudioDumpOffload,
AudioDump::keyAudioDumpResampler,
AudioDump::keyAudioDumpMixerEnd,
AudioDump::keyAudioDumpRecord,
AudioDump::keyAudioDumpEffect,
AudioDump::keyAudioDumpDrc,
AudioDump::keyAudioDumpLog,
AudioDump::keyAudioDumpAAudio,
};
const char * const AudioDump::af_track_pcm = "/data/debuglogger/audio_dump/af_track_pcm";
const char * const AudioDump::af_mixer_write_pcm = "/data/debuglogger/audio_dump/af_mixer_write";
const char * const AudioDump::af_mixer_end_pcm = "/data/debuglogger/audio_dump/mixer_end";
const char * const AudioDump::af_offload_write_raw = "/data/debuglogger/audio_dump/af_offload_write_raw";
const char * const AudioDump::af_record_read_pcm = "/data/debuglogger/audio_dump/af_record_read";
const char * const AudioDump::af_record_convert_pcm = "/data/debuglogger/audio_dump/af_record_convert";
const char * const AudioDump::af_effect_pcm = "/data/debuglogger/audio_dump/af_effect_pcm";
const char * const AudioDump::af_mixer_drc_pcm_before = "/data/debuglogger/audio_dump/mixer_drc_before";
const char * const AudioDump::af_mixer_drc_pcm_after = "/data/debuglogger/audio_dump/mixer_drc_after";
const char * const AudioDump::af_resampler_in_pcm = "/data/debuglogger/audio_dump/af_mixer_resampler_in";
const char * const AudioDump::af_resampler_out_pcm = "/data/debuglogger/audio_dump/af_mixer_resampler_out";
const char * const AudioDump::aaudio_share_dl = "/data/debuglogger/audio_dump/aaudio_share_dl";
const char * const AudioDump::aaudio_share_ul = "/data/debuglogger/audio_dump/aaudio_share_ul";
const char * const AudioDump::aaudio_exclusive_dl = "/data/debuglogger/audio_dump/aaudio_exclusive_dl";
const char * const AudioDump::aaudio_exclusive_ul = "/data/debuglogger/audio_dump/aaudio_exclusive_ul";
bool FeatureOption::MTK_AUDIOMIXER_ENABLE_DRC = false;
int FeatureOption:: MTK_ENABLE_STEREO_SPEAKER = 0;
bool FeatureOption::MTK_USB_PHONECALL = true;
bool FeatureOption::MTK_TTY_SUPPORT = false;
bool FeatureOption::MTK_HIFIAUDIO_SUPPORT = false;
bool FeatureOption::MTK_BESLOUDNESS_ENABLE = false;
bool FeatureOption::MTK_AUDIO_GAIN_TABLE = false;
bool FeatureOption::MTK_AUDIO_GAIN_NVRAM = false;
bool FeatureOption::MTK_FM_ENABLE = true;
bool FeatureOption::MTK_AURISYS_FRAMEWORK_SUPPORT = false;
bool FeatureOption::MTK_BT_HEARING_AID_SUPPORT = false;
bool FeatureOption::MTK_BT_HEARING_AID_USING_AOSP_FMW = false;
bool FeatureOption::MTK_TC10_FEATURE = false;
bool FeatureOption::MTK_TC10_IN_HOUSE = false;
bool FeatureOption::MTK_AUDIO_A2DP_LATENCY_IMPROVE = false;
bool FeatureOption::MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON = true;
bool FeatureOption::MTK_BLE_PHONECALL = true;
bool FeatureOption::MTK_CRS_FEATURE = true;
const char * const FeatureOption::foName_MTK_BESLOUDNESS_RUN_WITH_HAL = "MTK_BESLOUDNESS_RUN_WITH_HAL";
const char * const FeatureOption::foName_MTK_BESLOUDNESS_SUPPORT = "MTK_BESLOUDNESS_SUPPORT";
const char * const FeatureOption::foName_MTK_AUDIO_NUMBER_OF_SPEAKER = "MTK_AUDIO_NUMBER_OF_SPEAKER";
const char * const FeatureOption::foName_MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT = "MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT";
const char * const FeatureOption::foName_MTK_HIFIAUDIO_SUPPORT = "MTK_HIFIAUDIO_SUPPORT";
const char * const FeatureOption::foName_MTK_AURISYS_FRAMEWORK_SUPPORT = "MTK_AURISYS_FRAMEWORK_SUPPORT";
const char * const FeatureOption::foName_MTK_USB_PHONECALL = "MTK_USB_PHONECALL";
const char * const FeatureOption::foName_MTK_TTY_SUPPORT = "MTK_TTY_SUPPORT";
const char * const FeatureOption::foName_MTK_BT_HEARING_AID_SUPPORT = "MTK_BT_HEARING_AID_SUPPORT";
const char * const FeatureOption::foName_MTK_BT_HEARING_AID_USING_AOSP_FMW = "MTK_BT_HEARING_AID_USING_AOSP_FMW";
const char * const FeatureOption::foName_MTK_TC10_FEATURE = "MTK_TC10_FEATURE";
const char * const FeatureOption::foName_MTK_TC10_IN_HOUSE = "MTK_TC10_IN_HOUSE";
const char * const FeatureOption::foName_MTK_AUDIO_A2DP_LATENCY_IMPROVE = "MTK_AUDIO_A2DP_LATENCY_IMPROVE";
const char * const FeatureOption::foName_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON = "MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON";
const char * const FeatureOption::foName_MTK_BLE_PHONECALL = "MTK_BLE_PHONECALL";
struct WAVEFORMATEX {
uint16_t wFormatTag;
uint16_t nChannels;
uint32_t nSamplesPerSec;
uint32_t nAvgBytesPerSec;
uint16_t nBlockAlign;
uint16_t wBitsPerSample;
uint16_t cbSize;
WAVEFORMATEX() {
wFormatTag = 0;
nChannels = 0;
nSamplesPerSec = 0;
nAvgBytesPerSec = 0;
nBlockAlign = 0;
wBitsPerSample = 0;
cbSize = 0;
}
};
struct WavFormatHeader
{
char ckID[5]; // 4 : Chunk ID: "RIFF"
uint32_t cksize; // 4: Chunk size: File length - 8
char WAVEID[5]; // 4: WAVE ID: "WAVE"
// Format Chunk
char FormatckID[5]; // 4: "fmt "
uint32_t Formatcksize; // 4: Chunk size: 16 or 18 or 40 ( We will use 18, no extensiable format. )
char DataID[5]; // 4: "data"
uint32_t Datacksize; // 4: Chunk size: Data Size
WAVEFORMATEX WaveFormatEx;
WavFormatHeader()
: cksize(0),
Formatcksize(18),
Datacksize(0)
{
strncpy(ckID, "RIFF", sizeof(ckID));
strncpy(WAVEID, "WAVE", sizeof(WAVEID));
strncpy(FormatckID, "fmt ", sizeof(FormatckID));
strncpy(DataID, "data", sizeof(DataID));
}
};
// This structure will be written to the file header
struct AudioDumpFileInfo
{
audio_format_t format;
uint32_t sampleRate;
uint32_t channelCount;
int size;
AudioDumpFileInfo()
{
format = AUDIO_FORMAT_INVALID;
sampleRate = 0;
channelCount = 0;
size = 0;
}
};
struct AudioDumpBuffer
{
void *pBufBase;
int changeCount; // The serial number of the file
int allocBufSize;
AudioDumpFileInfo fileInfo;
AudioDumpBuffer()
{
pBufBase = NULL;
changeCount = 0;
allocBufSize = 0;
}
};
#define AUDIO_DUMP_BUFFER_COUNT_MAX 32 // How many buffer will combine
#define AUDIO_DUMP_FILE_WAV_HEADER_SIZE 46 //46 is wav header
pthread_t hAudioDumpThread = 0;
pthread_cond_t AudioDataNotifyEvent;
pthread_mutex_t AudioDataNotifyMutex;
Mutex mAudioDumpMutex;
Mutex mAudioDumpFileMutex;
KeyedVector<String8, Vector<AudioDumpBuffer *>* > mAudioDumpFileVector; ///< The queue buffer waiting for write
///< The first element of Vector<AudioDumpBuffer *> is the previous buffer info.
KeyedVector<String8, Vector<AudioDumpBuffer *>* > mAudioDumpQueueVector;
#define AUDIO_DUMP_FILE_DELAY_TIME_KEY "audiodump.filedelaytime"
int mAudioDumpSleepTime = 2;
uint32_t mAudioDumpFileIoDelayTime = 0;
FILE* fopen_rb(String8 filePath)
{
FILE * fp = fopen(filePath.string(), "rb+");
if (mAudioDumpFileIoDelayTime > 0) {
usleep(mAudioDumpFileIoDelayTime * 1000);
}
if (fp == NULL) {
ALOGV("fopen_rb() file(%s) rb+ fail, open with ab+", filePath.string());
fp= fopen(filePath.string(), "ab+");
if (mAudioDumpFileIoDelayTime > 0) {
usleep(mAudioDumpFileIoDelayTime * 1000);
}
}
if (fp == NULL) {
// ALOGE("fopen_rb() file(%s) fail", filePath.string());
return NULL;
}
return fp;
}
size_t fwrite_s(const void * ptr, size_t size, size_t count, FILE * stream)
{
size_t ret = fwrite(ptr, size, count, stream);
if (ret > 0 && mAudioDumpFileIoDelayTime > 0) {
usleep(mAudioDumpFileIoDelayTime * 1000);
}
return ret;
}
void fseek_s(FILE * stream, long int offset, int origin)
{
int ret = fseek(stream, offset, origin);
if (ret == 0 && mAudioDumpFileIoDelayTime > 0) {
usleep(mAudioDumpFileIoDelayTime * 1000);
}
}
size_t fread_s (void * ptr, size_t size, size_t count, FILE * stream)
{
size_t ret = fread(ptr, size, count, stream);
if (ret > 0 && mAudioDumpFileIoDelayTime > 0) {
usleep(mAudioDumpFileIoDelayTime * 1000);
}
return ret;
}
void WriteNewWaveHeader(FILE *fp, AudioDumpBuffer audioBuffer)
{
WavFormatHeader wavHeader;
void* tmpBuffer = malloc(46);
if(!tmpBuffer) {
ALOGE("%s(): malloc fail!", __FUNCTION__);
return;
}
if (audioBuffer.fileInfo.format == AUDIO_FORMAT_PCM_FLOAT) {
wavHeader.WaveFormatEx.wFormatTag = 3; // IEEE Float
wavHeader.WaveFormatEx.wBitsPerSample = 32;
} else {
wavHeader.WaveFormatEx.wFormatTag = 1; // PCM
if (audioBuffer.fileInfo.format == AUDIO_FORMAT_PCM_8_BIT) {
wavHeader.WaveFormatEx.wBitsPerSample = 8;
} else if (audioBuffer.fileInfo.format == AUDIO_FORMAT_PCM_16_BIT) {
wavHeader.WaveFormatEx.wBitsPerSample = 16;
} else if (audioBuffer.fileInfo.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
wavHeader.WaveFormatEx.wBitsPerSample = 24;
} else if (audioBuffer.fileInfo.format == AUDIO_FORMAT_PCM_8_24_BIT ||
audioBuffer.fileInfo.format == AUDIO_FORMAT_PCM_32_BIT) {
wavHeader.WaveFormatEx.wBitsPerSample = 32;
}
}
wavHeader.cksize = audioBuffer.fileInfo.size + 38; // 46 - 8
wavHeader.Datacksize = audioBuffer.fileInfo.size;
wavHeader.WaveFormatEx.nChannels = audioBuffer.fileInfo.channelCount;
wavHeader.WaveFormatEx.nSamplesPerSec = audioBuffer.fileInfo.sampleRate;
wavHeader.WaveFormatEx.nAvgBytesPerSec = wavHeader.WaveFormatEx.nSamplesPerSec * wavHeader.WaveFormatEx.nChannels
* wavHeader.WaveFormatEx.wBitsPerSample / 8;
wavHeader.WaveFormatEx.nBlockAlign = wavHeader.WaveFormatEx.nChannels * wavHeader.WaveFormatEx.wBitsPerSample / 8;
wavHeader.WaveFormatEx.cbSize = 0;
int pos = 0;
memcpy((char*)tmpBuffer + pos, &wavHeader.ckID, 4); pos += 4;
memcpy((char*)tmpBuffer + pos, &wavHeader.cksize, 4); pos += 4;
memcpy((char*)tmpBuffer + pos, &wavHeader.WAVEID, 4); pos += 4;
memcpy((char*)tmpBuffer + pos, &wavHeader.FormatckID, 4); pos += 4;
memcpy((char*)tmpBuffer + pos, &wavHeader.Formatcksize, 4); pos += 4;
memcpy((char*)tmpBuffer + pos, &wavHeader.WaveFormatEx, 18); pos += 18;
memcpy((char*)tmpBuffer + pos, &wavHeader.DataID, 4); pos += 4;
memcpy((char*)tmpBuffer + pos, &wavHeader.Datacksize, 4); pos += 4;
fwrite_s(tmpBuffer, 46, 1, fp);
free(tmpBuffer);
tmpBuffer = NULL;
}
void UpdateWaveHeader(FILE *fp, AudioDumpBuffer audioBuffer)
{
fseek_s(fp, 0, SEEK_END);
if (ftell(fp) == 0) {
WriteNewWaveHeader(fp, audioBuffer);
} else {
WavFormatHeader wavHeader;
void* tmpBuffer = malloc(46);
if(!tmpBuffer) {
ALOGE("%s(): malloc fail!", __FUNCTION__);
return;
}
fseek_s(fp, 0, SEEK_SET);
if (fread_s((char*)tmpBuffer, 46, 1, fp) <= 0) {
free(tmpBuffer);
tmpBuffer = NULL;
return;
}
memcpy((char*)(&wavHeader.cksize), (char*)tmpBuffer + 4, 4);
wavHeader.cksize += audioBuffer.fileInfo.size;
memcpy((char*)tmpBuffer + 4, &wavHeader.cksize, 4);
memcpy((char*)(&wavHeader.Datacksize), (char*)tmpBuffer + 42, 4);
wavHeader.Datacksize += audioBuffer.fileInfo.size;
memcpy((char*)tmpBuffer + 42, &wavHeader.Datacksize, 4);
fseek_s(fp, 0, SEEK_SET);
fwrite_s((char*)tmpBuffer, 46, 1, fp);
free(tmpBuffer);
tmpBuffer = NULL;
}
}
void UpdateWaveHeader_f(String8 filePath, AudioDumpBuffer audioBuffer)
{
FILE *fp = fopen_rb(filePath);
if (fp != NULL) {
//ALOGD("UpdateWaveHeader_f START filePath(%s)", filePath.string());
UpdateWaveHeader(fp, audioBuffer);
if (fclose(fp) != 0) {
ALOGE("%s(): Couldn't close dump file", __FUNCTION__);
}
}
}
void WriteAudioBuffer(FILE *fp, AudioDumpBuffer audioBuffer)
{
fwrite_s(audioBuffer.pBufBase, audioBuffer.fileInfo.size, 1, fp);
//ALOGD("free %p, %d", audioBuffer.pBufBase, audioBuffer.fileInfo.size);
free(audioBuffer.pBufBase);
audioBuffer.pBufBase = NULL;
}
void UpdateAllWaveHeader()
{
//int FileVectorSize = mAudioDumpFileVector.size();
for (size_t i = 0; i < mAudioDumpFileVector.size(); i++) {
String8 filePathPCM = mAudioDumpFileVector.keyAt(i);
Vector<AudioDumpBuffer *>*pvector = (mAudioDumpFileVector.valueAt(i));
int BufferVectorSize = (*pvector).size();
if (BufferVectorSize == 1) { // Only Header info.
String8 filePathWav = filePathPCM;
AudioDumpBuffer *pLastBufferInfo = (*pvector)[0];
if (pLastBufferInfo->changeCount == 0) {
filePathWav = String8::format("%s.wav", filePathPCM.string());
} else {
filePathWav = String8::format("%s.%d.wav", filePathPCM.string(), pLastBufferInfo->changeCount);
}
UpdateWaveHeader_f(filePathWav, *pLastBufferInfo);
bool bDeleted = false;
if ((*pvector).size() == 1) {
(*pvector).removeAt(0);
delete pLastBufferInfo;
pLastBufferInfo = NULL;
mAudioDumpFileVector.removeItem(filePathPCM);
delete pvector;
pvector = NULL;
bDeleted = true;
i--;
}
if (bDeleted) {
//break; // Break cause the vector size is changed.
}
}
}
}
void PushBufferFromeQueueToVector(String8 filePath, AudioDumpBuffer *newDumpBuffer)
{
AudioDumpBuffer *newInBuffer = newDumpBuffer;
Vector<AudioDumpBuffer *> *pDumpBufferVector = NULL;
ssize_t index = mAudioDumpFileVector.indexOfKey(filePath);
if (index < 0) {
pDumpBufferVector = new Vector<AudioDumpBuffer *>;
mAudioDumpFileVector.add(filePath, pDumpBufferVector);
} else {
pDumpBufferVector = mAudioDumpFileVector.valueAt(index);
}
if (pDumpBufferVector->size() == 0) { // No previous buffer info, create a new one.
AudioDumpBuffer *lastInfoBuffer = new AudioDumpBuffer();
memcpy(lastInfoBuffer, newInBuffer, sizeof(AudioDumpBuffer));
lastInfoBuffer->pBufBase = NULL; // We don't care this parameter in last info.
lastInfoBuffer->fileInfo.size = 0; // The size that had writtn to file. Set to 0 here since we havn't write anything.
pDumpBufferVector->add(lastInfoBuffer);
}
pDumpBufferVector->add(newInBuffer);
}
void ProcessBufferQueue(bool bFlush)
{
if (AUDIO_DUMP_BUFFER_COUNT_MAX == 1) {
bFlush = true;
}
Vector<AudioDumpBuffer *> *pQueueBufferVector = NULL;
Vector<String8> keyVector;
mAudioDumpMutex.lock();
int size = mAudioDumpQueueVector.size();
for (int i = 0; i < size; i++) {
String8 key = mAudioDumpQueueVector.keyAt(i);
keyVector.add(key);
}
mAudioDumpMutex.unlock();
for (size_t i = 0; i < keyVector.size(); i++) {
int allocBufSize = 0;
int currBufSize = 0;
int mergeBufSize = 0;
mAudioDumpMutex.lock();
pQueueBufferVector = mAudioDumpQueueVector.valueFor(keyVector[i]);
int queueSize = (*pQueueBufferVector).size();
mAudioDumpMutex.unlock();
while (queueSize >= 2) {
mAudioDumpMutex.lock();
AudioDumpBuffer *newQueueBuffer = (*pQueueBufferVector)[0];
AudioDumpBuffer *newQueueBuffer2 = (*pQueueBufferVector)[1];
mAudioDumpMutex.unlock();
if (memcmp(&(newQueueBuffer->fileInfo),
&(newQueueBuffer2->fileInfo),
sizeof(AudioDumpFileInfo) - sizeof(int)) != 0) { // Compare format/sample rate/channel, excluding size
PushBufferFromeQueueToVector(keyVector[i], newQueueBuffer);
mAudioDumpMutex.lock();
pQueueBufferVector->removeAt(0);
mAudioDumpMutex.unlock();
} else {
currBufSize = newQueueBuffer->fileInfo.size;
mergeBufSize = newQueueBuffer2->fileInfo.size;
// allocate a big buffer to merge data
if (newQueueBuffer->allocBufSize == 0) {
void *pBufTemp = newQueueBuffer->pBufBase;
allocBufSize = currBufSize * AUDIO_DUMP_BUFFER_COUNT_MAX;
newQueueBuffer->allocBufSize = allocBufSize;
newQueueBuffer->pBufBase = (char*)malloc(allocBufSize);
if (newQueueBuffer->pBufBase != NULL) {
memcpy((char*)newQueueBuffer->pBufBase, pBufTemp, currBufSize);
} else {
newQueueBuffer->allocBufSize = 0;
//error handle?
ALOGE("%s(): Error! Not enough memory for audio dump buffer size=%d", __FUNCTION__, allocBufSize);
}
free(pBufTemp);
pBufTemp = NULL;
}
if ((newQueueBuffer->pBufBase != NULL) && (newQueueBuffer->allocBufSize >= currBufSize + mergeBufSize)) {
memcpy((char*)(newQueueBuffer->pBufBase) + currBufSize,
(char*)(newQueueBuffer2->pBufBase), mergeBufSize);
newQueueBuffer->fileInfo.size += mergeBufSize;
mAudioDumpMutex.lock();
pQueueBufferVector->removeAt(1);
mAudioDumpMutex.unlock();
free(newQueueBuffer2->pBufBase);
newQueueBuffer2->pBufBase = NULL;
delete newQueueBuffer2;
newQueueBuffer2 = NULL;
} else {
PushBufferFromeQueueToVector(keyVector[i], newQueueBuffer);
mAudioDumpMutex.lock();
pQueueBufferVector->removeAt(0);
mAudioDumpMutex.unlock();
}
}
queueSize--;
}
if (bFlush && queueSize == 1) {
//ALOGD("Flush data");
mAudioDumpMutex.lock();
AudioDumpBuffer *newQueueBuffer = (*pQueueBufferVector)[0];
mAudioDumpMutex.unlock();
PushBufferFromeQueueToVector(keyVector[i], newQueueBuffer);
mAudioDumpMutex.lock();
pQueueBufferVector->removeItemsAt(0);
mAudioDumpMutex.unlock();
queueSize--;
}
}
}
void *AudioDumpThread(void *arg __attribute__((unused)))
{
pthread_detach(pthread_self());
bool bHasdata = false;
bool bFlush = false;
int iNoDataCount = 0;
int iLoopCount = 0;
ALOGV("AudioDumpThread(%ld) start", hAudioDumpThread);
id_t tid = gettid();
int priority = -10;
int ret;
//ret = getpriority(PRIO_PROCESS, tid);
//ALOGD("Thread(%d) priority = %d", tid, ret);
ret = setpriority(PRIO_PROCESS, tid, priority);
if (ret != 0) {
ALOGE("AudioDumpThread setpriority fail. tid(%d), priority(%d) ",
tid, priority);
}
//ret = getpriority(PRIO_PROCESS, tid);
//ALOGD("Thread(%d) priority = %d", tid, ret);
while (1) {
ProcessBufferQueue(bFlush);
bFlush = false;
bHasdata = false;
size_t FileVectorSize = mAudioDumpFileVector.size();
for (size_t i = 0; i < FileVectorSize; i++) {
String8 filePathPCM = mAudioDumpFileVector.keyAt(i);
Vector<AudioDumpBuffer *>* pvector = (mAudioDumpFileVector.valueAt(i));
int BufferVectorSize = (*pvector).size();
if (BufferVectorSize > 1) {
bHasdata = true;
FILE * fpWav = NULL;
String8 filePathWav = filePathPCM;
AudioDumpBuffer *pLastBufferInfo = (*pvector)[0];
if (pLastBufferInfo == NULL) {
ALOGE("Array index error!!![%s]", filePathPCM.string());
continue;
}
//get the dump file name
if (pLastBufferInfo->changeCount == 0) {
filePathWav = String8::format("%s.wav", filePathPCM.string());
} else {
filePathWav = String8::format("%s.%d.wav", filePathPCM.string(), pLastBufferInfo->changeCount);
}
// create dump folder if need
int ret = AudioDump::checkPath(filePathWav.string());
if (ret < 0) {
ALOGE("dump %s fail!!!", filePathWav.string());
continue;
}
while (BufferVectorSize > 1) {
AudioDumpBuffer *pAudioBuffer = (*pvector)[1];
if (pAudioBuffer == NULL || pLastBufferInfo == NULL) {
//ALOGE("AudioDumpThread null buffer error!!!!");
break;
}
// if the format is changed, we use a new file name
if (memcmp(&(pAudioBuffer->fileInfo), &(pLastBufferInfo->fileInfo),
sizeof(AudioDumpFileInfo) - sizeof(int)) != 0) {
if (fpWav != NULL) {
if (fclose(fpWav) != 0) {
ALOGE("%s(): Couldn't close dump file", __FUNCTION__);
}
fpWav = NULL;
}
UpdateWaveHeader_f(filePathWav, *pLastBufferInfo);
int changeCount = pLastBufferInfo->changeCount + 1;
memcpy(pLastBufferInfo, pAudioBuffer, sizeof(AudioDumpBuffer));
pLastBufferInfo->changeCount = changeCount;
pLastBufferInfo->fileInfo.size = 0;
filePathWav = String8::format("%s.%d.wav", filePathPCM.string(), pLastBufferInfo->changeCount);
}
// open the dump file, and write new header if need
if (fpWav == NULL) {
fpWav = fopen(filePathWav.string(), "ab+");
if (fpWav != NULL) {
fseek_s(fpWav, 0, SEEK_END);
if (ftell(fpWav) == 0) {
// Write Header
WriteNewWaveHeader(fpWav, *pLastBufferInfo);
}
}
}
// write audio buffer
if (fpWav != NULL) {
WriteAudioBuffer(fpWav, *pAudioBuffer);
pLastBufferInfo->fileInfo.size += pAudioBuffer->fileInfo.size;
(*pvector).removeAt(1);
delete pAudioBuffer;
pAudioBuffer = NULL;
BufferVectorSize--;
}
}
if (fpWav != NULL) {
if (fclose(fpWav) != 0) {
ALOGE("%s(): Couldn't close dump file.", __FUNCTION__);
}
fpWav = NULL;
}
}
}
if (!bHasdata) {
iNoDataCount++;
if (iNoDataCount >= 2 * AUDIO_DUMP_BUFFER_COUNT_MAX) { // wait 640ms
bFlush = true;
iLoopCount = 0;
}
if (iNoDataCount >= 2 * AUDIO_DUMP_BUFFER_COUNT_MAX + 1) { // wait 641ms
UpdateAllWaveHeader();
}
if (iNoDataCount >= 300) { // 3s
mAudioDumpMutex.lock();
mAudioDumpSleepTime = -1;
mAudioDumpMutex.unlock();
//ALOGD("AudioDumpThread, wait for new data dump\n");
pthread_mutex_lock(&AudioDataNotifyMutex);
pthread_cond_wait(&AudioDataNotifyEvent, &AudioDataNotifyMutex);
pthread_mutex_unlock(&AudioDataNotifyMutex);
//ALOGD("AudioDumpThread, PCM data dump again\n");
} else {
mAudioDumpMutex.lock();
mAudioDumpSleepTime = 10;
mAudioDumpMutex.unlock();
usleep(mAudioDumpSleepTime * 1000);
}
} else {
iNoDataCount = 0;
mAudioDumpMutex.lock();
mAudioDumpSleepTime = 2;
mAudioDumpMutex.unlock();
usleep(mAudioDumpSleepTime * 1000);
}
if (++iLoopCount >= 4 * AUDIO_DUMP_BUFFER_COUNT_MAX) {
bFlush = true;
iLoopCount = 0;
}
}
ALOGD("AudioDumpThread exit hAudioDumpThread=%ld", hAudioDumpThread);
hAudioDumpThread = 0;
pthread_exit(NULL);
return 0;
}
// Audio Dump Thread E
//class AudioDump
void AudioDump::dump(const char * filepath, void * buffer, int count)
{
{ // mAudioDumpKeyMutex region
Mutex::Autolock _l(mAudioDumpKeyMutex);
ssize_t index = mAudioDumpKeyEnableVector.indexOfKey(PROP_AUDIO_DUMP_LOG);
if (index < 0) { // new add
int bflag = (int)property_get_bool(af_dump_log, false);
mAudioDumpKeyEnableVector.add(PROP_AUDIO_DUMP_LOG, bflag);
}
}
int ret = checkPath(filepath);
if (ret < 0) {
// ALOGE("dump fail!!!");
} else {
FILE * fp= fopen(filepath, "ab+");
if (fp != NULL) {
fwrite_s(buffer, 1, count, fp);
if (fclose(fp) != 0) {
ALOGE("%s(): Couldn't close dump file", __FUNCTION__);
}
if (mAudioDumpKeyEnableVector.valueFor(PROP_AUDIO_DUMP_LOG) > 0) {
ALOGD("dump() %s(%d)", filepath, count); // For dump analysis
} else {
ALOGV("dump() %s(%d)", filepath, count); // For dump analysis
}
} else {
//ALOGE("dump %s fail",property);
}
}
}
void AudioDump::threadDump(const char * path, void * buffer, int count, audio_format_t format,
uint32_t sampleRate, uint32_t channelCount)
{
{ // mAudioDumpKeyMutex region
Mutex::Autolock _l(mAudioDumpKeyMutex);
ssize_t index = mAudioDumpKeyEnableVector.indexOfKey(PROP_AUDIO_DUMP_LOG);
if (index < 0) { // new add
int bflag = (int)property_get_bool(af_dump_log, false);
mAudioDumpKeyEnableVector.add(PROP_AUDIO_DUMP_LOG, bflag);
}
}
{
Mutex::Autolock _l(mAudioDumpMutex);
if (hAudioDumpThread == 0) {
char value[PROPERTY_VALUE_MAX] = {};
property_get(AUDIO_DUMP_FILE_DELAY_TIME_KEY, value, "2");
mAudioDumpFileIoDelayTime = atoi(value);
//create PCM data dump thread here
int ret = pthread_create(&hAudioDumpThread, NULL, AudioDumpThread, NULL);
if (ret != 0) {
// ALOGE("hAudioDumpThread create fail!!!");
} else {
// ALOGD("hAudioDumpThread=%p created", hAudioDumpThread);
}
/*struct sched_param sched;
sched.sched_priority = 0;
ret = pthread_setschedparam( hAudioDumpThread, SCHED_OTHER, &sched );
if (ret != 0)
{
ALOGE("pthread_setschedparam() fail!!!");
}*/
ret = pthread_cond_init(&AudioDataNotifyEvent, NULL);
if (ret != 0) {
ALOGE("AudioDataNotifyEvent create fail!!!");
}
ret = pthread_mutex_init(&AudioDataNotifyMutex, NULL);
if (ret != 0) {
ALOGE("AudioDataNotifyMutex create fail!!!");
}
}
}
pushBufferInfo(path, buffer, count, format, sampleRate, channelCount);
{
Mutex::Autolock _l(mAudioDumpKeyMutex);
if (mAudioDumpKeyEnableVector.valueFor(PROP_AUDIO_DUMP_LOG) > 0) {
ALOGD("threadDump() %s(%d)", path, count); // For dump analysis
} else {
ALOGV("threadDump() %s(%d)", path, count); // For dump analysis
}
}
}
bool AudioDump::getProperty(AudioDump::PROP_AUDIO_DUMP key)
{
Mutex::Autolock _l(mAudioDumpKeyMutex);
// get property from cache
ssize_t index = mAudioDumpKeyEnableVector.indexOfKey(key);
if (index < 0) { // new add
int bflag = (int)property_get_bool(AudioDump::audioDumpPropertyStr[key], false);
mAudioDumpKeyEnableVector.add(key, bflag);
return bflag;
}
return mAudioDumpKeyEnableVector[index];
}
int AudioDump::checkPath(const char * path)
{
char tmp[PATH_MAX];
unsigned i = 0;
while (*path) {
tmp[i] = *path;
if (*path == '/' && i) {
tmp[i] = '\0';
Mutex::Autolock _l(mAudioDumpFileMutex);
if (access(tmp, F_OK) != 0) {
if (mkdir(tmp, 0770) == -1) {
// ALOGE("mkdir error! %s",(char*)strerror(errno));
return -1;
}
}
tmp[i] = '/';
}
i++;
path++;
}
return 0;
}
unsigned long AudioDump::getDumpSize(const char * path)
{
unsigned long dump_size_in_queue = 0;
Vector<AudioDumpBuffer *> *pQueueBufferVector = NULL;
mAudioDumpMutex.lock();
ssize_t index = mAudioDumpQueueVector.indexOfKey(String8(path));
if (index >= 0) {
pQueueBufferVector = mAudioDumpQueueVector.valueAt(index);
int queueSize = (*pQueueBufferVector).size();
for (int i = 0; i < queueSize; i++) {
AudioDumpBuffer *newQueueBuffer = (*pQueueBufferVector)[i];
dump_size_in_queue += newQueueBuffer->fileInfo.size;
}
}
mAudioDumpMutex.unlock();
struct stat dump_stat;
String8 wavpath = String8::format("%s.wav", path);
if (stat(wavpath, &dump_stat) == 0) {
return dump_stat.st_size > AUDIO_DUMP_FILE_WAV_HEADER_SIZE ?
(dump_size_in_queue + dump_stat.st_size - AUDIO_DUMP_FILE_WAV_HEADER_SIZE) : dump_size_in_queue;
}
return dump_size_in_queue;
}
void AudioDump::updateKeys(int key)
{
Mutex::Autolock _l(mAudioDumpKeyMutex);
if (key < 0 || key >= AudioDump::PROP_AUDIO_DUMP_MAXNUM) {
mAudioDumpKeyEnableVector.clear();
} else {
mAudioDumpKeyEnableVector.removeItem((AudioDump::PROP_AUDIO_DUMP)key);
}
}
void AudioDump::pushBufferInfo(const char * path, void * buffer, int count,
audio_format_t format, uint32_t sampleRate, uint32_t channelCount)
{
if (buffer != NULL && count > 0) {
AudioDumpBuffer *newQueueBuffer = new AudioDumpBuffer();
newQueueBuffer->pBufBase = (char*)malloc(count);
if (newQueueBuffer->pBufBase != NULL) {
memcpy(newQueueBuffer->pBufBase, buffer, count);
} else {
//error handle?
ALOGE("%s(): Error! Not enough memory for audio dump buffer size=%d", __FUNCTION__, count);
}
newQueueBuffer->fileInfo.format = format;
newQueueBuffer->fileInfo.sampleRate = sampleRate;
newQueueBuffer->fileInfo.channelCount = channelCount;
newQueueBuffer->fileInfo.size = count;
Vector<AudioDumpBuffer *> *pQueueBufferVector = NULL;
mAudioDumpMutex.lock();
ssize_t index = mAudioDumpQueueVector.indexOfKey(String8(path));
if (index < 0) { // new add
pQueueBufferVector = new Vector<AudioDumpBuffer *>;
mAudioDumpQueueVector.add(String8(path), pQueueBufferVector);
ALOGD("new threadDump() %s.wav(%d)", path, count); // For dump analysis
} else {
pQueueBufferVector = mAudioDumpQueueVector.valueAt(index);
}
if (pQueueBufferVector) {
pQueueBufferVector->add(newQueueBuffer);
}
bool needWakeup = (mAudioDumpSleepTime == -1);
mAudioDumpMutex.unlock();
if (needWakeup) { //need to send event
pthread_mutex_lock(&AudioDataNotifyMutex);
pthread_cond_signal(&AudioDataNotifyEvent);
pthread_mutex_unlock(&AudioDataNotifyMutex);
}
}
}
void FeatureOption::getValues()
{
// FO values are cached in the system parser.
bool foValue_MTK_BESLOUDNESS_RUN_WITH_HAL = appIsFeatureOptionEnabled(foName_MTK_BESLOUDNESS_RUN_WITH_HAL);
bool foValue_MTK_BESLOUDNESS_SUPPORT = appIsFeatureOptionEnabled(foName_MTK_BESLOUDNESS_SUPPORT);
const char * foValue_MTK_USB_PHONECALL = appGetFeatureOptionValue(foName_MTK_USB_PHONECALL);
int foValue_MTK_AUDIO_NUMBER_OF_SPEAKER = atoi(appGetFeatureOptionValue(foName_MTK_AUDIO_NUMBER_OF_SPEAKER));
bool foValue_MTK_TTY_SUPPORT = appIsFeatureOptionEnabled(foName_MTK_TTY_SUPPORT);
bool foValue_MTK_HIFIAUDIO_SUPPORT = appIsFeatureOptionEnabled(foName_MTK_HIFIAUDIO_SUPPORT);
bool foValue_MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT = appIsFeatureOptionEnabled(foName_MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT);
bool foValue_MTK_AURISYS_FRAMEWORK_SUPPORT = appIsFeatureOptionEnabled(foName_MTK_AURISYS_FRAMEWORK_SUPPORT);
bool foValue_MTK_BT_HEARING_AID_SUPPORT = appIsFeatureOptionEnabled(foName_MTK_BT_HEARING_AID_SUPPORT);
bool foValue_MTK_BT_HEARING_AID_USING_AOSP_FMW = appIsFeatureOptionEnabled(foName_MTK_BT_HEARING_AID_USING_AOSP_FMW);
bool foValue_MTK_AUDIO_MTK_TC10_FEATURE = appIsFeatureOptionEnabled(foName_MTK_TC10_FEATURE);
bool foValue_MTK_AUDIO_MTK_TC10_IN_HOUSE = appIsFeatureOptionEnabled(foName_MTK_TC10_IN_HOUSE);
bool foValue_MTK_AUDIO_A2DP_LATENCY_IMPROVE = appIsFeatureOptionEnabled(foName_MTK_AUDIO_A2DP_LATENCY_IMPROVE);
char bluetooth_le_mode[PROPERTY_VALUE_MAX] = { 0 };
property_get("persist.vendor.bluetooth.leaudio_mode", bluetooth_le_mode,MTK_LEAUDIO_MODE_OFF);
bool foValue_MTK_BLE_PHONECALL = (strncmp(bluetooth_le_mode, MTK_LEAUDIO_MODE_CGUMS, strlen(MTK_LEAUDIO_MODE_CGUMS)) == 0);
const char * foValue_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON = appGetFeatureOptionValue(foName_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON);
MTK_AUDIOMIXER_ENABLE_DRC = !foValue_MTK_BESLOUDNESS_RUN_WITH_HAL && foValue_MTK_BESLOUDNESS_SUPPORT;
ALOGD("MTK_AUDIOMIXER_ENABLE_DRC: %d", MTK_AUDIOMIXER_ENABLE_DRC);
MTK_ENABLE_STEREO_SPEAKER = (foValue_MTK_AUDIO_NUMBER_OF_SPEAKER >= 2) ? 1 : 0;
ALOGD("MTK_ENABLE_STEREO_SPEAKER: %d", MTK_ENABLE_STEREO_SPEAKER);
MTK_USB_PHONECALL = foValue_MTK_USB_PHONECALL != NULL ? strcmp(foValue_MTK_USB_PHONECALL, "no"): true;
ALOGD("foValue_MTK_USB_PHONECALL %s, MTK_USB_PHONECALL: %d", foValue_MTK_USB_PHONECALL, MTK_USB_PHONECALL);
MTK_TTY_SUPPORT = foValue_MTK_TTY_SUPPORT;
ALOGD("MTK_TTY_SUPPORT %d", MTK_TTY_SUPPORT);
MTK_HIFIAUDIO_SUPPORT = foValue_MTK_HIFIAUDIO_SUPPORT;
ALOGD("MTK_HIFIAUDIO_SUPPORT: %d", MTK_HIFIAUDIO_SUPPORT);
MTK_BESLOUDNESS_ENABLE = foValue_MTK_BESLOUDNESS_SUPPORT;
ALOGD("MTK_BESLOUDNESS_ENABLE : %d", MTK_BESLOUDNESS_ENABLE);
MTK_AUDIO_GAIN_TABLE = foValue_MTK_AUDIO_HIERARCHICAL_PARAM_SUPPORT;
MTK_AUDIO_GAIN_NVRAM = !MTK_AUDIO_GAIN_TABLE;
ALOGD("MTK_AUDIO_GAIN_TABLE: %d", MTK_AUDIO_GAIN_TABLE);
ALOGD("MTK_FM_ENABLE : %d", MTK_FM_ENABLE);
MTK_AURISYS_FRAMEWORK_SUPPORT = foValue_MTK_AURISYS_FRAMEWORK_SUPPORT;
ALOGD("MTK_AURISYS_FRAMEWORK_SUPPORT : %d", MTK_AURISYS_FRAMEWORK_SUPPORT);
MTK_BT_HEARING_AID_SUPPORT = foValue_MTK_BT_HEARING_AID_SUPPORT;
ALOGD("MTK_BT_HEARING_AID_SUPPORT : %d", MTK_BT_HEARING_AID_SUPPORT);
MTK_BT_HEARING_AID_USING_AOSP_FMW = foValue_MTK_BT_HEARING_AID_USING_AOSP_FMW;
ALOGD("MTK_BT_HEARING_AID_USING_AOSP_FMW : %d", MTK_BT_HEARING_AID_USING_AOSP_FMW);
MTK_TC10_FEATURE = foValue_MTK_AUDIO_MTK_TC10_FEATURE;
ALOGD("MTK_TC10_FEATURE : %d", MTK_TC10_FEATURE);
MTK_TC10_IN_HOUSE = foValue_MTK_AUDIO_MTK_TC10_IN_HOUSE;
ALOGD("MTK_TC10_IN_HOUSE : %d", MTK_TC10_IN_HOUSE);
MTK_AUDIO_A2DP_LATENCY_IMPROVE = foValue_MTK_AUDIO_A2DP_LATENCY_IMPROVE;
ALOGD("MTK_AUDIO_A2DP_LATENCY_IMPROVE : %d", MTK_AUDIO_A2DP_LATENCY_IMPROVE);
MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON = foValue_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON != NULL ? strcmp(foValue_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON, "no"): true;
ALOGD("foValue_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON %s, MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON : %d", foValue_MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON, MTK_MUSIC_ROUTE_TO_BTSCO_DURING_BTSCO_ON);
MTK_BLE_PHONECALL = foValue_MTK_BLE_PHONECALL;
ALOGD("MTK_BLE_PHONECALL : %d", MTK_BLE_PHONECALL);
}
void AudioUtilThread::exit()
{
{
AutoMutex lock(mLock);
requestExit();
mWaitWorkCV.broadcast();
}
requestExitAndWait();
}
bool AudioUtilThread::threadLoop()
{
while (!exitPending()) {
Mutex::Autolock _l(mLock);
// <BatteryNotifier
Vector<AudioUtilThread::BatteryNote> mVector;
{
Mutex::Autolock _l(mBatteryStateVectorLock);
for (int i = 0; i < mBatteryStateVector.size(); i++) {
mVector.push_back(mBatteryStateVector[i]);
}
mBatteryStateVector.clear();
}
for (int i = 0; i < mVector.size(); i++) {
//ALOGD("%s+, event %d, uid %d", __func__, (int)mVector[i].event, (int)mVector[i].uid);
if (mVector[i].event == BATTERY_NOTE_START_AUDIO) {
BatteryNotifier::getInstance().noteStartAudio(mVector[i].uid);
} else if (mVector[i].event == BATTERY_NOTE_STOP_AUDIO) {
BatteryNotifier::getInstance().noteStopAudio(mVector[i].uid);
}
}
// BatteryNotifier>
mWaitWorkCV.wait(mLock);
}
ALOGV("AudioUtilThread %p exiting", this);
return false;
}
void AudioUtilThread::BatteryStateRegister(BATTERY_EVENT event, uint32_t uid)
{
//ALOGD("%s, event %d, uid %d", __func__, (int)event, (int)uid);
BatteryNote note;
note.event = event;
note.uid = uid;
Mutex::Autolock _l(mBatteryStateVectorLock);
mBatteryStateVector.add(note);
}
void AudioUtilThread::BatteryStateNotify()
{
//Mutex::Autolock _l(mBatteryStateVectorLock); // no need!!
if (mBatteryStateVector.size() > 0) {
mWaitWorkCV.signal();
}
}
}