diff options
Diffstat (limited to 'stack/avrc/avrc_bld_tg.c')
-rw-r--r-- | stack/avrc/avrc_bld_tg.c | 1547 |
1 files changed, 1547 insertions, 0 deletions
diff --git a/stack/avrc/avrc_bld_tg.c b/stack/avrc/avrc_bld_tg.c new file mode 100644 index 0000000..667499e --- /dev/null +++ b/stack/avrc/avrc_bld_tg.c @@ -0,0 +1,1547 @@ +/***************************************************************************** +** +** Name: avrc_bld_tg.c +** +** Description:Interface to AVRCP build message functions for the Target Role +** +** Copyright (c) 2008-2008, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#include <string.h> + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if (AVRC_METADATA_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avrc_bld_get_capability_rsp +** +** Description This function builds the Get Capability response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len = 0; + UINT8 xx; + UINT32 *p_company_id; + UINT8 *p_event_id; + tAVRC_STS status = AVRC_STS_NO_ERROR; + + if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) + { + AVRC_TRACE_ERROR1("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp); + status = AVRC_STS_BAD_PARAM; + return status; + } + + AVRC_TRACE_API0("avrc_bld_get_capability_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id); + p_count = p_data; + + if (len == 0) + { + *p_count = p_rsp->count; + p_data++; + len = 2; /* move past the capability_id and count */ + } + else + { + p_data = p_start + p_pkt->len; + *p_count += p_rsp->count; + } + + if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) + { + p_company_id = p_rsp->param.company_id; + for (xx=0; xx< p_rsp->count; xx++) + { + UINT24_TO_BE_STREAM(p_data, p_company_id[xx]); + } + len += p_rsp->count * 3; + } + else + { + p_event_id = p_rsp->param.event_id; + *p_count = 0; + for (xx=0; xx< p_rsp->count; xx++) + { + if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx])) + { + (*p_count)++; + UINT8_TO_BE_STREAM(p_data, p_event_id[xx]); + } + } + len += (*p_count); + } + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + status = AVRC_STS_NO_ERROR; + + return status; +} + +/******************************************************************************* +** +** Function avrc_bld_list_app_settings_attr_rsp +** +** Description This function builds the List Application Settings Attribute +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_num; + UINT16 len = 0; + UINT8 xx; + + AVRC_TRACE_API0("avrc_bld_list_app_settings_attr_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data; + if (len == 0) + { + /* first time initialize the attribute count */ + *p_num = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xx<p_rsp->num_attr; xx++) + { + if(AVRC_IsValidPlayerAttr(p_rsp->attrs[xx])) + { + (*p_num)++; + UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]); + } + } + + len = *p_num + 1; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_list_app_settings_values_rsp +** +** Description This function builds the List Application Setting Values +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_num; + UINT8 xx; + UINT16 len; + + AVRC_TRACE_API0("avrc_bld_list_app_settings_values_rsp"); + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + /* get the existing length, if any, and also the num attributes */ + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data; + /* first time initialize the attribute count */ + if (len == 0) + { + *p_num = p_rsp->num_val; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + *p_num += p_rsp->num_val; + } + + + for (xx=0; xx<p_rsp->num_val; xx++) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]); + } + + len = *p_num + 1; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_get_cur_app_setting_value_rsp +** +** Description This function builds the Get Current Application Setting Value +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len; + UINT8 xx; + + if (!p_rsp->p_vals) + { + AVRC_TRACE_ERROR0("avrc_bld_get_cur_app_setting_value_rsp NULL parameter"); + return AVRC_STS_BAD_PARAM; + } + + AVRC_TRACE_API0("avrc_bld_get_cur_app_setting_value_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + p_count = p_data; + if (len == 0) + { + /* first time initialize the attribute count */ + *p_count = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xx<p_rsp->num_val; xx++) + { + if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id, p_rsp->p_vals[xx].attr_val)) + { + (*p_count)++; + UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id); + UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val); + } + } + len = ((*p_count) << 1) + 1; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_set_app_setting_value_rsp +** +** Description This function builds the Set Application Setting Value +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_set_app_setting_value_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + /* nothing to be added. */ + AVRC_TRACE_API0("avrc_bld_set_app_setting_value_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_app_setting_text_rsp +** +** Description This function builds the Get Application Settings Attribute Text +** or Get Application Settings Value Text response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len, len_left; + UINT8 xx; + tAVRC_STS sts = AVRC_STS_NO_ERROR; + UINT8 num_added = 0; + + if (!p_rsp->p_attrs) + { + AVRC_TRACE_ERROR0("avrc_bld_app_setting_text_rsp NULL parameter"); + return AVRC_STS_BAD_PARAM; + } + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE - p_pkt->offset - p_pkt->len; + + BE_STREAM_TO_UINT16(len, p_data); + p_count = p_data; + + if (len == 0) + { + *p_count = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xx<p_rsp->num_attr; xx++) + { + if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) + { + AVRC_TRACE_ERROR3("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)", + xx, p_rsp->p_attrs[xx].str_len, len_left); + p_rsp->num_attr = num_added; + sts = AVRC_STS_INTERNAL_ERR; + break; + } + if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str ) + { + AVRC_TRACE_ERROR1("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx); + continue; + } + UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id); + UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len); + ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str, p_rsp->p_attrs[xx].str_len); + (*p_count)++; + num_added++; + } + len = p_data - p_count; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return sts; +} + +/******************************************************************************* +** +** Function avrc_bld_get_app_setting_attr_text_rsp +** +** Description This function builds the Get Application Setting Attribute Text +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt) +{ + AVRC_TRACE_API0("avrc_bld_get_app_setting_attr_text_rsp"); + return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt); +} + +/******************************************************************************* +** +** Function avrc_bld_get_app_setting_value_text_rsp +** +** Description This function builds the Get Application Setting Value Text +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt) +{ + AVRC_TRACE_API0("avrc_bld_get_app_setting_value_text_rsp"); + return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt); +} + +/******************************************************************************* +** +** Function avrc_bld_inform_charset_rsp +** +** Description This function builds the Inform Displayable Character Set +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_inform_charset_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + /* nothing to be added. */ + AVRC_TRACE_API0("avrc_bld_inform_charset_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_inform_battery_status_rsp +** +** Description This function builds the Inform Battery Status +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_inform_battery_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + /* nothing to be added. */ + AVRC_TRACE_API0("avrc_bld_inform_battery_status_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_get_elem_attrs_rsp +** +** Description This function builds the Get Element Attributes +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len; + UINT8 xx; + + AVRC_TRACE_API0("avrc_bld_get_elem_attrs_rsp"); + if (!p_rsp->p_attrs) + { + AVRC_TRACE_ERROR0("avrc_bld_get_elem_attrs_rsp NULL parameter"); + return AVRC_STS_BAD_PARAM; + } + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + p_count = p_data; + + if (len == 0) + { + *p_count = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xx<p_rsp->num_attr; xx++) + { + if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id)) + { + AVRC_TRACE_ERROR2("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, p_rsp->p_attrs[xx].attr_id); + continue; + } + if ( !p_rsp->p_attrs[xx].name.p_str ) + { + p_rsp->p_attrs[xx].name.str_len = 0; + } + UINT32_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.str_len); + ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len); + (*p_count)++; + } + len = p_data - p_count; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_get_play_status_rsp +** +** Description This function builds the Get Play Status +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_play_status_rsp (tAVRC_GET_PLAY_STATUS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API0("avrc_bld_get_play_status_rsp"); + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; + + /* add fixed lenth - song len(4) + song position(4) + status(1) */ + UINT16_TO_BE_STREAM(p_data, 9); + UINT32_TO_BE_STREAM(p_data, p_rsp->song_len); + UINT32_TO_BE_STREAM(p_data, p_rsp->song_pos); + UINT8_TO_BE_STREAM(p_data, p_rsp->play_status); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_notify_rsp +** +** Description This function builds the Notification response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + UINT8 *p_len; + UINT16 len = 0; + UINT8 xx; + tAVRC_STS status = AVRC_STS_NO_ERROR; + + AVRC_TRACE_API0("avrc_bld_notify_rsp"); + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + p_data += 2; + + UINT8_TO_BE_STREAM(p_data, p_rsp->event_id); + switch (p_rsp->event_id) + { + case AVRC_EVT_PLAY_STATUS_CHANGE: /* 0x01 */ + /* p_rsp->param.play_status >= AVRC_PLAYSTATE_STOPPED is always TRUE */ + if ((p_rsp->param.play_status <= AVRC_PLAYSTATE_REV_SEEK) || + (p_rsp->param.play_status == AVRC_PLAYSTATE_ERROR) ) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status); + len = 2; + } + else + { + AVRC_TRACE_ERROR0("bad play state"); + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_EVT_TRACK_CHANGE: /* 0x02 */ + ARRAY_TO_BE_STREAM(p_data, p_rsp->param.track, AVRC_UID_SIZE); + len = (UINT8)(AVRC_UID_SIZE + 1); + break; + + case AVRC_EVT_TRACK_REACHED_END: /* 0x03 */ + case AVRC_EVT_TRACK_REACHED_START: /* 0x04 */ +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_EVT_NOW_PLAYING_CHANGE: /* 0x09 */ + case AVRC_EVT_AVAL_PLAYERS_CHANGE: /* 0x0a */ +#endif + len = 1; + break; + + case AVRC_EVT_PLAY_POS_CHANGED: /* 0x05 */ + UINT32_TO_BE_STREAM(p_data, p_rsp->param.play_pos); + len = 5; + break; + + case AVRC_EVT_BATTERY_STATUS_CHANGE: /* 0x06 */ + if (AVRC_IS_VALID_BATTERY_STATUS(p_rsp->param.battery_status)) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status); + len = 2; + } + else + { + AVRC_TRACE_ERROR0("bad battery status"); + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_EVT_SYSTEM_STATUS_CHANGE: /* 0x07 */ + if (AVRC_IS_VALID_SYSTEM_STATUS(p_rsp->param.system_status)) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status); + len = 2; + } + else + { + AVRC_TRACE_ERROR0("bad system status"); + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_EVT_APP_SETTING_CHANGE: /* 0x08 */ + if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS) + p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS; + + if (p_rsp->param.player_setting.num_attr > 0) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.num_attr); + len = 2; + for (xx=0; xx<p_rsp->param.player_setting.num_attr; xx++) + { + if (avrc_is_valid_player_attrib_value(p_rsp->param.player_setting.attr_id[xx], p_rsp->param.player_setting.attr_value[xx])) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_id[xx]); + UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_value[xx]); + } + else + { + AVRC_TRACE_ERROR0("bad player app seeting attribute or value"); + status = AVRC_STS_BAD_PARAM; + break; + } + len += 2; + } + } + else + status = AVRC_STS_BAD_PARAM; + break; + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_EVT_ADDR_PLAYER_CHANGE: /* 0x0b */ + UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.player_id); /* player_id */ + UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.uid_counter); /* uid counter */ + len = 5; + break; + + case AVRC_EVT_UIDS_CHANGE: /* 0x0c */ + UINT16_TO_BE_STREAM(p_data, p_rsp->param.uid_counter); /* uid counter */ + len = 3; + break; + + case AVRC_EVT_VOLUME_CHANGE: /* 0x0d */ + UINT8_TO_BE_STREAM(p_data, (UINT8)(p_rsp->param.volume&AVRC_MAX_VOLUME)); + len = 2; + break; +#endif + + default: + status = AVRC_STS_BAD_PARAM; + AVRC_TRACE_ERROR0("unknown event_id"); + } + + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return status; +} + +/******************************************************************************* +** +** Function avrc_bld_next_rsp +** +** Description This function builds the Request Continue or Abort +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_next_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + /* nothing to be added. */ + AVRC_TRACE_API0("avrc_bld_next_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_group_navigation_rsp +** +** Description This function builds the Group Navigation +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt) +{ + UINT8 *p_data; + + if (!AVRC_IS_VALID_GROUP(navi_id)) + { + AVRC_TRACE_ERROR1("avrc_bld_group_navigation_rsp bad navigation op id: %d", navi_id); + return AVRC_STS_BAD_PARAM; + } + + AVRC_TRACE_API0("avrc_bld_group_navigation_rsp"); + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + UINT16_TO_BE_STREAM(p_data, navi_id); + p_pkt->len = 2; + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_rejected_rsp +** +** Description This function builds the General Response response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt ) +{ + UINT8 *p_data, *p_start; +#if (AVCT_BROWSE_INCLUDED == TRUE) + UINT8 opcode = avrc_opcode_from_pdu(p_rsp->pdu); +#endif + + AVRC_TRACE_API2("avrc_bld_rejected_rsp: status=%d, pdu:x%x", p_rsp->status, p_rsp->pdu); + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; +#if (AVCT_BROWSE_INCLUDED == TRUE) + if (opcode == AVRC_OP_BROWSE) + { + p_data = p_start + 1; + if (avrc_opcode_from_pdu(*p_start) != AVRC_OP_BROWSE) + { + /* if the given opcode is not recognized as a browsing command opcode, use general reject command */ + *p_start = AVRC_PDU_GENERAL_REJECT; + } + } + else +#endif + { + p_data = p_start + 2; + } + AVRC_TRACE_DEBUG1("pdu:x%x", *p_start); + + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + p_pkt->len = p_data - p_start; + + return AVRC_STS_NO_ERROR; +} + + +/***************************************************************************** +** the following commands are introduced in AVRCP 1.4 +*****************************************************************************/ + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) +/******************************************************************************* +** +** Function avrc_bld_ctrl_status_rsp +** +** Description This function builds the responses with a UINT8 parameter. +** +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_ctrl_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; /* pdu + rsvd */ + + /* add fixed lenth - status(1) */ + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_set_addr_player_rsp +** +** Description This function builds the Set Addresses Player response. +** +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_set_addr_player_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + AVRC_TRACE_API0("avrc_bld_set_addr_player_rsp"); + return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt); +} + +/******************************************************************************* +** +** Function avrc_bld_set_abs_volume_rsp +** +** Description This function builds the Set Absolute Volume response. +** +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_set_abs_volume_rsp (tAVRC_SET_VOLUME_RSP *p_rsp, BT_HDR *p_pkt) +{ + p_rsp->status = (p_rsp->volume & AVRC_MAX_VOLUME); + AVRC_TRACE_API2("avrc_bld_set_abs_volume_rsp volume:%d, sts:%d", p_rsp->volume, p_rsp->status); + return avrc_bld_ctrl_status_rsp((tAVRC_RSP *)p_rsp, p_pkt); +} + + +/******************************************************************************* +** +** Function avrc_bld_set_browsed_player_rsp +** +** Description This function builds the Set Browsed Player response. +** +** This message goes through the Browsing channel and is +** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +#if (AVCT_BROWSE_INCLUDED == TRUE) +static tAVRC_STS avrc_bld_set_browsed_player_rsp (tAVRC_SET_BR_PLAYER_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + UINT8 *p_len, xx; + UINT16 len; + tAVRC_NAME *p_folders = p_rsp->p_folders; + UINT16 len_left; + UINT8 *p_num; + UINT16 mtu; + + AVRC_TRACE_API0("avrc_bld_set_browsed_player_rsp"); + /* make sure the given GKI buffer can accomodate this response */ + len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE; + p_data = (UINT8 *)(p_pkt + 1); + BE_STREAM_TO_UINT16 (mtu, p_data); + if (len_left > mtu) + { + len_left = mtu; + } + len_left = len_left - p_pkt->offset - p_pkt->len; + AVRC_TRACE_DEBUG2("len_left:%d, mtu:%d ", len_left, mtu); + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 1; /* pdu */ + + /* the existing len */ + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data + 9; + if (len == 0) + { + /* first time initialize the attribute count */ + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter); + UINT32_TO_BE_STREAM(p_data, p_rsp->num_items); + UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id); + *p_num = 0; + p_data++; + len = 10; + len_left -= 12; /* assuming that we would never use a GKI buffer that is too small for headers */ + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; (xx<p_rsp->folder_depth) && (len_left>(p_folders[xx].str_len + 2)); xx++) + { + (*p_num)++; + UINT16_TO_BE_STREAM(p_data, p_folders[xx].str_len); + ARRAY_TO_BE_STREAM(p_data, p_folders[xx].p_str, p_folders[xx].str_len); + len += (p_folders[xx].str_len + 2); + } + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} +#endif + + +/******************************************************************************* +** +** Function avrc_bld_get_folder_items_rsp +** +** Description This function builds the Get Folder Items response. +** The error code is returned in *p_status. +** AVRC_STS_INTERNAL_ERR means no GKI buffers. +** Try again later or with smaller item_count +** +** This message goes through the Browsing channel and is +** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** AVRC_STS_INTERNAL_ERR, if the given GKI buffer does not have enough room +** Otherwise, the error code. +** +*******************************************************************************/ +#if (AVCT_BROWSE_INCLUDED == TRUE) +static tAVRC_STS avrc_bld_get_folder_items_rsp (tAVRC_GET_ITEMS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + UINT8 *p_len, xx; + UINT16 len; + UINT16 item_len; + UINT8 *p_item_len, yy; + tAVRC_ITEM_PLAYER *p_player; + tAVRC_ITEM_FOLDER *p_folder; + tAVRC_ITEM_MEDIA *p_media; + tAVRC_ATTR_ENTRY *p_attr; + tAVRC_ITEM *p_item_list = p_rsp->p_item_list; + tAVRC_STS status = AVRC_STS_NO_ERROR; + UINT16 len_left; + UINT8 *p_num, *p; + UINT8 *p_item_start, *p_attr_count; + UINT16 item_count; + UINT16 mtu; + + AVRC_TRACE_API0("avrc_bld_get_folder_items_rsp"); + /* make sure the given GKI buffer can accomodate this response */ + len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE; + p = (UINT8 *)(p_pkt + 1); + BE_STREAM_TO_UINT16 (mtu, p); + if (len_left > mtu) + len_left = mtu; + len_left = len_left - p_pkt->offset - p_pkt->len; + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 1; /* pdu */ + + /* the existing len */ + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data + 3; + if (len == 0) + { + /* first time initialize the attribute count */ + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter); + item_count = 0; + p_data+= 2; + len = 5; + len_left -= 5; + } + else + { + p_data = p_start + p_pkt->len; + p = p_num; + BE_STREAM_TO_UINT16 (item_count, p); + } + AVRC_TRACE_DEBUG3("len:%d, len_left:%d, num:%d", len, len_left, item_count); + + /* min len required = item_type(1) + item len(2) + min item (14) = 17 */ + for (xx=0; xx<p_rsp->item_count && len_left > 17; xx++) + { + p_item_start = p_data; + UINT8_TO_BE_STREAM(p_data, p_item_list[xx].item_type); + /* variable item lenth - save the location to add length */ + p_item_len = p_data; + p_data += 2; + item_len = 0; + len_left -= 3; /* item_type(1) + item len(2) */ + switch (p_item_list[xx].item_type) + { + case AVRC_ITEM_PLAYER: + /* min len required: 2 + 1 + 4 + 1 + 16 + 2 + 2 = 30 + str_len */ + p_player = &p_item_list[xx].u.player; + item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12; + if ((len_left > item_len) && + p_player->name.p_str && + (p_player->major_type & AVRC_MJ_TYPE_INVALID) == 0 && + (p_player->sub_type & AVRC_SUB_TYPE_INVALID) == 0 && + (p_player->play_status <= AVRC_PLAYSTATE_REV_SEEK || p_player->play_status == AVRC_PLAYSTATE_ERROR) ) + { + UINT16_TO_BE_STREAM(p_data, p_player->player_id); + UINT8_TO_BE_STREAM(p_data, p_player->major_type); + UINT32_TO_BE_STREAM(p_data, p_player->sub_type); + UINT8_TO_BE_STREAM(p_data, p_player->play_status); + ARRAY_TO_BE_STREAM(p_data, p_player->features, AVRC_FEATURE_MASK_SIZE); + UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_player->name.str_len); + ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str, p_player->name.str_len); + } + else + { + p_data = p_item_start; + } + break; + + case AVRC_ITEM_FOLDER: + /* min len required: 8 + 1 + 1 + 2 + 2 = 14 + str_len */ + p_folder = &p_item_list[xx].u.folder; + item_len = AVRC_UID_SIZE + p_folder->name.str_len + 6; + if ((len_left > item_len) && + p_folder->name.p_str && + p_folder->type <= AVRC_FOLDER_TYPE_YEARS && + p_folder->playable <= TRUE) + { + ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE); + UINT8_TO_BE_STREAM(p_data, p_folder->type); + UINT8_TO_BE_STREAM(p_data, p_folder->playable); + UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len); + ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str, p_folder->name.str_len); + } + else + { + p_data = p_item_start; + } + break; + + case AVRC_ITEM_MEDIA: + /* min len required: 8 + 1 + 2 + 2 + 1 = 14 + str_len */ + p_media = &p_item_list[xx].u.media; + item_len = AVRC_UID_SIZE + p_media->name.str_len + 6; + if ((len_left > item_len) && + p_media->name.p_str && + p_media->type <= AVRC_MEDIA_TYPE_VIDEO) + { + ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE); + UINT8_TO_BE_STREAM(p_data, p_media->type); + UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_media->name.str_len); + ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str, p_media->name.str_len); + p_attr_count = p_data++; + *p_attr_count = 0; + len_left -= item_len; + if (p_media->attr_count>0) + { + p_attr = p_media->p_attr_list; + for (yy=0; yy<p_media->attr_count && len_left > 8; yy++) + { + if (p_attr[yy].name.p_str && + AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id) && + (len_left >= (p_attr[yy].name.str_len + 8)) ) + { + (*p_attr_count) ++; + UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id); + UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len); + ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str, p_attr[yy].name.str_len); + item_len += (p_attr[yy].name.str_len + 8); + len_left -= (p_attr[yy].name.str_len + 8); + } + } + } + } + else + { + p_data = p_item_start; + } + break; + } /* switch item_type */ + + if (p_item_start != p_data) + { + /* successfully added the item */ + item_count++; + /* fill in variable item lenth */ + UINT16_TO_BE_STREAM(p_item_len, item_len); + } + else + { + /* some item is not added properly - set an error status */ + if (len_left > item_len) + status = AVRC_STS_INTERNAL_ERR; + else + status = AVRC_STS_BAD_PARAM; + } + + len += item_len; + len += 3; /* the item_type(1) and item_len(2) */ + AVRC_TRACE_DEBUG4("len:%d, len_left:%d, num:%d, item_len:%d", len, len_left, item_count, item_len); + } /* for item_count */ + + UINT16_TO_BE_STREAM(p_num, item_count); + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + if (p_rsp->item_count != xx) + { + p_rsp->item_count = xx; + if (status == AVRC_STS_NO_ERROR) + status = AVRC_STS_INTERNAL_ERR; + } + + return status; +} +#endif + + +/******************************************************************************* +** +** Function avrc_bld_change_path_rsp +** +** Description This function builds the Change Path response. +** +** This message goes through the Browsing channel and is +** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +#if (AVCT_BROWSE_INCLUDED == TRUE) +static tAVRC_STS avrc_bld_change_path_rsp (tAVRC_CHG_PATH_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 1; /* pdu */ + /* add fixed lenth - status(1) + num_items(4) */ + UINT16_TO_BE_STREAM(p_data, 5); + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + UINT32_TO_BE_STREAM(p_data, p_rsp->num_items); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} +#endif + + +/******************************************************************************* +** +** Function avrc_bld_get_item_attrs_rsp +** +** Description This function builds the Get Item Attributes response. +** +** This message goes through the Browsing channel and is +** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** AVRC_STS_INTERNAL_ERR, if the given GKI buffer does not have enough room +** Otherwise, the error code. +** +*******************************************************************************/ +#if (AVCT_BROWSE_INCLUDED == TRUE) +static tAVRC_STS avrc_bld_get_item_attrs_rsp (tAVRC_GET_ATTRS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + UINT8 *p_len, xx; + UINT16 len, len_left; + UINT8 *p_num; + UINT16 mtu; + + AVRC_TRACE_API0("avrc_bld_get_item_attrs_rsp"); + /* calculate the GKI buffer size needed and validate the parameters */ + if (!p_rsp->p_attr_list) + { + AVRC_TRACE_ERROR0("NULL p_attr_list"); + return AVRC_STS_BAD_PARAM; + } + + /* check the length before adding the attr to the message */ + len = 2; + for (xx=0; xx<p_rsp->attr_count; xx++) + { + if(p_rsp->p_attr_list[xx].name.p_str == 0 || + !AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attr_list[xx].attr_id)) + { + AVRC_TRACE_ERROR2("[%d] NULL p_attr_list str or bad attr_id:%d", xx, p_rsp->p_attr_list[xx].attr_id); + return AVRC_STS_BAD_PARAM; + } + len += (p_rsp->p_attr_list[xx].name.str_len + 8); + } + len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE; + p_data = (UINT8 *)(p_pkt + 1); + BE_STREAM_TO_UINT16 (mtu, p_data); + if (len_left > mtu) + { + len_left = mtu; + } + len_left = len_left - p_pkt->offset - p_pkt->len; + + AVRC_TRACE_DEBUG3("len_left:%d, mtu:%d len needed:%d", len_left, mtu, len); + if (len_left < 11) /* 11 is 4/attr_id + 2/charset_id + 2/str_len + 3/first timer/attr count & len */ + { + return AVRC_STS_INTERNAL_ERR; + } + if (len > len_left) + { + AVRC_TRACE_ERROR0("The GKI buffer does not have enough room to hold the given data."); + } + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 1; /* pdu */ + + /* the existing len */ + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data + 1; + if (len == 0) + { + /* first time initialize the attribute count */ + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + *p_num = 0; + p_data++; + len = 2; + len_left -= 3; + } + else + { + p_data = p_start + p_pkt->len; + } + + + for (xx=0; (xx<p_rsp->attr_count) && (len_left>9); xx++) + { + (*p_num)++; + UINT32_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].attr_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.str_len); + len_left -= 8; + if (p_rsp->p_attr_list[xx].name.str_len > len_left) + p_rsp->p_attr_list[xx].name.str_len = len_left; + ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.p_str, p_rsp->p_attr_list[xx].name.str_len); + len_left -= p_rsp->p_attr_list[xx].name.str_len; + len += (p_rsp->p_attr_list[xx].name.str_len + 8); + } + + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} +#endif + + +/******************************************************************************* +** +** Function avrc_bld_search_rsp +** +** Description This function builds the Search response. +** +** This message goes through the Browsing channel and is +** valid only when AVCT_BROWSE_INCLUDED compile option is TRUE +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +#if (AVCT_BROWSE_INCLUDED == TRUE) +static tAVRC_STS avrc_bld_search_rsp (tAVRC_SEARCH_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len; + + AVRC_TRACE_API0("avrc_bld_search_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 1; /* pdu */ + + /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */ + UINT16_TO_BE_STREAM(p_data, 7); + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter); + UINT32_TO_BE_STREAM(p_data, p_rsp->num_items); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} +#endif + + +/******************************************************************************* +** +** Function avrc_bld_play_item_rsp +** +** Description This function builds the Play Item response. +** +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_play_item_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + AVRC_TRACE_API0("avrc_bld_play_item_rsp"); + return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt); +} + + +/******************************************************************************* +** +** Function avrc_bld_add_to_now_playing_rsp +** +** Description This function builds the Add to Now Playing response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_add_to_now_playing_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + AVRC_TRACE_API0("avrc_bld_add_to_now_playing_rsp"); + return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt); +} + +#endif /* AVRC_ADV_CTRL_INCLUDED=TRUE */ + +/******************************************************************************* +** +** Function avrc_bld_init_rsp_buffer +** +** Description This function initializes the response buffer based on PDU +** +** Returns NULL, if no GKI buffer or failure to build the message. +** Otherwise, the GKI buffer that contains the initialized message. +** +*******************************************************************************/ +static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp) +{ + UINT16 offset, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE; + BT_HDR *p_pkt=NULL; + UINT8 opcode = avrc_opcode_from_pdu(p_rsp->pdu); + + AVRC_TRACE_API3("avrc_bld_init_rsp_buffer: pdu=%x, opcode=%x/%x", p_rsp->pdu, opcode, p_rsp->rsp.opcode); + if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR && avrc_is_valid_opcode(p_rsp->rsp.opcode)) + { + opcode = p_rsp->rsp.opcode; + AVRC_TRACE_API1("opcode=%x", opcode); + } + + switch (opcode) + { +#if (AVCT_BROWSE_INCLUDED == TRUE) + case AVRC_OP_BROWSE: + chnl = AVCT_DATA_BROWSE; + offset = AVCT_BROWSE_OFFSET; + len = AVRC_BROWSE_POOL_SIZE; + break; +#endif /* AVCT_BROWSE_INCLUDED */ + + case AVRC_OP_PASS_THRU: + offset = AVRC_MSG_PASS_THRU_OFFSET; + break; + + case AVRC_OP_VENDOR: + offset = AVRC_MSG_VENDOR_OFFSET; + if (p_rsp->pdu == AVRC_PDU_GET_ELEMENT_ATTR) + len = AVRC_BROWSE_POOL_SIZE; + break; + } + + /* allocate and initialize the buffer */ + p_pkt = (BT_HDR *)GKI_getbuf(len); + if (p_pkt) + { + UINT8 *p_data, *p_start; + + p_pkt->layer_specific = chnl; + p_pkt->event = opcode; + p_pkt->offset = offset; + p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_start = p_data; + + /* pass thru - group navigation - has a two byte op_id, so dont do it here */ + if (opcode != AVRC_OP_PASS_THRU) + *p_data++ = p_rsp->pdu; + + switch (opcode) + { + case AVRC_OP_VENDOR: + /* reserved 0, packet_type 0 */ + UINT8_TO_BE_STREAM(p_data, 0); + /* continue to the next "case to add length */ +#if (AVCT_BROWSE_INCLUDED == TRUE) + case AVRC_OP_BROWSE: +#endif + /* add fixed lenth - 0 */ + UINT16_TO_BE_STREAM(p_data, 0); + break; + } + + p_pkt->len = (p_data - p_start); + } + p_rsp->rsp.opcode = opcode; + return p_pkt; +} + +/******************************************************************************* +** +** Function AVRC_BldResponse +** +** Description This function builds the given AVRCP response to the given +** GKI buffer +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt) +{ + tAVRC_STS status = AVRC_STS_BAD_PARAM; + BT_HDR *p_pkt; + BOOLEAN alloc = FALSE; +#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE)) + UINT8 *p; + UINT16 peer_mtu; +#endif + + if (!p_rsp || !pp_pkt) + { + AVRC_TRACE_API2("AVRC_BldResponse. Invalid parameters passed. p_rsp=%p, pp_pkt=%p", p_rsp, pp_pkt); + return AVRC_STS_BAD_PARAM; + } + + if (*pp_pkt == NULL) + { + if ((*pp_pkt = avrc_bld_init_rsp_buffer(p_rsp)) == NULL) + { + AVRC_TRACE_API0("AVRC_BldResponse: Failed to initialize response buffer"); + return AVRC_STS_INTERNAL_ERR; + } +#if ((AVRC_ADV_CTRL_INCLUDED == TRUE) && (AVCT_BROWSE_INCLUDED == TRUE)) + if ((*pp_pkt)->layer_specific == AVCT_DATA_BROWSE) + { + p = (UINT8 *)((*pp_pkt) + 1); + peer_mtu = AVCT_GetBrowseMtu(handle) - AVCT_HDR_LEN_SINGLE; + UINT16_TO_BE_STREAM(p, peer_mtu); + } +#endif + alloc = TRUE; + } + status = AVRC_STS_NO_ERROR; + p_pkt = *pp_pkt; + + AVRC_TRACE_API2("AVRC_BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status); + if (p_rsp->rsp.status != AVRC_STS_NO_ERROR) + { + return( avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt) ); + } + + switch (p_rsp->pdu) + { + case AVRC_PDU_NEXT_GROUP: + case AVRC_PDU_PREV_GROUP: + status = avrc_bld_group_navigation_rsp(p_rsp->pdu, p_pkt); + break; + + case AVRC_PDU_GET_CAPABILITIES: + status = avrc_bld_get_capability_rsp(&p_rsp->get_caps, p_pkt); + break; + + case AVRC_PDU_LIST_PLAYER_APP_ATTR: + status = avrc_bld_list_app_settings_attr_rsp(&p_rsp->list_app_attr, p_pkt); + break; + + case AVRC_PDU_LIST_PLAYER_APP_VALUES: + status = avrc_bld_list_app_settings_values_rsp(&p_rsp->list_app_values, p_pkt); + break; + + case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: + status = avrc_bld_get_cur_app_setting_value_rsp(&p_rsp->get_cur_app_val, p_pkt); + break; + + case AVRC_PDU_SET_PLAYER_APP_VALUE: + status = avrc_bld_set_app_setting_value_rsp(&p_rsp->set_app_val, p_pkt); + break; + + case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: + status = avrc_bld_get_app_setting_attr_text_rsp(&p_rsp->get_app_attr_txt, p_pkt); + break; + + case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: + status = avrc_bld_get_app_setting_value_text_rsp(&p_rsp->get_app_val_txt, p_pkt); + break; + + case AVRC_PDU_INFORM_DISPLAY_CHARSET: + status = avrc_bld_inform_charset_rsp(&p_rsp->inform_charset, p_pkt); + break; + + case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: + status = avrc_bld_inform_battery_status_rsp(&p_rsp->inform_battery_status, p_pkt); + break; + + case AVRC_PDU_GET_ELEMENT_ATTR: + status = avrc_bld_get_elem_attrs_rsp(&p_rsp->get_elem_attrs, p_pkt); + break; + + case AVRC_PDU_GET_PLAY_STATUS: + status = avrc_bld_get_play_status_rsp(&p_rsp->get_play_status, p_pkt); + break; + + case AVRC_PDU_REGISTER_NOTIFICATION: + status = avrc_bld_notify_rsp(&p_rsp->reg_notif, p_pkt); + break; + + case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ + status = avrc_bld_next_rsp(&p_rsp->continu, p_pkt); + break; + + case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ + status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt); + break; + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ + status = avrc_bld_set_abs_volume_rsp(&p_rsp->volume, p_pkt); + break; + + case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */ + status = avrc_bld_set_addr_player_rsp(&p_rsp->addr_player, p_pkt); + break; + + case AVRC_PDU_PLAY_ITEM: /* 0x74 */ + status = avrc_bld_play_item_rsp(&p_rsp->play_item, p_pkt); + break; + + case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */ + status = avrc_bld_add_to_now_playing_rsp(&p_rsp->add_to_play, p_pkt); + break; + +#if (AVCT_BROWSE_INCLUDED == TRUE) + case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */ + status = avrc_bld_set_browsed_player_rsp(&p_rsp->br_player, p_pkt); + break; + + case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */ + status = avrc_bld_get_folder_items_rsp(&p_rsp->get_items, p_pkt); + break; + + case AVRC_PDU_CHANGE_PATH: /* 0x72 */ + status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt); + break; + + case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */ + status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt); + break; + + case AVRC_PDU_SEARCH: /* 0x80 */ + status = avrc_bld_search_rsp(&p_rsp->search, p_pkt); + break; +#endif +#endif + } + + if (alloc && (status != AVRC_STS_NO_ERROR) ) + { + GKI_freebuf(p_pkt); + *pp_pkt = NULL; + } + AVRC_TRACE_API1("AVRC_BldResponse: returning %d", status); + return status; +} + +#endif /* (AVRC_METADATA_INCLUDED == TRUE)*/ + |