こんにちは!カイトさんのブログはこちら
私とのコミュニケーションを歓迎します。
Android N の例を次に示します。
AudioTrack を理解する前に、AudioTrack、PlaybackThread、および出力ストリーム デバイス間の対応を簡単に説明するインターネットの写真を見つけました。1対1の対応です(OffloadThreadはcompress_offloadデバイスにのみオーディオデータを出力し、MixerThread(FastMixerを使用)はlow_latencyデバイスにのみオーディオデータを出力します)
AudioTrack、PlaybackThread、および出力ストリーム デバイスの関係図から、AudioTrack がオーディオ ストリーム データを対応する PlaybackThread に送信し、アプリケーション プロセスがこれらのオーディオ ストリームを制御したい場合 (たとえば、start() の再生の開始、停止) を確認できます。再生停止()、一時停止再生一時停止()、どうすればいいですか? アプリケーション プロセスと AudioFlinger は同じプロセス上にないことに注意してください。これには、AudioFlinger がオーディオ ストリーム管理機能を提供し、アプリケーション プロセスがプロセス間で AudioFlinger のオーディオ ストリーム ステータスを制御できるようにする一連の通信インターフェイスを提供する必要があります。
AudioFlinger オーディオ ストリーム管理は、AudioFlinger::PlaybackThread::Track によって実装されます。トラックと AudioTrack は 1 対 1 の関係にあります。アプリケーションでは、AudioTrack が作成されるたびに、AudioFlinger 側でトラックが作成されます。それに対応する AudioFlinger の PlaybackThread;
PlaybackThread と AudioTrack/Track は 1 対多の関係にあり、1 つの PlaybackThread で複数のトラックをハングアップできます。Track と AudioTrack の間で、オーディオ データは共有メモリを介して送信されます。これは 2 つの状況に分けることができます
。着信音やシステム通知など、メモリをほとんど必要としない再生操作に適しています。
2.MODE_STREAM: ストリーム モードは、ネットワーク ベースのオーディオ ストリーム再生に似ており、オーディオ データは最後まで要件に厳密に従って複数回レシーバに渡されます。これは通常、オーディオ ファイルが大きい場合に適用されます。オーディオ プロパティの要件が高く、サンプリング レートが高く深度が大きいデータなどです。
- AudioFlinger::PlaybackThread : 再生スレッドの基本クラス、異なる出力識別子を持つオーディオ ストリームは異なるタイプの PlaybackThread インスタンスに対応します
- AudioFlinger::PlaybackThread::Track : オーディオ ストリーム管理クラス。AudioTrack と AudioFlinger 間のデータ交換用の匿名共有メモリを作成します。
- AudioFlinger::TrackHandle: The Track object is only responsible for the audio stream management business. 外部へのクロスプロセス Binder 呼び出しインターフェイスを提供せず、アプリケーション プロセスがオーディオ ストリームを制御する必要があるため、オブジェクトが必要です。 Track のクロスプロセス通信をプロキシする. この役割は TrackHandle であり、それを通じて AudioTrack は Track と相互作用する.
- AudioTrack: Android オーディオ システムによって提供される API クラスで、オーディオ ストリーム データ出力を担当します。各オーディオ ストリームは AudioTrack インスタンスに対応し、異なる出力識別子を持つ AudioTrack は異なる AudioFlinger::PlaybackThread と一致します。
- AudioTrack::AudioTrackThread : データ送信モードが TRANSFER_CALLBACK の場合、このスレッドを作成する必要があります. ユーザー プロセスから積極的にデータを要求し、audioCallback コールバック関数を呼び出してバッファに入力します. データ送信モードが TRANSFER_SYNC の場合、これがスレッドを作成する必要はありません. ユーザー プロセスは引き続き AudioTrack.write() を呼び出してデータをバッファーに入れるため; データ転送モードが TRANSFER_SHARED の場合, ユーザー プロセスが匿名共有メモリを作成し、一度に再生する音声データをこの匿名共有メモリにコピーします
ソース コードに Audiotrack のアプリケーション例があり、左右のステレオ チャンネルの最大音量をテストするために使用されます。
//frameworks/base/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java
public void testSetStereoVolumeMax() throws Exception {
// constants for test
final String TEST_NAME = "testSetStereoVolumeMax";
final int TEST_SR = 22050;
final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
//-------- initialization --------------
int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
minBuffSize, TEST_MODE);
byte data[] = new byte[minBuffSize/2];
//-------- test --------------
track.write(data, 0, data.length);
track.write(data, 0, data.length);
track.play();
float maxVol = AudioTrack.getMaxVolume();//获取最大音量值
assertTrue(TEST_NAME, track.setStereoVolume(maxVol, maxVol) == AudioTrack.SUCCESS);
//-------- tear down --------------
track.release();
}
このデモには、AudioTrack の一般的な操作が含まれています。
ステップ 1: getMinBufferSize、最小バッファー サイズを計算する
ステップ 2: audiotrack オブジェクトを作成する ステップ
3: オーディオ データを書き込むための書き込み
ステップ 4: 再生を開始してオーディオを再生する
ステップ 5: リリースして再生を終了する
//@AudioTrack.cpp
AudioTrack::AudioTrack(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
audio_output_flags_t flags,
callback_t cbf,
void* user,
int32_t notificationFrames,
audio_session_t sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
int uid,
pid_t pid,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed)
: mStatus(NO_INIT),
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
}
status_t AudioTrack::set(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
audio_output_flags_t flags,
callback_t cbf,
void* user,
int32_t notificationFrames,
const sp<IMemory>& sharedBuffer,
bool threadCanCallJava,
audio_session_t sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
int uid,
pid_t pid,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed)
{
//......
// handle default values first.
if (streamType == AUDIO_STREAM_DEFAULT) {
streamType = AUDIO_STREAM_MUSIC;//default则默认为AUDIO_STREAM_MUSIC
}
if (pAttributes == NULL) {
//不会超过AUDIO_STREAM_PUBLIC_CNT,一共有13种类型可选择
if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
ALOGE("Invalid stream type %d", streamType);
return BAD_VALUE;
}
//mStreamType赋值,createTrack_l里会用到
mStreamType = streamType;
} else {
// stream type shouldn't be looked at, this track has audio attributes
memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
//mStreamType赋值,createTrack_l里会用到
mStreamType = AUDIO_STREAM_DEFAULT;
if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
}
if ((mAttributes.flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
flags = (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_FAST);
}
}
//......
//mFlags赋值,createTrack_l里会用到
mOrigFlags = mFlags = flags;
mCbf = cbf;
if (cbf != NULL) {
mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
// thread begins in paused state, and will not reference us until start()
}
// create the IAudioTrack
status_t status = createTrack_l();
}
- 1. 最初に streamType を決定し、AudioTrack メンバー mStreamType に値を割り当てます。
- 2. AudioTrack メンバー mFlags に値を割り当てます。フラグは AudioTrack の構築時に渡されます。
- 3. cbf (audioCallback コールバック関数) が空でない場合、audioTrackThread スレッドを作成して audioCallback コールバック関数を処理します (MODE_STREAM モードでは、cbf は空です);
- 4.実行しますが、すぐには実行されません。開始されるまで一時停止します (スレッドは一時停止状態で開始され、start() まで参照されません);
- 5. createTrack_l メソッドを呼び出して IAudioTrack を作成します。
status_t AudioTrack::createTrack_l()
{
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
status = AudioSystem::getOutputForAttr(attr, &output,
mSessionId, &streamType, mClientUid,
mSampleRate, mFormat, mChannelMask,
mFlags, mSelectedDeviceId, mOffloadInfo);
sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
mSampleRate,
mFormat,
mChannelMask,
&temp,
&flags,
mSharedBuffer,
output,
mClientPid,
tid,
&mSessionId,
mClientUid,
&status);
// update proxy
//用于管理共享内存
if (mSharedBuffer == 0) {
//MODE_STREAM
mStaticProxy.clear();
mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSize);
} else {
//MODE_STATIC
mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSize);
mProxy = mStaticProxy;
}
}
- 1. audioFlinger を取得する
- 2. getOutputForAttr は、AudioTrack によって渡されたサウンド タイプに従って属性を設定し、サウンド属性に従ってそのグループ/カテゴリを決定し、デバイスを見つけ、最後にデバイスに従って対応する出力を見つけます。(デバイスは複数の出力に対応する場合があります(各サウンドカードは出力に対応します)が、選択されるのは 1 つだけです)
- 3. AudioFlinger::PlaybackThread::Track を作成します。(AudioTrack 作成プロセス中に、出力を選択します。出力は再生デバイスに対応し、PlaybackThread にも対応します。アプリケーションの AudioTrack は PlaybackThread のトラックに対応します)。
- 4. AudioTrackClientProxy/StaticAudioTrackClientProxy を作成して、共有メモリを管理します。(APP の AudioTrack <==> スレッドのトラックは、共有メモリを介してデータを転送します)
次の関数呼び出しスタックは次のとおりです。
AudioTrack::createTrack_l
AudioSystem::getOutputForAttr
AudioPolicyService::getOutputForAttr
AudioPolicyManager::getOutputForAttr
AudioPolicyManager::getOutputForDevice
AudioPolicyService::AudioPolicyClient::openOutput
af->openOutput
AudioFlinger::createTrack
AudioFlinger::PlaybackThread::createTrack_l
AudioFlinger::PlaybackThread::Track::Track
AudioFlinger::ThreadBase::TrackBase::TrackBase
new AudioTrackServerProxy/StaticAudioTrackServerProxy
new TrackHandle
new AudioTrackClientProxy/StaticAudioTrackClientProxy
AudioSystem::getOutputForAttr を見てください。
//@AudioTrack.cpp
status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
audio_port_handle_t selectedDeviceId,
const audio_offload_info_t *offloadInfo)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return NO_INIT;
return aps->getOutputForAttr(attr, output, session, stream, uid,
samplingRate, format, channelMask,
flags, selectedDeviceId, offloadInfo);
}
//@AudioPolicyInterfaceImpl.cpp
status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
audio_port_handle_t selectedDeviceId,
const audio_offload_info_t *offloadInfo)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate,
format, channelMask, flags, selectedDeviceId, offloadInfo);
}
//@AudioPolicyManager.cpp
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
audio_port_handle_t selectedDeviceId,
const audio_offload_info_t *offloadInfo)
{
audio_attributes_t attributes;
if (attr != NULL) {
if (!isValidAttributes(attr)) {
ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
attr->usage, attr->content_type, attr->flags,
attr->tags);
return BAD_VALUE;
}
attributes = *attr;
} else {
if (*stream < AUDIO_STREAM_MIN || *stream >= AUDIO_STREAM_PUBLIC_CNT) {
ALOGE("getOutputForAttr(): invalid stream type");
return BAD_VALUE;
}
stream_type_to_audio_attributes(*stream, &attributes);
}
//根据attributes获取策略strategy,即获取类别/组
routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
//根据strategy获取device,即根据类别/组获取播放设备(耳机、蓝牙、外放喇叭)
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
//哪些output上有对应当device
*output = getOutputForDevice(device, session, *stream,
samplingRate, format, channelMask,
flags, offloadInfo);
}
//@AudioPolicyManager.cpp
audio_io_handle_t AudioPolicyManager::getOutputForDevice(
audio_devices_t device,
audio_session_t session,
audio_stream_type_t stream,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
//......
status = mpClientInterface->openOutput(profile->getModuleHandle(),
&output,
&config,
&outputDesc->mDevice,
address,
&outputDesc->mLatency,
outputDesc->mFlags);
//......
return output;
}
//@AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t *devices,
const String8& address,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
//af即AudioFlinger,这里即是AudioFlinger::openOutput
return af->openOutput(module, output, config, devices, address, latencyMs, flags);
}
getOutputForAttr は、出力の出力チャンネルを取得します (出力は、プライマリ アウト、低レイテンシー アウト、オフロード、direct_pcm、a2dp 出力、usb_device 出力、dp 出力などを含む、hal 層のオーディオ チャンネルの代表として理解できます)。 AudioFlinger::openOutputのプロセスは、次の記事を参照してください: Android オーディオ サブシステム (1) ------ openOutput オープン プロセス
したがって、最終的に getOutputForAttr は attr、streamType およびその他のパラメーターを渡し、デバイスを選択して OutputFor を取得します (実際、AudioPolicyClient::openOutput は開いているデバイスを返します)。
sp<IAudioTrack> AudioFlinger::createTrack(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *frameCount,
audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t pid,
pid_t tid,
audio_session_t *sessionId,
int clientUid,
status_t *status)
{
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
PlaybackThread *thread = checkPlaybackThread_l(output);
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus);
// return handle to client
trackHandle = new TrackHandle(track);
}
- 1. checkPlaybackThread_l を使用して、audio_io_handle_t 型パラメーターに従って、対応する PlaybackThread を見つけます (これらは対応関係です)。
- 2. PlaybackThread::createTrack_l を呼び出して、Track オブジェクトを作成し、mTracks に追加します。トラックが構築されたら、AudioFlinger と AudioTrack 間のデータ交換用にメモリのブロックを割り当て (audio_track_cblk_t* mCblk は制御ブロック)、AudioTrackServerProxy /StaticAudioTrackServerProxy オブジェクトを作成して Buffer を管理します (PlaybackThread はそれを使用して読み取り可能なデータの場所を取得します)。バッファから)
- 3. Track 通信エージェント TrackHandle を作成し、trackHandle に割り当てます。
ここでは、AudioTrack オブジェクトを作成すると、特定の PlaybackThread で Track オブジェクトが作成されることもわかります。これらは対応する関係です。
//@Threads.cpp
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
const sp<AudioFlinger::Client>& client,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
audio_output_flags_t *flags,
pid_t tid,
int uid,
status_t *status)
{
//......
track = new Track(this, client, streamType, sampleRate, format,
channelMask, frameCount, NULL, sharedBuffer,
sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
//PlaybackThread中存在一个数组mTracks,其中包含一个或者多个Track
//每一个Track都对应应用程序中创建的AudioTrack
mTracks.add(track);
}
//@Tracks.cpp
AudioFlinger::PlaybackThread::Track::Track(
PlaybackThread *thread,
const sp<Client>& client,
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
int uid,
audio_output_flags_t flags,
track_type type)
: TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
(sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
sessionId, uid, true /*isOut*/,
(type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
type),
mFillingUpStatus(FS_INVALID),
// mRetryCount initialized later when needed
mSharedBuffer(sharedBuffer),
mStreamType(streamType),
mName(-1), // see note below
mMainBuffer(thread->mixBuffer()),
mAuxBuffer(NULL),
mAuxEffectId(0), mHasVolumeController(false),
mPresentationCompleteFrames(0),
mFrameMap(16 /* sink-frame-to-track-frame map memory */),
// mSinkTimestamp
mFastIndex(-1),
mCachedVolume(1.0),
mIsInvalid(false),
mAudioTrackServerProxy(NULL),
mResumeToStopping(false),
mFlushHwPending(false),
mFlags(flags)
{
if (sharedBuffer == 0) {
mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize, !isExternalTrack(), sampleRate);
} else {
mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize);
}
mServerProxy = mAudioTrackServerProxy;
}
//@Tracks.cpp
AudioFlinger::ThreadBase::TrackBase::TrackBase(
ThreadBase *thread,
const sp<Client>& client,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
audio_session_t sessionId,
int clientUid,
bool isOut,
alloc_type alloc,
track_type type)
: RefBase(),
mThread(thread),
mClient(client),
mCblk(NULL),
// mBuffer
mState(IDLE),
mSampleRate(sampleRate),
mFormat(format),
mChannelMask(channelMask),
mChannelCount(isOut ?
audio_channel_count_from_out_mask(channelMask) :
audio_channel_count_from_in_mask(channelMask)),
mFrameSize(audio_has_proportional_frames(format) ?
mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
mFrameCount(frameCount),
mSessionId(sessionId),
mIsOut(isOut),
mServerProxy(NULL),
mId(android_atomic_inc(&nextTrackId)),
mTerminated(false),
mType(type),
mThreadIoHandle(thread->id())
{
size_t size = sizeof(audio_track_cblk_t);
size_t bufferSize = (buffer == NULL ? roundup(frameCount) : frameCount) * mFrameSize;
/*如果buffer为空,并且alloc == ALLOC_CBLK*/
if (buffer == NULL && alloc == ALLOC_CBLK) {
/*size为一个头部(起到控制作用),如果buffer为NULL,即应用程序没有分配,则大小增加bufferSize*/
size += bufferSize;
}
if (client != 0) {
/*分配内存*/
mCblkMemory = client->heap()->allocate(size);
} else {
// this syntax avoids calling the audio_track_cblk_t constructor twice
mCblk = (audio_track_cblk_t *) new uint8_t[size];
// assume mCblk != NULL
}
// construct the shared structure in-place.
if (mCblk != NULL) {
new(mCblk) audio_track_cblk_t();
switch (alloc) {
case ALLOC_READONLY: {
const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
if (roHeap == 0 ||
(mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
(mBuffer = mBufferMemory->pointer()) == NULL) {
mCblkMemory.clear();
mBufferMemory.clear();
return;
}
memset(mBuffer, 0, bufferSize);
} break;
case ALLOC_PIPE:
mBufferMemory = thread->pipeMemory();
// mBuffer is the virtual address as seen from current process (mediaserver),
// and should normally be coming from mBufferMemory->pointer().
// However in this case the TrackBase does not reference the buffer directly.
// It should references the buffer via the pipe.
// Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
mBuffer = NULL;
break;
case ALLOC_CBLK:
// clear all buffers
if (buffer == NULL) {
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, bufferSize);
} else {
mBuffer = buffer;
}
break;
case ALLOC_LOCAL:
mBuffer = calloc(1, bufferSize);
break;
case ALLOC_NONE:
mBuffer = buffer;
break;
}
}
上記の Track コンストラクターでは、アプリケーションが MODE_STREAM モードの場合、Buffer を管理するために AudioTrackServerProxy が作成されます。それ以外の場合は、Buffer を管理するために MODE_STATIC モードで StaticAudioTrackServerProxy が作成されます。
前に言ったように、APP が AudioTrack を作成し、次に AudioFlinger::playbackThread が対応するトラックを作成します。それらは共有メモリを介してデータを渡します:
Track は AudioTrackServerProxy/StaticAudioTrackServerProxy を使用して Buffer を管理し、対応して AudioTrack は AudioTrackClientProxy/StaticAudioTrackClientProxy を使用して AudioTrack::set の Buffer を管理します。
Track 内の AudioTrackServerProxy/StaticAudioTrackServerProxy はすべて ServerProxy から継承されます。ServerProxy は、obtainBuffer、releaseBuffer 関数を含む共有メモリの管理に使用され、playbackThread は obtiainBuffer を使用してデータを含むメモリを取得し、releaseBuffer を使用して消費後にデータを解放します。
//@AudioTrackShared.h
// Proxy used by AudioFlinger server
class ServerProxy : public Proxy {
virtual status_t obtainBuffer(Buffer* buffer, bool ackFlush = false);
virtual void releaseBuffer(Buffer* buffer);
}
Android は大きすぎ、プロセスが多すぎます。. . . . .
一般に、AudioTrack は次の 3 つのステップに単純に分けることができます。
1 AudioTrack のプロパティを使用して、AudioPolicy に従って対応する出力と PlaybackThread を見つけます。 2 PlaybackThread に
対応するトラックを作成します。
3 APP の AudioTrack と mTracks のトラックの間共有メモリの作成