ANDROIDオーディオシステムハッシュの1つ:A 2 dpAudioInterface

6864 ワード

前に書く
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()で呼び出され、次にオーディオデータの上位層から下位層のハードウェアデバイスへの伝送の流れを簡単に説明する.