ANDROIDオーディオシステムハッシュの1つ:A 2 dpAudioInterface
前に書く
Androidオーディオシステムを書こうと思っていたのですが、下記のようなリンクの3つの記事をじっくり検討し、思い切って私の考えを中断しました.誇張しないで、これは私が見た最も良いAndroidオーディオシステムを述べる文章で、簡潔で精巧で、オーディオシステムの各方面の重要な脈絡を説明しました.この3つの文章があり、Androidオーディオシステムを理解するのは10倍に加速しただけではない.
Android Audio Systemの1つ:AudioTrackがAudioFlingerとオーディオデータをどのように交換するか
Android Audio Systemの2:AudioFlinger
Android Audio Systemの3:AudioPolicyServiceとAudioPolicyManager
A2dpAudioInterface
Androidオーディオシステムには2つの大きなサービスがあります.1つはAudioFlinger、2つはAudioPolicyServiceです.AudioFlingerはAudioHardwareInterfaceにアクセスし、オーディオPCMデータの混音/入出力を実現し、音量調整を実現する.AudioPolicyServiceは、オーディオ入出力デバイスの接続状態を担当し、オーディオポリシースケジューリング、すなわち、ローカルCODEC、Bluetooth A 2 DP、Headsetなどのオーディオデバイスの切り替えポリシーを担当します(ポリシーを担当するだけであることに注意してください.本当の切り替え操作は、AudioFlingerのopenOutputであり、AudioFlingerが最下位のオーディオハードウェアを操作することを担当しています).AudioPolicyServiceは、A 2 DP-AudioがAudioFlingerにどのように登録されているかを主に検討し、オーディオPCMデータの流れについて簡単に説明します.
良いプラットフォームソフトウェアには、固定されたインタフェースを下に提供し、異なるハードウェアデバイスがこれらのインタフェースに基づいてそれぞれの方法を実現し、この抽象層に登録する抽象層が必要です.これは、下位ハードウェアの相違にかかわらず、抽象層インタフェースを呼び出すだけでよいため、上位アプリケーションには何の違いもありません.AudioFlingerは、下位層がALSAデバイスでもBluetoothHeadsetでも、上位層はAudioFlingerのインタフェースしか見えない抽象層です.ALSAデバイスがBluetoothHeadsetに切り替わるタイミングについては、オーディオポリシースケジューリングの範疇であるAudioPolicyServiceに属します.
hw = new A2dpAudioInterface(hw);
赤い部分hwに注意してください.なぜA 2 dpAudioInterfaceにはcreateAudioHardware()が開いているAudioHardwareInterface(ALSAデバイスインタフェースだと仮定します)が必要なのでしょうか.私たちが知っているように、BluetoothA 2 DPはALSAデバイスと同じインタフェースを歩んでいないため、Androidの設計者はALSAデバイスインタフェースをA 2 DPインタフェースに捨てて管理しています.これはどのように管理されていますか?簡単に言えば、上層部から伝わったパラメータdevicesに基づいて、devicesがDEVICE_であるか否かを判断するOUT_BLUETOOTH_A 2 DPは、A 2 DPインタフェースであればALSAデバイスインタフェースであり、そうでなければALSAデバイスインタフェースである.たとえば、オーディオ出力ストリームを開く必要がある場合:
liba2dp
A 2 dpAudioInterfaceの層に着くと、BlueZのオーディオ操作インターフェースにアクセスします.主にexternalbluetoothbluezaudioliba 2 dpです.c.liba2dp.cコードは複雑かもしれませんが、私も深く理解したことがありませんが、インタフェースはとても簡単で使いやすいです.liba 2 dpを見てh、いくつかのインタフェースしかありません.
a2dp_set_sink:Bluetoothアドレスaddressをa 2 dpDataにバインドします.
a2dp_write:a 2 dpにオーディオPCMデータを書き込む;
a2dp_stop:a 2 dp再生を停止します.
例えば、オーディオPCMデータがBluetoothに送られるたびに、
この関数はAudioFlinger::MixerThread::threadLoop()で呼び出され、次にオーディオデータの上位層から下位層のハードウェアデバイスへの伝送の流れを簡単に説明する.
Androidオーディオシステムを書こうと思っていたのですが、下記のようなリンクの3つの記事をじっくり検討し、思い切って私の考えを中断しました.誇張しないで、これは私が見た最も良いAndroidオーディオシステムを述べる文章で、簡潔で精巧で、オーディオシステムの各方面の重要な脈絡を説明しました.この3つの文章があり、Androidオーディオシステムを理解するのは10倍に加速しただけではない.
Android Audio Systemの1つ:AudioTrackがAudioFlingerとオーディオデータをどのように交換するか
Android Audio Systemの2:AudioFlinger
Android Audio Systemの3:AudioPolicyServiceとAudioPolicyManager
A2dpAudioInterface
Androidオーディオシステムには2つの大きなサービスがあります.1つはAudioFlinger、2つはAudioPolicyServiceです.AudioFlingerはAudioHardwareInterfaceにアクセスし、オーディオPCMデータの混音/入出力を実現し、音量調整を実現する.AudioPolicyServiceは、オーディオ入出力デバイスの接続状態を担当し、オーディオポリシースケジューリング、すなわち、ローカルCODEC、Bluetooth A 2 DP、Headsetなどのオーディオデバイスの切り替えポリシーを担当します(ポリシーを担当するだけであることに注意してください.本当の切り替え操作は、AudioFlingerのopenOutputであり、AudioFlingerが最下位のオーディオハードウェアを操作することを担当しています).AudioPolicyServiceは、A 2 DP-AudioがAudioFlingerにどのように登録されているかを主に検討し、オーディオPCMデータの流れについて簡単に説明します.
良いプラットフォームソフトウェアには、固定されたインタフェースを下に提供し、異なるハードウェアデバイスがこれらのインタフェースに基づいてそれぞれの方法を実現し、この抽象層に登録する抽象層が必要です.これは、下位ハードウェアの相違にかかわらず、抽象層インタフェースを呼び出すだけでよいため、上位アプリケーションには何の違いもありません.AudioFlingerは、下位層がALSAデバイスでもBluetoothHeadsetでも、上位層はAudioFlingerのインタフェースしか見えない抽象層です.ALSAデバイスがBluetoothHeadsetに切り替わるタイミングについては、オーディオポリシースケジューリングの範疇であるAudioPolicyServiceに属します.
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
{
mHardwareStatus = AUDIO_HW_IDLE;
mAudioHardware = AudioHardwareInterface::create();
......
AudioHardwareInterface::create():AudioHardwareInterface* AudioHardwareInterface::create()
{
/*
* FIXME: This code needs to instantiate the correct audio device
* interface. For now - we use compile-time switches.
*/
AudioHardwareInterface* hw = 0;
char value[PROPERTY_VALUE_MAX];
#ifdef GENERIC_AUDIO
hw = new AudioHardwareGeneric();
#else
// if running in emulation - use the emulator driver
if (property_get("ro.kernel.qemu", value, 0)) {
LOGD("Running in emulation - using generic audio driver");
hw = new AudioHardwareGeneric();
}
else {
LOGV("Creating Vendor Specific AudioHardware");
hw = createAudioHardware();
}
#endif
if (hw->initCheck() != NO_ERROR) {
LOGW("Using stubbed audio hardware. No sound will be produced.");
delete hw;
hw = new AudioHardwareStub();
}
#ifdef WITH_A2DP
hw = new A2dpAudioInterface(hw);
#endif
#ifdef ENABLE_AUDIO_DUMP
// This code adds a record of buffers in a file to write calls made by AudioFlinger.
// It replaces the current AudioHardwareInterface object by an intermediate one which
// will record buffers in a file (after sending them to hardware) for testing purpose.
// This feature is enabled by defining symbol ENABLE_AUDIO_DUMP.
// The output file is set with setParameters("test_cmd_file_name="). Pause are not recorded in the file.
LOGV("opening PCM dump interface");
hw = new AudioDumpInterface(hw); // replace interface
#endif
return hw;
}
この関数はANDROID 2にあります.3オーディオシステムHALは簡単な分析があります.次にA 2 DPの登録を見てみましょう.hw = new A2dpAudioInterface(hw);
赤い部分hwに注意してください.なぜA 2 dpAudioInterfaceにはcreateAudioHardware()が開いているAudioHardwareInterface(ALSAデバイスインタフェースだと仮定します)が必要なのでしょうか.私たちが知っているように、BluetoothA 2 DPはALSAデバイスと同じインタフェースを歩んでいないため、Androidの設計者はALSAデバイスインタフェースをA 2 DPインタフェースに捨てて管理しています.これはどのように管理されていますか?簡単に言えば、上層部から伝わったパラメータdevicesに基づいて、devicesがDEVICE_であるか否かを判断するOUT_BLUETOOTH_A 2 DPは、A 2 DPインタフェースであればALSAデバイスインタフェースであり、そうでなければALSAデバイスインタフェースである.たとえば、オーディオ出力ストリームを開く必要がある場合:
AudioStreamOut* A2dpAudioInterface::openOutputStream(
uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
}
status_t err = 0;
// only one output stream allowed
if (mOutput) {
if (status)
*status = -1;
return NULL;
}
// create new output stream
A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
mOutput = out;
mOutput->setBluetoothEnabled(mBluetoothEnabled);
mOutput->setSuspended(mSuspended);
} else {
delete out;
}
if (status)
*status = err;
return mOutput;
}
上層部から伝達されたdevicesがA 2 DPデバイスに属していない場合、return mHardwareInterface->openOutputStream(devices,format,channels,sampleRate,status);このうちmHardwareInterfaceはALSAのhwを保存しています.A 2 dpAudioStreamOut*out=new A 2 dpAudioStreamOut()A 2 DPのオーディオ出力ストリームを開きます.liba2dp
A 2 dpAudioInterfaceの層に着くと、BlueZのオーディオ操作インターフェースにアクセスします.主にexternalbluetoothbluezaudioliba 2 dpです.c.liba2dp.cコードは複雑かもしれませんが、私も深く理解したことがありませんが、インタフェースはとても簡単で使いやすいです.liba 2 dpを見てh、いくつかのインタフェースしかありません.
int a2dp_init(int rate, int channels, a2dpData* dataPtr);
void a2dp_set_sink(a2dpData data, const char* address);
int a2dp_write(a2dpData data, const void* buffer, int count);
int a2dp_stop(a2dpData data);
void a2dp_cleanup(a2dpData data);
a2dp_init:入力されたサンプリングレートrateに基づいて、チャネル数channelsはa 2 dpDataを初期化する.a2dp_set_sink:Bluetoothアドレスaddressをa 2 dpDataにバインドします.
a2dp_write:a 2 dpにオーディオPCMデータを書き込む;
a2dp_stop:a 2 dp再生を停止します.
例えば、オーディオPCMデータがBluetoothに送られるたびに、
ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
{
Mutex::Autolock lock(mLock);
size_t remaining = bytes;
status_t status = -1;
if (!mBluetoothEnabled || mClosing || mSuspended) {
LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
mBluetoothEnabled %d, mClosing %d, mSuspended %d",
mBluetoothEnabled, mClosing, mSuspended);
goto Error;
}
status = init();
if (status < 0)
goto Error;
while (remaining > 0) {
status = a2dp_write(mData, buffer, remaining);
if (status <= 0) {
LOGE("a2dp_write failed err: %d
", status);
goto Error;
}
remaining -= status;
buffer = ((char *)buffer) + status;
}
mStandby = false;
return bytes;
Error:
// Simulate audio output timing in case of error
usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);
return status;
}
コア文:status=a 2 dp_write(mData, buffer, remaining); オーディオデータのヘッダアドレスとサイズを入力するだけでいいです.この関数はAudioFlinger::MixerThread::threadLoop()で呼び出され、次にオーディオデータの上位層から下位層のハードウェアデバイスへの伝送の流れを簡単に説明する.