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;
}