Apple Media Service

目录

AMS entities:

(1)Player : 

(2)Queue :  

(3)Track : 

AMS characteristics:

(1)The Remote Command characteristic

(2)The Entity Update characteristic:

(3)The Entity Attribute characteristic: 

AMS error codes

RTL8762D官方例程使用AMS问题:(暂未搞明白)

 问题1:

问题2:

(1)ams_handle_msg

(2)ams_send_msg_to_app

(3)ams_send_msg

(4)ams_send_msg_to_app 和 ams_send_msg 的调用过程:


AMS

MR: watch

MS:phone

AMS entities:

AMS定义了3个不同的实体entities,每个entities具有各自不同的属性attributes

(1)Player : 

The currently active media app。
该实体的attributes包括其名称、播放状态和播放音量等值。

(2)Queue :  

The currently loaded playback queue,当前加载的播放队列。
该实体的attributes包括其大小、播放/重复模式等值。

(3)Track : 

The currently loaded track,当前加载的曲目。
此实体的attributes包括艺术家、标题和持续时间等值。

The MR may want to know only the value of a specific subset of entity/attribute pairs. For each entity, the MR must indicate once to the MS which entity/attribute pairs, if any, it wants to monitor. The MS will then notify the MR of the initial, current values of all registered entity/attribute pairs, and subsequently notify the MR whenever these values change.

MR可能只想知道实体/属性对(entity/attribute pairs)的特定子集的值。对于每个entity,MR必须向MS指示一次要监控的entity/attribute pairs(如果有)。然后,MS将通知MR所有已注册entity/attribute pairs的初始、当前值,并随后在这些值发生变化时通知MR。

eg:Typical operation of the Media Service

AMS characteristics:

三种基本属性:Remote Commond , Entity Update , Entity Attribute

(1)The Remote Command characteristic

是指MR可以发送远程命令以影响MS的播放状态的特性,例如播放、下一曲目、增加音量等。

该特性还用于向MR报告MS支持的命令列表。

调用函数:

//* @brief  Used by application, to send remote command.
bool ams_write_remote_cmd(uint8_t conn_id, T_AMS_REMOTE_CMD_ID cmd_id);

(2)The Entity Update characteristic:

是MR可以告知MS其感兴趣的entity/attribute pairs的特性,并在这些entity/attribute pairs发生变化时被告知。

例如,可以通知MR当前加载曲目的标题,或活动媒体应用程序的名称。

By default, the MR does not receive any information about any attribute of any entity. In order to receive this data, an MR first needs to subscribe for GATT notifications on the Entity Update characteristic. Then, the MR writes commands to the Entity Update characteristic to inform the MS which entity/attribute pair values it wants to know.

默认情况下,MR不会收到任何实体的任何属性的任何信息。

为了接收这些数据,MR首先需要订阅关于实体更新特性的GATT通知。

调用函数:

//* @brief  Used by application, to set the notifcation flag of entity update.
bool ams_subscribe_entity_upd(uint8_t conn_id, bool subscribe);

然后,MR将命令写入Entity Update characteristic,以通知MS它想要知道哪些实体/属性对值。

MR发送的Entity Update命令的格式如下:

Byte

Value

1

EntityID

2

AttributeID 1

3

AttributeID 2

...

other sAttributeID

调用函数:

//@brief  Used by application, to write the Entity Update characteristic.
bool ams_write_entity_upd_cmd(uint8_t conn_id, uint8_t *p_value, uint8_t value_len);

如果写入成功,MR将立即开始以GATT通知的形式获取其注册到monitor的entity/attribute pairs的值。(in the form of GATT notifications for the same characteristic.)

The format of GATT notifications delivered by the MS is shown below:

Byte

Value

1

EntityID

2

AttributeID

3

EntityUpdateFlags

4...

Value

(3)The Entity Attribute characteristic: 

MR可以检索属性的扩展值。

理想情况下,仅当entity/attribute pairs的值在相应的实体更新通知中被标记为截断,且MR希望显示更多相关值时,才应使用此特征。

要检索特定entity/attribute pairs的完整值,MR必须首先通过写入Entity Attribute characteristic来发送命令。

调用函数:

//* @brief  Used by application, to write the Entity Attribute characteristic.
bool ams_write_entity_attr(uint8_t conn_id, T_AMS_ENTITY_ATTR entity_attr);

如果写入成功,则相应entity/attribute pairs的值被加载为Entity Attribute characteristic的值,并且MR可以方便地读取该值。

//* @brief  Used by application, to read the Entity Attribute characteristic.
bool ams_read_entity_attr(uint8_t conn_id, T_AMS_ENTITY_ATTR entity_attr);

AMS error codes

当写入任何characteristic或读取Entity Attribute时,MR可能会收到以下AMS特定错误代码:

  • Invalid State (0xA0): The MR has not properly set up the AMS, e.g. it wrote to the Entity Update or Entity Attribute characteristic without subscribing to GATT notifications for the Entity Update characteristic.

  • Invalid Command (0xA1): The command was improperly formatted.

  • Absent Attribute (0xA2): The corresponding attribute is empty.

RTL8762D官方例程使用AMS问题:(暂未搞明白)

 问题1:

ams_client_cb函数在被调用时,哪里给它赋值的?

void ams_init(uint8_t link_num)  // ams.c
{
    AMSDataBlockInit();
    ams_queue_init();
    ams_client = ams_add_client(ams_client_cb, link_num);
}

 T_CLIENT_ID ams_add_client(P_FUN_GENERAL_APP_CB app_cb, uint8_t link_num)  //ams_client.c
{
    if (false == client_register_spec_client_cb(&ams_client_id, &ams_cbs))
    {}
    ams_client_cb = app_cb;
}

const T_FUN_CLIENT_CBS ams_cbs =
{
    ams_client_cb_discover_state,   //!< Discovery State callback function pointer
    ams_client_cb_discover_result,  //!< Discovery result callback function pointer
    ams_client_cb_read_result,      //!< Read response callback function pointer
    ams_client_cb_write_result,     //!< Write result callback function pointer
    ams_client_cb_notify_ind,       //!< Notify Indicate callback function pointer
    ams_client_cb_disc              //!< Link disconnection callback function pointer
}; 

问题2:

三个函数---ams_handle_msg, ams_send_msg, ams_send_msg_to_app

(1)ams_handle_msg

函数原型如下:

void ams_handle_msg(T_IO_MSG *p_io_msg)
{
    uint8_t conn_id = p_io_msg->u.param;
    T_AMS_MSG ams_msg;
    uint32_t msg_num;
    os_msg_queue_peek(ams_queue_handle, &msg_num);
    if (os_msg_recv(ams_queue_handle, &ams_msg, 0) == false)
    {
        APP_PRINT_INFO1("ams_handle_msg: conn_id 0x%x os_msg_recv null(no msg in ams queue)", conn_id);
        return;
    }
    if (ams_msg.type == AMS_MSG_TYPE_REMOTE_CMD)
    {
        ams_write_remote_cmd(conn_id, ams_msg.remote_cmd_id);
    }
    else if (ams_msg.type == AMS_MSG_ENTITY_UPDATE_CMD)
    {
        ams_write_entity_upd_cmd(conn_id, ams_msg.param, ams_msg.param_len);
    }
}

是在上层的wristband_handle_io_message();中,当msg_type = IO_MSG_TYPE_AMS时被调用。整个过程如下所示:

    while (true)
    {
        if (os_msg_recv(evt_queue_handle, &event, 0xFFFFFFFF) == true)
        {
            if (event == EVENT_IO_TO_APP)
            {
                T_IO_MSG io_msg;
                if (os_msg_recv(io_queue_handle, &io_msg, 0) == true)
                {
                    app_handle_io_msg(io_msg);
                }
            }
            else
            {
                gap_handle_msg(event);
            }
        }
    }

当 event_type = EVENT_IO_TO_APP 时,调用app_handle_io_msg(io_msg); 

当 io_msg_type = IO_MSG_TYPE_WRISTBNAD 时,调用wristband_handle_io_message(&io_msg); 

当 p_wristband_msg->subtype = IO_MSG_TYPE_AMS 时,调用ams_handle_msg(p_wristband_msg); 
 

问题:我理解的是,当对应事件发生时,并且收到消息,如果该消息是ams消息,则进入ams_handle_msg() 进行处理??

(2)ams_send_msg_to_app

函数原型如下:

static void ams_send_msg_to_app(uint8_t conn_id)
{
    T_IO_MSG io_msg;
    uint8_t event = EVENT_IO_TO_APP;
    io_msg.type = IO_MSG_TYPE_WRISTBNAD;
    io_msg.subtype = IO_MSG_TYPE_AMS;
    io_msg.u.param = conn_id;

    if (os_msg_send(io_queue_handle, &io_msg, 0) == false)
    {
        GAP_PRINT_ERROR0("ams_send_msg_to_app fail1");
    }
    else if (os_msg_send(evt_queue_handle, &event, 0) == false)
    {
        GAP_PRINT_ERROR0("ams_send_msg_to_app fail2");
    }
}

(3)ams_send_msg

函数原型如下:

void ams_send_msg(uint8_t conn_id, T_AMS_MSG *ams_msg)
{
    uint32_t msg_num;
    os_msg_queue_peek(ams_queue_handle, &msg_num);
    if (msg_num == 0){
        switch (ams_msg->type)
        {
        case AMS_MSG_TYPE_REMOTE_CMD:
            {
                if (ams_write_remote_cmd(conn_id, ams_msg->remote_cmd_id) == true)
                    return;
            }
            break;
        case AMS_MSG_ENTITY_UPDATE_CMD:
            {
                if (ams_write_entity_upd_cmd(conn_id, ams_msg->param, ams_msg->param_len) == true)
                    return;
            }
            break;
        default:
            break;
        }
    }
    if (os_msg_send(ams_queue_handle, ams_msg, 0) == false){
        APP_PRINT_ERROR0("ams send msg: discard, ams msg queue is full");
    }
}

(4)ams_send_msg_to_app 和 ams_send_msg 的调用过程:

T_APP_RESULT ams_client_cb(T_CLIENT_ID client_id, uint8_t conn_id, void *p_data)
{
    T_APP_RESULT  result = APP_RESULT_SUCCESS;
    T_AMS_CB_DATA *p_cb_data = (T_AMS_CB_DATA *)p_data;

    switch (p_cb_data->cb_type)
    {
    case AMS_CLIENT_CB_TYPE_WRITE_RESULT:
        {
            switch (p_cb_data->cb_content.write_result.type)
            {
            case AMS_WRITE_REMOTE_CMD_NOTIFY_ENABLE:
                APP_PRINT_INFO0("AMS_WRITE_REMOTE_CMD_NOTIFY_ENABLE");
                ams_subscribe_entity_upd(conn_id, true);
                break;

            case AMS_WRITE_REMOTE_CMD_NOTIFY_DISABLE:
                APP_PRINT_INFO0("AMS_WRITE_REMOTE_CMD_NOTIFY_DISABLE");
                break;

            case AMS_WRITE_ENTITY_UPD_NOTIFY_ENABLE:
                {
                    APP_PRINT_INFO0("AMS_WRITE_ENTITY_UPD_NOTIFY_ENABLE");
                    T_AMS_MSG ams_msg;
                    static uint8_t cmd[3];
                    cmd[0] = ENTITY_ID_TRACK;
                    cmd[1] = TRACK_ATTR_ID_ARTIST;
                    cmd[2] = TRACK_ATTR_ID_TITLE;
                    ams_msg.type = AMS_MSG_ENTITY_UPDATE_CMD;
                    ams_msg.param = cmd;
                    ams_msg.param_len = 3;
                    ams_send_msg(conn_id, &ams_msg);
                }
                break;

            case AMS_WRITE_ENTITY_UPD_NOTIFY_DISABLE:
                APP_PRINT_INFO0("AMS_WRITE_ENTITY_UPD_NOTIFY_DISABLE");
                break;

            case AMS_WRITE_ENTITY_ATTR_VALUE:
                APP_PRINT_INFO0("AMS_WRITE_ENTITY_ATTR_VALUE");
                break;

            case AMS_WRITE_REMOTE_CMD_VALUE:
                {
                    APP_PRINT_INFO0("AMS_WRITE_REMOTE_CMD_VALUE");
                    uint32_t msg_num;
                    os_msg_queue_peek(ams_queue_handle, &msg_num);
                    if (msg_num)
                    {
                        ams_send_msg_to_app(conn_id);
                    }
                }
                break;
            default:
                break;
            }
        }
        break;
    }
}

另外,当 case AMS_WRITE_REMOTE_CMD_NOTIFY_ENABLE: 时,为什么调用的是ams_subscribe_entity_upd 函数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值