編輯:關於Android編程
最近在關注藍牙耳機方面的問題,做下簡單的流程分析。
解碼後,在AudioFlinger裡把音頻數據寫到設備裡。這裡主要看看AudioFlinger,AudioPolicyManager和external/bluetooth/bluez/audio裡面的android_audio_hw.c和liba2dp.c。
在AudioPolicyManager裡有設備連接判斷。
status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
AudioSystem::device_connection_state state,
const char *device_address)
{
#ifdef WITH_A2DP
// handle A2DP device connection
if (AudioSystem::isA2dpDevice(device)) {
status_t status = handleA2dpConnection(device, device_address);//這裡是執行藍牙連接
if (status != NO_ERROR) {
mAvailableOutputDevices &= ~device;
return status;
}
} else
#endif
}
。。。。。
status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device,
const char *device_address)
{
...............
mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
if (mA2dpOutput) {
// add A2DP output descriptor
addOutput(mA2dpOutput, outputDesc);
//TODO: configure audio effect output stage here
// set initial stream volume for A2DP device
applyStreamVolumes(mA2dpOutput, device);
if (a2dpUsedForSonification()) {
mDuplicatedOutput = mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput);
}
if (mDuplicatedOutput != 0 ||
!a2dpUsedForSonification()) {
// If both A2DP and duplicated outputs are open, send device address to A2DP hardware
// interface
AudioParameter param;
param.add(String8("a2dp_sink_address"), String8(device_address));
mpClientInterface->setParameters(mA2dpOutput, param.toString());
mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
if (a2dpUsedForSonification()) {
// add duplicated output descriptor
AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor();
dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput);
dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput);
dupOutputDesc->mSamplingRate = outputDesc->mSamplingRate;
dupOutputDesc->mFormat = outputDesc->mFormat;
dupOutputDesc->mChannels = outputDesc->mChannels;
dupOutputDesc->mLatency = outputDesc->mLatency;
addOutput(mDuplicatedOutput, dupOutputDesc);
applyStreamVolumes(mDuplicatedOutput, device);
}
} else {
.........
}
如果只是藍牙播放,那麼mDuplicatedOutput和a2dpUsedForSonification都為0,僅執行 addOutput(mA2dpOutput, outputDesc);,走類似speaker和麥克風的流程。
如果是藍牙和speaker或麥克風同時播放聲音,走mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput);注意的是,第一個參數是mA2dpOutput,藍牙的,第二個參數是mHardwareOutput,speaker或mic等其他輸出設備。
那麼接下來我們去看看openDuplicateOutput函數。在AudioFlinger.cpp裡有定義
int AudioFlinger::openDuplicateOutput(int output1, int output2)
{
Mutex::Autolock _l(mLock);
MixerThread *thread1 = checkMixerThread_l(output1);
MixerThread *thread2 = checkMixerThread_l(output2);
if (thread1 == NULL || thread2 == NULL) {
LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2);
return 0;
}
int id = nextUniqueId();
DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
// notify client processes of the new output creation
thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
return id;
}
這個函數開啟2個線程,一個是藍牙的,另一個是mHardwareOutput,實現兩者同時播放,比如來電,短信,鬧鈴聲等。
先暫停在這裡,接著
static const char *audio_interfaces[] = {
"primary",
"a2dp",
"usb",
};
4.0的代碼有三種audio接口,一個是primary,是codec,我們常用的speaker,mic等;二是a2dp,是藍牙;三是usb接口。
void AudioFlinger::onFirstRef()
{
int rc = 0;
Mutex::Autolock _l(mLock);
/* TODO: move all this work into an Init() function */
mHardwareStatus = AUDIO_HW_IDLE;
for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
const hw_module_t *mod;
audio_hw_device_t *dev;
rc = load_audio_interface(audio_interfaces[i], &mod, &dev);//加載接口.so文件
if (rc)
continue;
LOGI("Loaded %s audio interface from %s (%s)", audio_interfaces[i],
mod->name, mod->id);
mAudioHwDevs.push(dev);
.........
}
這裡會遍歷audio接口。
void AudioFlinger::RecordThread::onFirstRef()
{
run(mName, PRIORITY_URGENT_AUDIO);
}
int AudioFlinger::openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
uint32_t *pFormat,
uint32_t *pChannels,
uint32_t *pLatencyMs,
uint32_t flags){
......
outHwDev = findSuitableHwDev_l(*pDevices);//獲取有效audio接口設備
if (outHwDev == NULL)
return 0;
//獲取接口.so庫裡面的參數信息
status = outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
&channels, &samplingRate, &outStream);
LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
outStream,
samplingRate,
format,
channels,
status);
mHardwareStatus = AUDIO_HW_IDLE;
if (outStream != NULL) {
AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);//建立這種設備的輸出
........
}
outHwDev->open_output_stream 來自藍牙audio裡的接口函數。
再看android_audio_hw.c
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct adev_a2dp *adev;
int ret;
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
adev = calloc(1, sizeof(struct adev_a2dp));
if (!adev)
return -ENOMEM;
adev->bt_enabled = true;
adev->suspended = false;
pthread_mutex_init(&adev->lock, NULL);
adev->output = NULL;
adev->device.common.tag = HARDWARE_DEVICE_TAG;
adev->device.common.version = 0;
adev->device.common.module = (struct hw_module_t *) module;
adev->device.common.close = adev_close;
adev->device.get_supported_devices = adev_get_supported_devices;
adev->device.init_check = adev_init_check;
adev->device.set_voice_volume = adev_set_voice_volume;
adev->device.set_master_volume = adev_set_master_volume;
adev->device.set_mode = adev_set_mode;
adev->device.set_mic_mute = adev_set_mic_mute;
adev->device.get_mic_mute = adev_get_mic_mute;
adev->device.set_parameters = adev_set_parameters;
adev->device.get_parameters = adev_get_parameters;
adev->device.get_input_buffer_size = adev_get_input_buffer_size;
adev->device.open_output_stream = adev_open_output_stream;
adev->device.close_output_stream = adev_close_output_stream;
adev->device.open_input_stream = adev_open_input_stream;
adev->device.close_input_stream = adev_close_input_stream;
adev->device.dump = adev_dump;
*device = &adev->device.common;
return 0;
err_str_parms_create:
free(adev);
return ret;
}
這樣AudioFlinger裡需要的參數,通過這裡設定。接著藍牙audio進行相關init,config,start,stop等狀態操作。當然包括藍牙讀寫。
最終效果圖,點擊save會保存到文件中,點擊show會從文件中讀取出內容並顯示。main.xml<?xml version=1.0 encoding=utf
Android Fragment(動態,靜態)碎片詳解一.Fragment的相關概念(一)Fragment的基礎知識 &nb
夜深也是無聊,翻看以前的老代碼,發現那個我們經常用的菊花圈,原來是幀動畫做的,有點意思。突然感覺幀動畫做的東西效果不錯啊,至少看起來聽耐看的。開工上代碼: 先是布局文件:
一、歷史回顧隨科技的迅速發展,當前已經全線進入4G時代,5G時代也即將開啟。Android版本迭代迅速,如今已是6.0的版本。時不時可以看到,手機危害了當前人群的生活,如