IAudioManager.cpp源码解读

news2024/11/18 6:03:25

IAudioManager.cpp源码如下:
源码路径:https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/services/audiomanager/IAudioManager.cpp;drc=84410fbd18148d422d3581201c67f1a72a6658c4;l=147?hl=zh-cn

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "IAudioManager"
//#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <stdint.h>
#include <sys/types.h>

#include <binder/Parcel.h>
#include <audiomanager/AudioManager.h>
#include <audiomanager/IAudioManager.h>

namespace android {

class BpAudioManager : public BpInterface<IAudioManager>
{
public:
    explicit BpAudioManager(const sp<IBinder>& impl)
        : BpInterface<IAudioManager>(impl)
    {
    }

    virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
            audio_content_type_t content, const sp<IBinder>& player, audio_session_t sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32(1); // non-null PlayerIdCard parcelable
        // marshall PlayerIdCard data
        data.writeInt32((int32_t) playerType);
        //   write attributes of PlayerIdCard
        data.writeInt32((int32_t) usage);
        data.writeInt32((int32_t) content);
        data.writeInt32(0 /*source: none here, this is a player*/);
        data.writeInt32(0 /*flags*/);
        //   write attributes' tags
        data.writeInt32(1 /*FLATTEN_TAGS*/);
        data.writeString16(String16("")); // no tags
        //   write attributes' bundle
        data.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle
        //   write IPlayer
        data.writeStrongBinder(player);
        //   write session Id
        data.writeInt32((int32_t)sessionId);
        // get new PIId in reply
        const status_t res = remote()->transact(TRACK_PLAYER, data, &reply, 0);
        if (res != OK || reply.readExceptionCode() != 0) {
            ALOGE("trackPlayer() failed, piid is %d", PLAYER_PIID_INVALID);
            return PLAYER_PIID_INVALID;
        } else {
            const audio_unique_id_t piid = (audio_unique_id_t) reply.readInt32();
            ALOGV("trackPlayer() returned piid %d", piid);
            return piid;
        }
    }

    virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
            audio_content_type_t content) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        data.writeInt32(1); // non-null AudioAttributes parcelable
        data.writeInt32((int32_t) usage);
        data.writeInt32((int32_t) content);
        data.writeInt32(0 /*source: none here, this is a player*/);
        data.writeInt32(0 /*flags*/);
        //   write attributes' tags
        data.writeInt32(1 /*FLATTEN_TAGS*/);
        data.writeString16(String16("")); // no tags
        //   write attributes' bundle
        data.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle
        return remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);
    }

    virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
            audio_port_handle_t eventId) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        data.writeInt32((int32_t) event);
        data.writeInt32((int32_t) eventId);
        return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
    }

    virtual status_t releasePlayer(audio_unique_id_t piid) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        return remote()->transact(RELEASE_PLAYER, data, &reply, IBinder::FLAG_ONEWAY);
    }

    virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeStrongBinder(recorder);
        // get new RIId in reply
        const status_t res = remote()->transact(TRACK_RECORDER, data, &reply, 0);
        if (res != OK || reply.readExceptionCode() != 0) {
            ALOGE("trackRecorder() failed, riid is %d", RECORD_RIID_INVALID);
            return RECORD_RIID_INVALID;
        } else {
            const audio_unique_id_t riid = (audio_unique_id_t) reply.readInt32();
            ALOGV("trackRecorder() returned riid %d", riid);
            return riid;
        }
    }

    virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) riid);
        data.writeInt32((int32_t) event);
        return remote()->transact(RECORDER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
    }

    virtual status_t releaseRecorder(audio_unique_id_t riid) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) riid);
        return remote()->transact(RELEASE_RECORDER, data, &reply, IBinder::FLAG_ONEWAY);
    }

    virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        data.writeInt32((int32_t) sessionId);
        return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);
    }

    virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
            const std::unique_ptr<os::PersistableBundle>& extras) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) portId);
        data.writeInt32((int32_t) event);
        // TODO: replace PersistableBundle with own struct
        data.writeNullableParcelable(extras);
        return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
    }
};

IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");

// ----------------------------------------------------------------------------

}; // namespace android

这里显示了一个名为 IAudioManager.cpp 的文件,它是一个 C++ 语言的源代码文件,用于实现音频管理器的接口。代码的逻辑如下:

  • 定义了一个 BpAudioManager 类,它继承了 BpInterface 类,用于实现 Binder 通信的代理端。
  • 在 BpAudioManager 类中,实现了 IAudioManager 接口中的各个方法,包括:
    • trackPlayer:用于追踪一个播放器的类型、用途、内容、会话 ID 等信息,并返回一个唯一的播放器 ID。
    • playerAttributes:用于更新一个播放器的用途和内容属性。
    • playerEvent:用于通知一个播放器的状态变化,如开始、暂停、停止等。
    • releasePlayer:用于释放一个播放器的资源。
    • trackRecorder:用于追踪一个录音器的引用,并返回一个唯一的录音器 ID。
    • recorderEvent:用于通知一个录音器的状态变化,如开始、暂停、停止等。
    • releaseRecorder:用于释放一个录音器的资源。
    • playerSessionId:用于更新一个播放器的会话 ID。
    • portEvent:用于通知一个端口的事件,如连接、断开、配置等。
  • 使用 IMPLEMENT_META_INTERFACE 宏来注册 AudioManager 接口的名称和描述。
 explicit BpAudioManager(const sp<IBinder>& impl)
        : BpInterface<IAudioManager>(impl)
    {
    }

这是是一个 C++ 语言的构造函数,用于创建一个 BpAudioManager 对象。这个构造函数的参数是一个 IBinder 类型的智能指针,用于指向 Binder 通信的远程端。这个构造函数的作用是调用 BpInterface 类的构造函数,将 impl 作为参数传递,从而初始化 BpAudioManager 对象的基类成员变量。这个构造函数没有其他的操作,所以函数体为空。

virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
            audio_content_type_t content, const sp<IBinder>& player, audio_session_t sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32(1); // non-null PlayerIdCard parcelable
        // marshall PlayerIdCard data
        data.writeInt32((int32_t) playerType);
        //   write attributes of PlayerIdCard
        data.writeInt32((int32_t) usage);
        data.writeInt32((int32_t) content);
        data.writeInt32(0 /*source: none here, this is a player*/);
        data.writeInt32(0 /*flags*/);
        //   write attributes' tags
        data.writeInt32(1 /*FLATTEN_TAGS*/);
        data.writeString16(String16("")); // no tags
        //   write attributes' bundle
        data.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle
        //   write IPlayer
        data.writeStrongBinder(player);
        //   write session Id
        data.writeInt32((int32_t)sessionId);
        // get new PIId in reply
        const status_t res = remote()->transact(TRACK_PLAYER, data, &reply, 0);
        if (res != OK || reply.readExceptionCode() != 0) {
            ALOGE("trackPlayer() failed, piid is %d", PLAYER_PIID_INVALID);
            return PLAYER_PIID_INVALID;
        } else {
            const audio_unique_id_t piid = (audio_unique_id_t) reply.readInt32();
            ALOGV("trackPlayer() returned piid %d", piid);
            return piid;
        }
    }

这是一个 C++ 语言的虚函数,用于追踪一个播放器的信息,并返回一个唯一的播放器 ID。这个函数的参数是:

  • playerType:一个枚举类型,表示播放器的类型,如媒体播放器、声音池、硬件编解码器等。
  • usage:一个枚举类型,表示播放器的用途,如闹钟、游戏、通话等。
  • content:一个枚举类型,表示播放器的内容,如音乐、电影、语音等。
  • player:一个 IBinder 类型的智能指针,用于指向播放器的远程接口。
  • sessionId:一个整数类型,表示播放器的会话 ID,用于关联不同的音频流。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的 PlayerIdCard 对象不为空。
  • 调用 data.writeInt32() 方法,写入 playerType 参数,表示播放器的类型。
  • 调用 data.writeInt32() 方法,依次写入 usage 和 content 参数,表示播放器的用途和内容。
  • 调用 data.writeInt32() 方法,写入两个 0,表示播放器的源和标志为空。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的属性标签为 FLATTEN_TAGS。
  • 调用 data.writeString16() 方法,写入一个空字符串,表示没有属性标签。
  • 调用 data.writeInt32() 方法,写入一个整数 -1977,表示要发送的属性包为空。
  • 调用 data.writeStrongBinder() 方法,写入 player 参数,表示播放器的远程接口。
  • 调用 data.writeInt32() 方法,写入 sessionId 参数,表示播放器的会话 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 TRACK_PLAYER,表示要执行的操作是追踪播放器,以及 0,表示不需要阻塞等待返回。
  • 判断返回的状态是否为 OK,以及 reply 对象中是否有异常代码,如果有,则打印错误日志,并返回一个无效的播放器 ID。
  • 如果没有异常,则从 reply 对象中读取一个整数,作为新分配的播放器 ID,并打印日志,然后返回该 ID。

简而言之,这个函数是用于追踪一个播放器的信息,并返回一个唯一的播放器 ID 的 AudioManager 接口的虚函数。

virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
            audio_content_type_t content) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        data.writeInt32(1); // non-null AudioAttributes parcelable
        data.writeInt32((int32_t) usage);
        data.writeInt32((int32_t) content);
        data.writeInt32(0 /*source: none here, this is a player*/);
        data.writeInt32(0 /*flags*/);
        //   write attributes' tags
        data.writeInt32(1 /*FLATTEN_TAGS*/);
        data.writeString16(String16("")); // no tags
        //   write attributes' bundle
        data.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle
        return remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);
    }

这段代码是一个 C++ 语言的虚函数,用于更新一个播放器的用途和内容属性。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。
  • usage:一个枚举类型,表示播放器的用途,如闹钟、游戏、通话等。
  • content:一个枚举类型,表示播放器的内容,如音乐、电影、语音等。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入 piid 参数,表示播放器的唯一 ID。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的 AudioAttributes 对象不为空。
  • 调用 data.writeInt32() 方法,依次写入 usage 和 content 参数,表示播放器的用途和内容属性。
  • 调用 data.writeInt32() 方法,写入两个 0,表示播放器的源和标志为空。
  • 调用 data.writeInt32() 方法,写入一个整数 1,表示要发送的属性标签为 FLATTEN_TAGS。
  • 调用 data.writeString16() 方法,写入一个空字符串,表示没有属性标签。
  • 调用 data.writeInt32() 方法,写入一个整数 -1977,表示要发送的属性包为空。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PLAYER_ATTRIBUTES,表示要执行的操作是更新播放器的属性,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于更新一个播放器的用途和内容属性的 AudioManager 接口的虚函数。

virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
            audio_port_handle_t eventId) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        data.writeInt32((int32_t) event);
        data.writeInt32((int32_t) eventId);
        return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
    }

这段代码是一个 C++ 语言的虚函数,用于通知一个播放器的状态变化。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。
  • event:一个枚举类型,表示播放器的状态,如开始、暂停、停止等。
  • eventId:一个整数类型,表示播放器的事件 ID,用于区分不同的事件。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 piid、event 和 eventId 参数,表示播放器的 ID、状态和事件 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PLAYER_EVENT,表示要执行的操作是通知播放器的状态变化,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于通知一个播放器的状态变化的 AudioManager 接口的虚函数。

virtual status_t releasePlayer(audio_unique_id_t piid) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        return remote()->transact(RELEASE_PLAYER, data, &reply, IBinder::FLAG_ONEWAY);
    }

这是一个 C++ 语言的虚函数,用于释放一个播放器的资源。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入 piid 参数,表示播放器的唯一 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 RELEASE_PLAYER,表示要执行的操作是释放播放器的资源,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于释放一个播放器的资源的 AudioManager 接口的虚函数。

 virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeStrongBinder(recorder);
        // get new RIId in reply
        const status_t res = remote()->transact(TRACK_RECORDER, data, &reply, 0);
        if (res != OK || reply.readExceptionCode() != 0) {
            ALOGE("trackRecorder() failed, riid is %d", RECORD_RIID_INVALID);
            return RECORD_RIID_INVALID;
        } else {
            const audio_unique_id_t riid = (audio_unique_id_t) reply.readInt32();
            ALOGV("trackRecorder() returned riid %d", riid);
            return riid;
        }
    }

这是一个 C++ 语言的虚函数,用于追踪一个录音器的引用,并返回一个唯一的录音器 ID。这个函数的参数是:

  • recorder:一个 IBinder 类型的智能指针,用于指向录音器的远程接口。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeStrongBinder() 方法,写入 recorder 参数,表示录音器的远程接口。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 TRACK_RECORDER,表示要执行的操作是追踪录音器,以及 0,表示不需要阻塞等待返回。
  • 判断返回的状态是否为 OK,以及 reply 对象中是否有异常代码,如果有,则打印错误日志,并返回一个无效的录音器 ID。
  • 如果没有异常,则从 reply 对象中读取一个整数,作为新分配的录音器 ID,并打印日志,然后返回该 ID。

简而言之,这个函数是用于追踪一个录音器的引用,并返回一个唯一的录音器 ID 的 AudioManager 接口的虚函数。

virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) riid);
        data.writeInt32((int32_t) event);
        return remote()->transact(RECORDER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
    }

这段代码是一个 C++ 语言的虚函数,用于通知一个录音器的状态变化。这个函数的参数是:

  • riid:一个整数类型,表示录音器的唯一 ID。
  • event:一个枚举类型,表示录音器的状态,如开始、暂停、停止等。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 riid 和 event 参数,表示录音器的 ID 和状态。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 RECORDER_EVENT,表示要执行的操作是通知录音器的状态变化,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于通知一个录音器的状态变化的 AudioManager 接口的虚函数。

   virtual status_t releaseRecorder(audio_unique_id_t riid) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) riid);
        return remote()->transact(RELEASE_RECORDER, data, &reply, IBinder::FLAG_ONEWAY);
    }

这是一个 C++ 语言的虚函数,用于释放一个录音器的资源。这个函数的参数是:

  • riid:一个整数类型,表示录音器的唯一 ID。
    这个函数的逻辑如下:
  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,写入 riid 参数,表示录音器的唯一 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 RELEASE_RECORDER,表示要执行的操作是释放录音器的资源,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。
    简而言之,这个函数是用于释放一个录音器的资源的 AudioManager 接口的虚函数
virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) piid);
        data.writeInt32((int32_t) sessionId);
        return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);
    }

这段代码是一个 C++ 语言的虚函数,用于更新一个播放器的会话 ID。这个函数的参数是:

  • piid:一个整数类型,表示播放器的唯一 ID。
  • sessionId:一个整数类型,表示播放器的会话 ID,用于关联不同的音频流。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 piid 和 sessionId 参数,表示播放器的 ID 和会话 ID。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PLAYER_SESSION_ID,表示要执行的操作是更新播放器的会话 ID,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。
    简而言之,这个函数是用于更新一个播放器的会话 ID 的 AudioManager 接口的虚函数。
 virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
            const std::unique_ptr<os::PersistableBundle>& extras) {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
        data.writeInt32((int32_t) portId);
        data.writeInt32((int32_t) event);
        // TODO: replace PersistableBundle with own struct
        data.writeNullableParcelable(extras);
        return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
    }

这段代码是一个 C++ 语言的虚函数,用于通知一个端口的事件。这个函数的参数是:

  • portId:一个整数类型,表示端口的唯一 ID。
  • event:一个枚举类型,表示端口的事件,如连接、断开、配置等。
  • extras:一个智能指针,指向一个 os::PersistableBundle 类型的对象,用于存储额外的信息。

这个函数的逻辑如下:

  • 创建一个 Parcel 对象 data,用于存储要发送的数据。
  • 创建一个 Parcel 对象 reply,用于接收返回的数据。
  • 调用 data.writeInterfaceToken() 方法,写入 AudioManager 接口的标识符,用于验证 Binder 通信的有效性。
  • 调用 data.writeInt32() 方法,依次写入 portId 和 event 参数,表示端口的 ID 和事件。
  • 调用 data.writeNullableParcelable() 方法,写入 extras 参数,表示额外的信息。如果 extras 为空,则写入一个空的 Parcelable 对象。
  • 调用 remote()->transact() 方法,将 data 对象发送给远程端,并将返回的数据存储在 reply 对象中。传递的参数是 PORT_EVENT,表示要执行的操作是通知端口的事件,以及 IBinder::FLAG_ONEWAY,表示不需要等待返回的结果。

简而言之,这个函数是用于通知一个端口的事件的 AudioManager 接口的虚函数。

IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");

这是是一个 C++ 语言的宏定义,用于实现 AudioManager 接口的两个方法,分别是:

  • getInterfaceDescriptor():用于返回 AudioManager 接口的标识符,即 “android.media.IAudioService”。
  • asInterface():用于将一个 IBinder 类型的对象转换为一个 IAudioManager 类型的对象,如果该对象是本地对象并且实现了 AudioManager 接口,则返回其实际对象,否则返回一个代理对象。

这个宏定义的参数是:

  • INTERFACE:表示接口的名称,即 AudioManager。
  • NAME:表示接口的标识符,即 “android.media.IAudioService”。

简而言之,这个宏定义是用于实现 AudioManager 接口的两个方法的简化写法。
这里asInterface()在这里面可以看到
https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/libs/binder/include/binder/IInterface.h;drc=84410fbd18148d422d3581201c67f1a72a6658c4;l=115?hl=zh-cn
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1476207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot实现线上阅读系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现线上阅读系统演示 摘要 随着社会发展速度的愈来愈快&#xff0c;以及社会压力变化的越来越快速&#xff0c;致使很多人采取各种不同的方法进行解压。大多数人的稀释压力的方法&#xff0c;是捧一本书籍&#xff0c;心情地让自己沉浸在情节里面&#xff0c;以…

【Linux】TCP应用与相关API守护进程

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 相关使用接口2. 代码实现2.1 日志组件2.2 Server端2.3 Client端2.3 bug解决 3. 守…

动态规划|【斐波那契数列模型 】|面试题08.01三步问题

目录 题目 思路 普通思路 动态规划思路 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 代码 空间优化 题目 题目链接 面试题 08.01. 三步问题https://leetcode.cn/problems/three-steps-problem-lcci/ 三步问题。有个小孩正在上楼梯&#xff0c;楼梯有n…

【JAVA日志】关于日志系统的架构讨论

目录 1.日志系统概述 2.环境搭建 3.应用如何推日志到MQ 4.logstash如何去MQ中取日志 5.如何兼顾分布式链路追踪 1.日志系统概述 关于日志系统&#xff0c;其要支撑的核心能力无非是日志的存储以及查看&#xff0c;最好的查看方式当然是实现可视化。目前市面上有成熟的解决…

今天面试了一个工作4年的测试工程师,一问连自动化基础都不知道,还反过来怼我..

金三银四黄金期&#xff0c;我们公司也开始大量招人了&#xff0c;我这次是公司招聘的面试官之一&#xff0c;主要负责一些技术上的考核&#xff0c;这段时间还真让我碰到了不少奇葩求职者 昨天公司的HR小席刚跟我吐槽&#xff1a;这几个星期没有哪天不加班的&#xff01;各种…

LTD264次升级 | 对接AsiaPay • 人民币买外币商品 •知识付费订单可关闭 • 专栏支持VIP免支付购买

​ 1、对接AsiaPay第三方支付平台&#xff0c;支持人民币买外币商品&#xff1b; 2、知识付费购买优化 3、账号绑定的微信号可解除绑定&#xff1b; 4、其他已知问题修复与优化&#xff1b; 01 商城 1) 新增海外跨境支付系统AsiaPay 在本次升级中&#xff0c;商城支付系统新增…

【面试题】在浏览器地址栏输入URL后会发生什么

1. 地址栏输入后的本地操作 当我们在浏览器的地址栏中&#xff0c;输入xxx内容后&#xff0c;浏览器的进程首先会判断输入的内容&#xff1a; 如果是普通的字符&#xff0c;那浏览器会使用默认的搜索引擎去对于输入的xxx生成URL。如若输入的是网址&#xff0c;那浏览器会拼接…

StarRocks实战——滴滴OLAP的技术实践与发展方向

原文大佬的这篇StarRocks实践文章整体写的很深入&#xff0c;介绍了StarRocks数仓架构设计、物化视图加速实时看板、全局字典精确去重等内容&#xff0c;这里直接摘抄下来用作学习和知识沉淀。 目录 一、背景介绍 1.1 滴滴OLAP的发展历程 1.2 OLAP引擎存在的痛点 1.2.1 运维…

在 Jupyter Notebook 中查看所使用的 Python 版本和 Python 解释器路径

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 我们在做 Python 开发时&#xff0c;有时在我们的服务器上可能安装了多个 Python 版本。 使用 conda info --envs 可以列出所有的 conda 环境。当在 Linux 服务器上使用 which python 命令时&#xff0…

【数据结构与算法】回溯法解题20240229

【数据结构与算法】回溯法解题20240229 一、46. 全排列1、以[1,2,3]为例&#xff0c;抽象成树形结构2、回溯三部曲 二、LCR 084. 全排列 II1、以[1,1,2]为例&#xff0c;抽象成树形结构 三、面试题 08.07. 无重复字符串的排列组合四、面试题 08.08. 有重复字符串的排列组合 一、…

代码随想录-力扣刷题-总结笔记01

代码随想录&#xff1a;代码随想录力扣&#xff1a;力扣 (LeetCode) 全球极客挚爱的技术成长平台 目录 01、代码随想录 00、琐碎知识点 01、数组 02、链表 03、哈希表 04、字符串 05、双指针法 06、栈与队列 6.1、栈 6.2、队列 07、二叉树 7.1、前中后序-递归遍历 …

UTONMOS元宇宙游戏发展趋势是什么?

UTONMOS元宇宙游戏的发展趋势包括以下几个方面&#xff1a; 更加真实的体验&#xff1a;随着技术的进步&#xff0c;UTONMOS元宇宙游戏将提供更加逼真的视觉、听觉和触觉体验&#xff0c;让玩家更加身临其境。 社交互动&#xff1a;UTONMOS元宇宙游戏将越来越注重社交互动&am…

Premiere水墨风格婚纱照片婚礼视频模板|PR婚庆后期剪辑模板

时尚大气水墨风格婚纱照片展示&#xff0c;婚礼视频制作PR模板&#xff0c;婚庆后期剪辑模板MOGRT。 主要特点&#xff1a;高清&#xff08;19201080&#xff09;分辨率/30帧/秒&#xff0c;Premiere Pro 2022或更高版本软件&#xff0c;易于定制&#xff0c;持续时间00:50秒&a…

猫头虎分享已解决Bug || 虚拟网络问题(Virtual Network Issue):VirtualNetworkError, VNetFailure

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

IPD(集成产品开发)—核心思想

企业发展到一定阶段就会遇到管理瓶颈&#xff0c;IPD流程是一种高度结构化的产品开发流程&#xff0c;它集成了业界很多优秀的产品开发方法论&#xff0c;像搭积木一样的组合成一种非常有效的流程。如果我们能根据企业的规模和行业特点&#xff0c;对全流程的IPD进行合适的裁剪…

陪诊小程序:温暖您的就医之路,让关怀触手可及

随着社会的进步和科技的发展&#xff0c;人们对于医疗健康的需求日益增长。然而&#xff0c;在繁忙的生活节奏中&#xff0c;许多人在面对就医时却面临着无人陪伴的困境。为了解决这一问题&#xff0c;陪诊小程序应运而生。 陪诊小程序是一种便捷、高效、人性化的医疗服务应用…

Python正则表达式:从基础到高级应用的全面总结与实战【第103篇—JSON模块】

Python正则表达式&#xff1a;从基础到高级应用的全面总结与实战 正则表达式是一种强大的文本匹配和处理工具&#xff0c;广泛应用于文本处理、数据抽取、表单验证等领域。本文将从正则表达式的基础知识出发&#xff0c;逐步深入&#xff0c;最终结合代码实战&#xff0c;带你…

【代码随想录python笔记整理】第十四课 · 链表的基础操作 2

前言:本笔记仅仅只是对内容的整理和自行消化&#xff0c;并不是完整内容&#xff0c;如有侵权&#xff0c;联系立删。 一、分析题目要求 在前面一课中&#xff0c;我们学习了链表的创建以及新元素的插入&#xff0c;并且我们学会了打印链表中的元素。这节课我们依托上节课的基础…

DataGrip 2023:让数据库开发变得更简单、更高效 mac/win版

JetBrains DataGrip 2023是一款功能强大的数据库IDE&#xff0c;专为数据库开发和管理而设计。通过DataGrip&#xff0c;您可以连接到各种关系型数据库管理系统(RDBMS)&#xff0c;并使用其提供的一组工具来查询、管理、编辑和开发数据库。 DataGrip 2023 软件获取 DataGrip …

2024深度学习主流框架对比

tensorFlow 是最受欢迎和广泛使用的深度学习框架之一&#xff0c;目前在github的start数为181k。 TensorFlow是一个由Google Brain团队开发的开源深度学习框架。它允许开发者创建多种机器学习模型&#xff0c;包括卷积神经网络、循环神经网络和深度神经网络等&#xff0c;该框架…