AudioTrack 参数的初始化
接下来我们重点看一下set函数,其中set函数分成两个部分,参数相关的设置和创建IAudioTrack。这里我们重点看一下参数相关的初始化。
1. 数据传输类型的判断
这里主要根据调用者传入的transferType(数据传输类型), 回调函数(cbf)和共享内存(sharedBuffer)。
(1) TRANSFER_SHARED模式,必须传入 sharedBuffer。
这种模式适用于比较短的声音以及需要低延时播放的声音。数据只需要传一次,sharedBuffer就是数据的起始地址。
(2) TRANSFER_CALLBACK模式,需要传入一个 cbf 用于对上层的回调。
这种模式下,AudioTrack会创建一个 AudioTrackThread。主要负责上层和AudioFlinger之间的数据传输以及调用cbf报告数据传输的状态。
(3) TRANSFER_OBTAIN 模式,主动写数据的一种模式。
上层调用obtainBuffer等待有可用的buffer,obtainBuffer会返回一段Buffer,上层把数据传到这块Buffer,然后调用releaseBuffer即可。
(4) TRANSFER_SYNC 模式,另一种主动写数据模式。
对 TRANSFER_OBTAIN 模式的一种封装,上层只需要调用write函数传入数据。
(5) TRANSFER_SYNC_NOTIF_CALLBACK 模式,类似于 TRANSFER_SYNC 模式。
上层需要传入 cbf,用于收AudioTrack传入的 EVENT_CAN_WRITE_MORE_DATA 等消息。
switch (transferType) {
case TRANSFER_DEFAULT:
if (sharedBuffer != 0) {
// 如果传入了sharedBuffer,只能用TRANSFER_SHARED
transferType = TRANSFER_SHARED;
} else if (cbf == NULL || threadCanCallJava) {
// 没有cbf和sharedBuffer,一般需要使用TRANSFER_SYNC
transferType = TRANSFER_SYNC;
} else {
// 如果传入了cbf,一般需要使用TRANSFER_CALLBACK
transferType = TRANSFER_CALLBACK;
}
break;
// ..............
}
mSharedBuffer = sharedBuffer;
mTransfer = transferType;
mDoNotReconnect = doNotReconnect;
2. 关于 streamType, Attributes和 flags 的处理
这两个变量是对声音声音的内容和用途的描述。Attributes是对streamType一个扩展,用来取代streamType,Attributes可以用来描述更多的信息。
Attributes直接影响AudioPlicy的策略,比如声音的输出设备,音量的控制,数据的延时等。
flags是上层用来主动选择播放策略,例如 offload,low latency, deep buffer …
如果上层传入了 Attributes, streamType和flags 都会被忽略
// (1) streamType的处理
if (streamType == AUDIO_STREAM_DEFAULT) {
// 默认会选择 AUDIO_STREAM_MUSIC
streamType = AUDIO_STREAM_MUSIC;
}
// (2) Attributes的处理
if (pAttributes == NULL) {
// 如果上层没有传入 Attributes,会使用 streamType
mStreamType = streamType;
} else {
// 如果传入了 Attributes,StreamType 和 flags 会被忽略
memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
mStreamType = AUDIO_STREAM_DEFAULT;
audio_flags_to_audio_output_flags(mAttributes.flags, &flags);
}
// (3) flags的处理
// 如果应用需要使用COMPRESS_OFFLOAD或者数据格式不是PCM,需要添加FLAG_DIRECT,并且去除FLAG_FAST。
// 对于非PCM的数据,只能用FLAG_DIRECT。
if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) || !audio_is_linear_pcm(format))
flags = (audio_output_flags_t)((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
// 如果FLAG_HW_AV_SYNC(硬件音视频同步)强制使用FLAG_DIRECT
if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
3.数据格式相关的参数 format,Channel, sampleRate
// format : PCM 16BIT作为默认的数据格式
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
}
mFormat = format;
// Channel : 通过ChannelMask计算ChannelCount
mChannelMask = channelMask;
channelCount = audio_channel_count_from_out_mask(channelMask);
mChannelCount = channelCount;
// FrameSize : 一个帧的大小
// 对于非PCM数据,使用一个字节的大小
// 对于PCM数据,使用声道数 * 采样精度
if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
if (audio_has_proportional_frames(format)) {
mFrameSize = channelCount * audio_bytes_per_sample(format);
} else {
mFrameSize = sizeof(uint8_t);
}
} else {
ALOG_ASSERT(audio_has_proportional_frames(format));
mFrameSize = channelCount * audio_bytes_per_sample(format);
}
// sampleRate : 采样率
mSampleRate = sampleRate;
mOriginalSampleRate = sampleRate;
mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
// 1.0 <= mMaxRequiredSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX
mMaxRequiredSpeed = min(max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
4. OffloadInfo的赋值(没有copy,只是传了地址)
if (offloadInfo != NULL) {
mOffloadInfoCopy = *offloadInfo;
mOffloadInfo = &mOffloadInfoCopy;
} else {
mOffloadInfo = NULL;
memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
}
5. 初始化mReqFrameCount
// mFrameCount is initialized in createTrack_l
mReqFrameCount = frameCount;
if (notificationFrames >= 0) {
mNotificationFramesReq = notificationFrames;
mNotificationsPerBufferReq = 0;
} else {
mNotificationFramesReq = 0;
const uint32_t minNotificationsPerBuffer = 1;
const uint32_t maxNotificationsPerBuffer = 8;
mNotificationsPerBufferReq = min(maxNotificationsPerBuffer,
max((uint32_t) -notificationFrames, minNotificationsPerBuffer));
}
6. 获取调用者的pid,uid
callingPid = IPCThreadState::self()->getCallingPid();
myPid = getpid();
if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) {
mClientUid = IPCThreadState::self()->getCallingUid();
} else {
mClientUid = uid;
}
if (pid == -1 || (callingPid != myPid)) {
mClientPid = callingPid;
} else {
mClientPid = pid;
}