I. 目的
前回、AudioFlinger(AF)の話をしましたが、いつも感じるのは、コードの中に不明な点が多すぎて、心臓に毛が生えているということです。AudioPolicyServiceって何?なぜ存在するの?AudioPolicyServiceとは何ですか?さらに悪いことに、実際に質問してみてください。ヘッドホンを接続した後、音が再生されてからヘッドホンから出力されるまでの流れはどうなっているのでしょうか?音量を調整するときは、ミュージックの音量を調整するのですか、それとも着信の音量を調整するのですか?どれもAFプロセスではカバーされていません。しかし、繰り返しになりますが、これらは非常に重要です。私の個人的な理解では、戦略はプロセスよりも複雑で理解しにくいものです。
もちろん、伝統的な分析手法に従うためには、入り口がなければなりません。
ここでのエントリーポイントは
l AFとAPSシステムが立ち上がった当初、実際に行っていたこと。
l ヘッドセット挿入イベント検出後の AF および APS の処理。
私のステップ・バイ・ステップに従えば、嗚呼、結局APSはそんなに難しくないのだとすぐに気づくでしょう。
エントリーポイントが見つからず、コードの最初から最後までしか知らなかったからです!
II AFとAPSの誕生
あれを見てください。
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
//まずAFを作る
AudioFlinger::instantiate();
//再びAPSを作成する
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
new AudioFlinger
前述したように、instantiateは内部でオブジェクトをインスタンス化するので、AFコンストラクタを直接見てください。
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),//ベースクラスのコンストラクタ
mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
{
mAudioHardware と mNextThreadId に注意してください。
mHardwareStatus = AUDIO_HW_IDLE。
// オーディオのHAL表現を作成
mAudioHardware = AudioHardwareInterface::create();
mHardwareStatus = AUDIO_HW_INIT。
//APSはまだ作られていません!
if (mAudioHardware->initCheck() == NO_ERROR) {
setMode(AudioSystem::MODE_NORMAL);
setMasterVolume(1.0f);
setMasterMute(false);
}
AFのコンストラクタは、重要なAudioHardWareのHAL表現を作成しているように感じます。
それ以外は戦術的なことは何もしていないようです。
ただし、AFはAudioHardwareのHALオブジェクトを作成します。これはシステム全体で唯一のAudioHardwareであることに注意してください。つまり、インラインヘッドセット、ブルートゥースヘッドセット、マイク、外部アンプなどであっても、最終的にはすべてこのHALで管理されます。
もう一度APSを見てみましょう。
new AudioPolicyService
AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService() , mpPolicyManager(NULL)
{
// mpPolicyManager?ストラテジー・マネージャー?重要なことかもしれない。
char value[PROPERTY_VALUE_MAX];
// TonePlayback?着信音を再生する?なぜここに置くのか?後で調べてみて。
mTonePlaybackThread = new AudioCommandThread(String8(""));
// Audio Command?オーディオ・コマンド?Commandというと、デザインパターンのCommandパターンを思い浮かべる。
//Android特にMediaPlayerServiceはこのパターンを多用している。
mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
//AudioPolicyManagerBaseコンストラクタは thisを渡している。
mpPolicyManager = new AudioPolicyManagerBase(this);
//GenericのAudioデバイスが使われていると仮定してみよう。
#else
...
#endif
// システムプロパティに基づいて、カメラが強制的にサウンドを使用するかどうかを決定します。これは...なぜここに?
//ビデオカメラを搭載した携帯電話では、盗撮防止のためシャッターを押す際に音を鳴らすことが義務付けられているようです。
// そういうことでしょ?
property_get("ro.camera.sound.forced", value, "0");
mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
}
そう簡単!、そう簡単じゃないでしょう?疑うことは惜しんではいけません!多くの疑問がありますが、どれを最初に見るべきでしょうか?ここで分析したのはAudio Policyで、コンストラクタはAudioPolicyManagerBaseを作成し、様々なベンダーが独自のAudioPolicyManagerを実装することができます。
Androidのコードにおけるこれらの命名は、要所要所でより慎重かつ正確であると言わざるを得ません。
また、AudioPolicyManagerBaseのコンストラクタはAPSを渡すので、APSに依存するコールバックもありそうです。なんて回り道。
AudioPolicyManagerBase
コードの場所 framework/base/libs/audioflinger/AudioPolicyManagerBase.cpp 内
AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
:
mPhoneState(AudioSystem::MODE_NORMAL), ---->携帯電話のステータスはこんな感じか?
mRingerMode(0),
mMusicStopTime(0),
mLimitRingtoneVolume(false)
{
[--->mPhoneState(AudioSystem::MODE_NORMAL)]
AudioSystemは、Androidがオーディオシステムをどのように管理しているかを覗き見るのに良い場所です。この場所は
framework/base/include/media/AudioSystem.hには、Googleのオーディオシステムに対する考え方を表現するためのenumなどがたくさん定義されています。どうなるかは見てのお楽しみです。
以下はaudio_modeの定義です。ここで一つ注意すべきことがあります:
C++のAudioSystem部分については、SDKの命令はAudioManagerにあります。
enum audio_mode {
//以下、これ以上説明しないSDKの命令を説明する。
MODE_INVALID = -2, //無効なモード
MODE_CURRENT = -1,//現在のモードは、オーディオ・デバイスの切り替えに関係している。
MODE_NORMAL = 0,//ノーマルモード、電話なし、着信音なし
MODE_RINGTONE,//着信信号があり、着信音が鳴っている。
MODE_IN_CALL,//電話モード、ここでは通話がすでに確立されていることを意味する
NUM_MODES // Androidこのテクニックの多くは、列挙が終わったことを示すために使われている。
};
では、どうぞ:
...
mPhoneState(AudioSystem::MODE_NORMAL), ---->携帯電話のステータスはこんな感じか?
mRingerMode(0),
mMusicStopTime(0),
mLimitRingtoneVolume(false)
{
mpClientInterface = clientInterface;//BT,APSオブジェクトを保存する。
//forceUse?一体これは何なんだ?
for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
mForceUse[i] = AudioSystem::FORCE_NONE;
}
ここには2つの列挙型があることに注意してください。まずFORCE_NONEを見てみましょう。
enum forced_config { _コンフィギュレーションを見ると、外部アンプ、ヘッドフォン、ブルートゥースなどのデバイスの使用を強制しているようだ。
FORCE_NONE,
FORCE_SPEAKER,
FORCE_HEADPHONES,
FORCE_BT_SCO,
FORCE_BT_A2DP,
FORCE_WIRED_ACCESSORY,
FORCE_BT_CAR_DOCK,
FORCE_BT_DESK_DOCK,
NUM_FORCE_CONFIG,
FORCE_DEFAULT = FORCE_NONE //これ、つまらなすぎる。
};
このAudioSystem::NUM_FORCE_USEをもう一度見てみましょう。
enum force_use {
FOR_COMMUNICATION,//以下は_xxx,強制ではない _xxx。
FOR_MEDIA,
FOR_RECORD,
FOR_DOCK,
NUM_FORCE_USE
};
どっちもダメ。どうして?何かわかる?私にもわかりません。正しいシナリオが見つからなかったからです!じゃあ、SDKに行って探してみてください。ええ。
AudioManagerのこの関数setSpeakerphoneOnを見ました。さて、私は
こう呼んでください。
setSpeakerphoneOn(true)で実装を見ることができます。
今回はもう時間を無駄にせず、新しいツール、coolfindを使い、フレームワークディレクトリを検索し、setSpeakerphoneという文字列にマッチする*.javaファイルを探しました。
framework/base/media/java/android/media/AudioService.javaで見つけた。
public void setSpeakerphoneOn(boolean on){
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return;
}
if (on) {
// これを見て、十中八九納得できるのではないでしょうか?この次のコールは
//スピーカーの使用を強要する!ということですね!
AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,
ioSystem.FORCE_SPEAKER);
mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
} else {
AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,
ioSystem.FORCE_NONE);
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
}
さて、少し話がそれますが、Androidのソースコードが公開されているので、もっと検索しない理由は何でしょうか?インターネットのgoogleも検索ですが、ソースコードをチェックするのも同じですか?しかし、目的を持っている:シーンの適切な使用を見つけることです。
force_useとforce_configについては、改めて説明する必要はないでしょう?
[--->AudioPolicyManagerBase::AudioPolicyManagerBase]
...
// 以下は、複数のfor_useケースで使用されるすべてのデバイスがNONEに設定されていることを意味します。
// 例えば、FOR_MEDIAシナリオを設定した場合、使用されるデバイスはFORCE_NONEです。
for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
mForceUse[i] = AudioSystem::FORCE_NONE;
}
// 現在使用可能な出力デバイス、ヘッドフォン、外部アンプ
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
AudioSystem::DEVICE_OUT_SPEAKER;
//現在利用可能なMIC内蔵入力デバイス
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
繰り返しになるが、AudioSystemがどのように入力と出力のデバイスを定義しているかを見てみる必要があるだろう。
[--->mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE]
enum audio_devices {
// output devices
DEVICE_OUT_EARPIECE = 0x1,
DEVICE_OUT_SPEAKER = 0x2,
DEVICE_OUT_WIRED_HEADSET = 0x4,
DEVICE_OUT_WIRED_HEADPHONE = 0x8,
DEVICE_OUT_BLUETOOTH_SCO = 0x10,
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
DEVICE_OUT_AUX_DIGITAL = 0x400,
DEVICE_OUT_DEFAULT = 0x8000,
DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER |
DEVICE_OUT_WIRED_HEADSET | DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),
DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
// input devices
DEVICE_IN_COMMUNICATION = 0x10000,
DEVICE_IN_AMBIENT = 0x20000,
DEVICE_IN_BUILTIN_MIC = 0x40000,
DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
DEVICE_IN_WIRED_HEADSET = 0x100000,
DEVICE_IN_AUX_DIGITAL = 0x200000,
DEVICE_IN_VOICE_CALL = 0x400000,
DEVICE_IN_BACK_MIC = 0x800000,
DEVICE_IN_DEFAULT = 0x80000000,
DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT |
DEVICE_IN_BUILTIN_MIC |DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET |
DEVICE_IN_AUX_DIGITAL | DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC |
DEVICE_IN_DEFAULT)
};
目視しやすいものには赤で印をつけました。たくさんのことがありましたが、もう理解できないことはありません。
さあ、続けてください。
[--->AudioPolicyManagerBase::AudioPolicyManagerBase] です。
// ヘッドフォンもアウトボードも、現在利用可能な出力装置は厳しい設定です。
// そして最終的には、mAvailableOutputDevices = 0X3 となります。
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE | です。
AudioSystem::DEVICE_OUT_SPEAKER。
// 現在利用可能な入力デバイス、内蔵 MIC、mAvailableInputDevices は 0x4000 ですが、入力には関係ありません。
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
下敷きになるものはほとんどなく、すべて一発で終わります。
// AudioOutputDescriptor を作成し、そのデバイスを周辺機器 0x2 に設定します。
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
// APSのopenOutputを呼び出してmHardwareOutputを取得します。これは int です。
// でも、それがポインターかどうかはわかりません。
// また、以下のパラメータはすべてポインタ型ですよね?値を変更する人はいますか?
mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
// これは...intとポインタをマップに追加して、簡単に管理できるようにしているのでしょう。
addOutput(mHardwareOutput,outputDesc);
// 後で見てください。
setOutputDevice(mHardwareOutput, AudioSystem::DEVICE_OUT_SPEAKER, true);
// 後で見てください。
updateDeviceForStrategy();
さて、あそこには呼ばれるのを待っている一連の関数があります。ひとつひとつ見ていきましょう。
はっきりさせておきますが、これがAudioManagerBaseの心臓部です。
[---->AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor()].
// 各オーディオ出力の現在の設定を維持するために使用されます。
// そして、各オーディオ・ストリーム・タイプによる this出力の使用状況を追跡します。
わかる?たぶん、そういうことです:
l 設定情報の保存に使用できる音声出力について説明します。
l オーディオストリームの種類によって、この出力の使い方の一部を追跡します。
わからないでしょ?後でその場面に出くわしたらわかりますよ。
そのコンストラクタは次のようなフックを行います:
AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()
: mId(0), mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
mFlags((AudioSystem::output_flags)0), mDevice(0), mOutput1(0), mOutput2(0)
{}
// 集計がゼロになるのは素晴らしいことです。以上のことは説明するまでもないでしょう?命名規則も見ることができます。
わかりました。
ここでの呼び出しは、APSからのopenOutputです:
[--->AudioPolicyService::openOutput]
audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
uint32_t *pFormat,
uint32_t *pChannels,
uint32_t *pLatencyMs,
AudioSystem::output_flags flags)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
//マザーファッカー、AFを弄る。
return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels,
pLatencyMs, flags);
}
[----->AudioFlinger::openOutput]
int AudioFlinger::openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
uint32_t *pFormat,
uint32_t *pChannels,
uint32_t *pLatencyMs,
uint32_t flags)
{
//で渡される値について考えてみよう。
//*pDevices=0x2,外部アンプを代表して
//其他都是0。 嘿嘿,有了值,这不就知道下面该怎么走了吗?
status_t status;
PlaybackThread *thread = NULL;
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
uint32_t format = pFormat ? *pFormat : 0;
uint32_t channels = pChannels ? *pChannels : 0;
uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
Mutex::Autolock _l(mLock);
//HALオブジェクトはAudioStreamOutを取得するが、渡された値は変わるのか?
AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,
(int *)&format,
&channels,
&samplingRate,
&status);
mHardwareStatus = AUDIO_HW_IDLE;
if (output != 0) {
#p#
//どの支店に行くべきか?お答えしましょう。
// もちろん、AFはGENERIC Audioハードウェアを使用しています。興味のある方は、その実装をチェックしてみてください。
// 後で記事にします。とにかくここまで。
// フォーマットはPCM_16_BIT、チャンネルは2、サンプリングレートは14400です。
// その場合、elseブランチでなければなりません。
if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
(format != AudioSystem::PCM_16_BIT) ||
(channels != AudioSystem::CHANNEL_OUT_STEREO)) {
thread = new DirectOutputThread(this, output, ++mNextThreadId);
} else {
//Outputを開くと、AFでミキシングスレッドが作成されます。素敵なデザインですね。
//再生に設定されたすべてのプログラムの出力に、この再生ストリームミキシングスレッドが働いていると想像してください。
// ヘッドフォンに設定されているすべてのプログラムは、このヘッドフォンストリームのミキシングスレッドによって出力されます。
//なぜストリームを特別視するのですか?
// 呼び出しは mAudioHardware->openOutputStream(0x2,,,) です。返り値は
//これはAudioStreamOutであり、デバイスではありません。
// ヘッドフォンや周辺機器、ブルートゥースのリアルデバイスなどを管理するために、独自のシステムを考え出す必要はありません。例えば、GenericのAudio Halは1つのOutputStreamしかサポートしていません。
thread = new MixerThread(this, output, ++mNextThreadId);
}
//さて、もう1つスレッドがあります。
mPlaybackThreads.add(mNextThreadId, thread);
if (pSamplingRate) *pSamplingRate = samplingRate;
if (pFormat) *pFormat = format;
if (pChannels) *pChannels = channels;
if (pLatencyMs) *pLatencyMs = thread->latency();
// ここからリミックススレッドのインデックスが返されます。
return mNextThreadId.
return 0;// スレッドの作成に成功しなかった場合は0を返します。
}
さて、AudioManagerBaseに戻ります。
[--->AudioPolicyManagerBase::AudioPolicyManagerBase]
mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
//APSは実際にスレッドインデックスを持つだけで十分なのでしょうか?インデックスをハードウェアの識別子として扱いますが。
// これは...マップにintやポインタを追加して管理しやすくしているのでしょう。見ないでください。
addOutput(mHardwareOutput,outputDesc);
// 何のために?
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
[--->setOutputDevice(mHardwareOutput,...)]
この機能、重要です!また、いくつかのより多くのヒントを渡します。常に後方および後方のソースの洞察力ではありませんが、直接最近開いたファイルをリストしているウィンドウメニューを、見つけるAudioManagerBase.cppを、行にない?
void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)
{
// パラメータに注意してください:
// 出力 = 1.
AudioSystem::DEVICE_OUT_SPEAKER 用 //デバイス
// forceがtrueの場合、delayMsはデフォルト値0を使用します。
//addOutputですでに追加されています。addOutputですでに追加されています。
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
if (outputDesc->isDuplicated()) {
setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
return;
}
// addOutputの前に設定されたデバイスを覚えていますか?そう、0X3、外部ヘッドフォンです。
uint32_t prevDevice = (uint32_t)outputDesc->device();
さて、セットアップは周辺機器だ。,
if ((device == 0 || device == prevDevice) && !force) {
return;
}
//このoutputDescをoutgoingに設定する。
outputDesc->mDevice = device;
popCount2については、デバイス=0x2=0010
// また、特に興味があるのは以下の出力です== mHardwareOutput.先ほどのクエリを覚えていますか?
// mHardwareOutputは、実際にはAFが返すスレッドインデックスです。
すべてのスレッドを管理するのはどうでしょう?案の定、出力が最初に作成されたスレッドのインデックスと等しいかどうかの比較です。
// これは示しています。このようなmHardwareOutputしかありませんが、実際には他の出力を操作することができます!
if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) {
setStrategyMute(STRATEGY_MEDIA, true, output);
usleep(outputDesc->mLatency*2*1000);
}
// しかし、意味は明確です。
// 新しい出力デバイスは外部です。
//外付けからヘッドフォンへの切り替えについては、また後日お話しします。
AudioParameter param = AudioParameter();
param.addInt(String8(AudioParameter::keyRouting), (int)device);
mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);
// update stream volumes according to new device
applyStreamVolumes(output, device, delayMs);
// ヘッドセットとスピーカーを組み合わせたルートから変更する場合は、メディアストリームのミュートを解除します。
if == 2) {。
// 詳しくは後ほど。
setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
}
}
じゃあ、下がって。
setOutputDevice(mHardwareOutput、AudioSystem::DEVICE_OUT_SPEAKER、true);
この研究では、mHardwareOutputに対応する出力ルーティング・デバイスを更新し、またAPSに、私のためにリミックス・スレッドに対応する出力ルーティング・デバイスを更新してくださいというコマンドを送りました。
[--->AudioPolicyManagerBase::AudioPolicyManagerBase]
.....
addOutput(mHardwareOutput, outputDesc);
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER,
true);
// 最後の関数だけが残っています
updateDeviceForStrategy();
[----->updateDeviceForStrategy()]
void AudioPolicyManagerBase::updateDeviceForStrategy()
{
for (int i = 0; i < NUM_STRATEGIES; i++) {
mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);
}
}
また列挙が始まったわ。見てください。
[---->for (int i = 0; i < NUM_STRATEGIES; i++)]
NUM_STRATEGIESハードウェア/libhardwareでは_legacy/include/hardware_legacy/
AudioPolicyManagerBase.hで定義する。
enum routing_strategy {
//かなり理解されているようだ
STRATEGY_MEDIA,
STRATEGY_PHONE,//しゃべる音?
STRATEGY_SONIFICATION,//他の3つに加えて、着信音、リマインダー音等もあり得る。
STRATEGY_DTMF,//発信音のようだ。
NUM_STRATEGIES
};
これは、とにかく、SDKに該当する説明がなかったので、後で見てみます。
[----->getDeviceForStrategy(i,false)]。
関数名の意味を見て、様々な戦略のために対応するデバイスを検索します。
uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
{
// fromCacheはfalseです。
// 一見すると、この関数は非常に戦略的なことに関与しているように見えます。
// なぜそのような動作をするのか、Googleに聞いてみてください。
uint32_t device = 0;
switch (strategy) {
case STRATEGY_DTMF:
if (mPhoneState != AudioSystem::MODE_IN_CALL) {
//通話中にもう一度ボタンを押すと、MEDIAで1つのデバイスになる
device = getDeviceForStrategy(STRATEGY_MEDIA, false);
break;
}
//他のモードでは、DTMFとPHONEは単一のストラテジーを使用します。
ケース STRATEGY_PHONE.
// また、ユーザーが出力デバイスの使用を強制しているかどうかも判断しなければなりません。
switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
case AudioSystem::FORCE_BT_SCO:
if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
device = mAvailableOutputDevices &
AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device) break;
}
device = mAvailableOutputDevices &
AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
if (device) break;
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
if (device) break;
// if SCO device is requested but no SCO device is available, fall back to default
// case
// FALL THROUGH
//強制的な設定を覚えているだろうか?そう、この時点ではすべてforceなのだ_NONE
//而且,mAvailableOutputDevices是0X3 (外放|ヘッドフォン)
default: // FORCE_NONE
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
if (device) break;
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
if (device) break;
//ほら、次の文章が成り立つ どういう意味か?ヘッドホンがあれば、出力デバイスはヘッドホンである
//その通りだ。実際の携帯電話はそうなっているのではないだろうか?
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
break;
//今言ったことをもう一度確認すると、外部アンプを強制的に使用する場合,
case AudioSystem::FORCE_SPEAKER:
if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
device = mAvailableOutputDevices &
AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device) break;
}
//案の定、発信音を強制的に使うことになる。
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
break;
}
break;
case STRATEGY_SONIFICATION://分析は上記と同じなので割愛する。
if (mPhoneState == AudioSystem::MODE_IN_CALL) {
device = getDeviceForStrategy(STRATEGY_PHONE, false);
break;
}
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
// SONIFICATIONがMEDIAストラテジーの影響を受けていることがわかる。
case STRATEGY_MEDIA: {
uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
}
//残念ながら、上記のような先進的なデバイスはない。
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
}
//SONIFICATIONから音が降りてこないと仮定すると、デバイスは最終的に次のようになる。= DEVICE_OUT_SPEAKER。
//SONIFICATIONから降りてくると仮定すると、DEVICEはやはりDEVICEに等しい。_OUT_SPEAKER
//不思議なことに、なぜヘッドホンがあると出るのか?普通のヘッドホンとインラインヘッドホンの区別はあるのだろうか?
device |= device2;
} break;
default:
break;
}
return device;
}
さて、話を戻します。
[---->AudioPolicyManagerBase::updateDeviceForStrategy()]
void AudioPolicyManagerBase::updateDeviceForStrategy()
{
for (int i = 0; i < NUM_STRATEGIES; i++) {
mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);
}
}
この機能が終了したということは、様々なポリシーの下で使用される対応するデバイスの準備も整ったということです。
APSのビルドが完了しました。
記念にどうぞ:
AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
{
....
updateDeviceForStrategy();
}
AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService() , mpPolicyManager(NULL)
{
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
mpPolicyManager = new AudioPolicyManagerBase(this);
LOGV("build for GENERIC_AUDIO - using generic audio policy");
...
#endif
property_get("ro.camera.sound.forced", value, "0");
mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
}
要約すると
要約すると、AF,APSを作成し、何ができましたか?以下、優先順位順。
l AFはHALオブジェクトの表現を作成します。
l APSは2つのAudioCommandThreadsを作成し、1つはコマンドを処理し、もう1つはトーンを再生します。
l APSは、システムのデフォルトオーディオマネージャーとしてAudioManagerBaseも作成します。
l AMBはポリシーの上にあるものを一元管理し、同時にAFのopenOutputにミキシングスレッドを作成します。同時に、AMBは戦略の取り決めの一部を更新します。
また、分析されたAMBはGenericですが、異なるメーカーは独自の戦略を実行できます。例えば、ヘッドホンを持っている限り、あらゆる種類の音がヘッドホンから出るように設定できます。
AMBの側面に関する上記は、まだそのコードを見ただけで、実用的な例として評価できるものではありません。





