/******************************************************************************* ** ** Function avrc_prs_get_elem_attrs_rsp ** ** Description This function parses the Get Element Attributes ** response. ** ** Returns AVRC_STS_NO_ERROR, if the response is parsed successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_prs_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, UINT8 *p_data) { UINT8 *p_start, *p_len, *p_count; UINT16 len; UINT8 xx; UINT32 attr_id; if (p_rsp->num_attr == 0) return AVRC_STS_NO_ERROR; AVRC_TRACE_API("avrc_prs_get_elem_attrs_rsp num_attr: %d", p_rsp->num_attr); p_rsp->p_attrs = (tAVRC_ATTR_ENTRY*)malloc(sizeof(tAVRC_ATTR_ENTRY) * p_rsp->num_attr); for (xx=0; xx<p_rsp->num_attr; xx++) { BE_STREAM_TO_UINT32(attr_id, p_data); if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(attr_id)) { AVRC_TRACE_ERROR("avrc_prs_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, attr_id); continue; } p_rsp->p_attrs[xx].attr_id = attr_id; BE_STREAM_TO_UINT16(p_rsp->p_attrs[xx].name.charset_id, p_data); BE_STREAM_TO_UINT16(p_rsp->p_attrs[xx].name.str_len, p_data); p_rsp->p_attrs[xx].name.p_str = (UINT8*)malloc(sizeof(UINT8) * p_rsp->p_attrs[xx].name.str_len); BE_STREAM_TO_ARRAY(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len); AVRC_TRACE_DEBUG("avrc_prs_get_elem_attrs_rsp str_len: %d, str: %s", p_rsp->p_attrs[xx].name.str_len, p_rsp->p_attrs[xx].name.p_str); } return AVRC_STS_NO_ERROR; }
/****************************************************************************** ** ** Function avrc_sdp_cback ** ** Description This is the SDP callback function used by A2D_FindService. ** This function will be executed by SDP when the service ** search is completed. If the search is successful, it ** finds the first record in the database that matches the ** UUID of the search. Then retrieves various parameters ** from the record. When it is finished it calls the ** application callback function. ** ** Returns Nothing. ** ******************************************************************************/ static void avrc_sdp_cback(UINT16 status) { AVRC_TRACE_API("avrc_sdp_cback status: %d", status); /* reset service_uuid, so can start another find service */ avrc_cb.service_uuid = 0; /* return info from sdp record in app callback function */ (*avrc_cb.p_cback) (status); return; }
/******************************************************************************* ** ** Function avrc_bld_init_cmd_buffer ** ** Description This function initializes the command 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_cmd_buffer(tAVRC_COMMAND *p_cmd) { UINT16 offset = 0, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE; BT_HDR *p_pkt=NULL; UINT8 opcode; opcode = avrc_opcode_from_pdu(p_cmd->pdu); AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode); switch (opcode) { case AVRC_OP_PASS_THRU: offset = AVRC_MSG_PASS_THRU_OFFSET; break; case AVRC_OP_VENDOR: offset = AVRC_MSG_VENDOR_OFFSET; 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_cmd->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 */ /* add fixed lenth - 0 */ UINT16_TO_BE_STREAM(p_data, 0); break; } p_pkt->len = (p_data - p_start); } p_cmd->cmd.opcode = opcode; return p_pkt; }
/******************************************************************************* ** ** Function avrc_bld_set_abs_volume_cmd ** ** Description This function builds the Set Absolute Volume command. ** ** Returns AVRC_STS_NO_ERROR, if the command is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt) { UINT8 *p_data, *p_start; AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd"); /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_start + 2; /* pdu + rsvd */ /* add fixed lenth 1 - volume (1) */ UINT16_TO_BE_STREAM(p_data, 1); UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume)); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/****************************************************************************** ** ** Function AVRC_FindService ** ** Description This function is called by the application to perform service ** discovery and retrieve AVRCP SDP record information from a ** peer device. Information is returned for the first service ** record found on the server that matches the service UUID. ** The callback function will be executed when service discovery ** is complete. There can only be one outstanding call to ** AVRC_FindService() at a time; the application must wait for ** the callback before it makes another call to the function. ** The application is responsible for allocating memory for the ** discovery database. It is recommended that the size of the ** discovery database be at least 300 bytes. The application ** can deallocate the memory after the callback function has ** executed. ** ** Input Parameters: ** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET) ** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) ** ** bd_addr: BD address of the peer device. ** ** p_db: SDP discovery database parameters. ** ** p_cback: Pointer to the callback function. ** ** Output Parameters: ** None. ** ** Returns AVRC_SUCCESS if successful. ** AVRC_BAD_PARAMS if discovery database parameters are invalid. ** AVRC_NO_RESOURCES if there are not enough resources to ** perform the service search. ** ******************************************************************************/ UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr, tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback) { tSDP_UUID uuid_list; BOOLEAN result = TRUE; UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */ ATTR_ID_PROTOCOL_DESC_LIST, ATTR_ID_BT_PROFILE_DESC_LIST, ATTR_ID_SERVICE_NAME, ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_PROVIDER_NAME }; AVRC_TRACE_API("AVRC_FindService uuid: %x", service_uuid); if ( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) || p_db == NULL || p_db->p_db == NULL || p_cback == NULL) { return AVRC_BAD_PARAM; } /* check if it is busy */ if ( avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET || avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) { return AVRC_NO_RESOURCES; } /* set up discovery database */ uuid_list.len = LEN_UUID_16; uuid_list.uu.uuid16 = service_uuid; if (p_db->p_attrs == NULL || p_db->num_attr == 0) { p_db->p_attrs = a2d_attr_list; p_db->num_attr = AVRC_NUM_ATTR; } result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr, p_db->p_attrs); if (result == TRUE) { /* store service_uuid and discovery db pointer */ avrc_cb.p_db = p_db->p_db; avrc_cb.service_uuid = service_uuid; avrc_cb.p_cback = p_cback; /* perform service search */ result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback); } return (result ? AVRC_SUCCESS : AVRC_FAIL); }
/******************************************************************************* ** ** Function avrc_bld_get_element_attr_cmd ** ** Description This function builds the Get Element Attribute command. ** ** Returns AVRC_STS_NO_ERROR, if the command is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_get_element_attr_cmd (tAVRC_GET_ELEM_ATTRS_CMD *p_cmd, BT_HDR *p_pkt) { int i; UINT8 *p_data, *p_start; AVRC_TRACE_API("avrc_bld_get_element_attr_cmd num_attr: %d", p_cmd->num_attr); /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_start + 2; /* pdu + rsvd */ /* add length */ UINT16_TO_BE_STREAM(p_data, 8 + 1 /* id + attr count */ + p_cmd->num_attr * sizeof(UINT32)); /* Identifier 0x0 (PLAYING) */ UINT64_TO_BE_STREAM(p_data, (UINT64)(0)); /* Attribute count */ UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr); for (i=0; i<p_cmd->num_attr; i++){ AVRC_TRACE_API("avrc_bld_get_element_attr_cmd attr_id: %d", p_cmd->attrs[i]); UINT32_TO_BE_STREAM(p_data, p_cmd->attrs[i]); } p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function avrc_bld_vol_change_notfn ** ** Description This function builds the register notification for volume change. ** ** Returns AVRC_STS_NO_ERROR, if the command is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR * p_pkt) { UINT8 *p_data, *p_start; AVRC_TRACE_API("avrc_bld_vol_change"); /* get the existing length, if any, and also the num attributes */ // Set the notify value p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_start + 2; /* pdu + rsvd */ /* add fixed length 5 -*/ UINT16_TO_BE_STREAM(p_data, 5); UINT8_TO_BE_STREAM(p_data,AVRC_EVT_VOLUME_CHANGE); UINT32_TO_BE_STREAM(p_data, 0); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/******************************************************************************* ** ** Function avrc_bld_next_cmd ** ** Description This function builds the Request Continue or Abort command. ** ** Returns AVRC_STS_NO_ERROR, if the command is built successfully ** Otherwise, the error code. ** *******************************************************************************/ static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt) { UINT8 *p_data, *p_start; AVRC_TRACE_API("avrc_bld_next_cmd"); /* get the existing length, if any, and also the num attributes */ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; p_data = p_start + 2; /* pdu + rsvd */ /* add fixed lenth 1 - pdu_id (1) */ UINT16_TO_BE_STREAM(p_data, 1); UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu); p_pkt->len = (p_data - p_start); return AVRC_STS_NO_ERROR; }
/****************************************************************************** ** ** Function AVRC_AddRecord ** ** Description This function is called to build an AVRCP SDP record. ** Prior to calling this function the application must ** call SDP_CreateRecord() to create an SDP record. ** ** Input Parameters: ** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET) ** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) ** ** p_service_name: Pointer to a null-terminated character ** string containing the service name. ** If service name is not used set this to NULL. ** ** p_provider_name: Pointer to a null-terminated character ** string containing the provider name. ** If provider name is not used set this to NULL. ** ** categories: Supported categories. ** ** sdp_handle: SDP handle returned by SDP_CreateRecord(). ** ** Output Parameters: ** None. ** ** Returns AVRC_SUCCESS if successful. ** AVRC_NO_RESOURCES if not enough resources to build the SDP record. ** ******************************************************************************/ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name, UINT16 categories, UINT32 sdp_handle) { UINT16 browse_list[1]; BOOLEAN result = TRUE; UINT8 temp[8]; UINT8 *p; UINT16 count = 1; UINT16 class_list[2]; AVRC_TRACE_API("AVRC_AddRecord uuid: %x", service_uuid); if( service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL ) return AVRC_BAD_PARAM; /* add service class id list */ class_list[0] = service_uuid; #if SDP_AVRCP_1_5 == TRUE if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) { class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; count = 2; } #else #if SDP_AVRCP_1_4 == TRUE if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) { class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; count = 2; } #endif #endif result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list); /* add protocol descriptor list */ result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, (tSDP_PROTOCOL_ELEM *)avrc_proto_list); /* add profile descriptor list */ #if SDP_AVRCP_1_5 == TRUE /* additional protocol list to include browsing channel */ result &= SDP_AddAdditionProtoLists( sdp_handle, AVRC_NUM_ADDL_PROTO_ELEMS, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list); result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_5); #else #if SDP_AVRCP_1_4 == TRUE /* additional protocol list to include browsing channel */ result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list); result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_5); #else #if AVRC_METADATA_INCLUDED == TRUE result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_3); #else result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_0); #endif #endif #endif /* add supported categories */ p = temp; UINT16_TO_BE_STREAM(p, categories); result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, (UINT32)2, (UINT8*)temp); /* add provider name */ if (p_provider_name != NULL) { result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name); } /* add service name */ if (p_service_name != NULL) { result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name); } /* add browse group list */ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); return (result ? AVRC_SUCCESS : AVRC_FAIL); }
/******************************************************************************* ** ** Function avrc_pars_vendor_rsp ** ** Description This function parses the vendor specific commands defined by ** Bluetooth SIG ** ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result) { tAVRC_STS status = AVRC_STS_NO_ERROR; UINT8 *p = p_msg->p_vendor_data; UINT16 len; UINT8 xx, yy; tAVRC_NOTIF_RSP_PARAM *p_param; tAVRC_APP_SETTING *p_app_set; tAVRC_APP_SETTING_TEXT *p_app_txt; tAVRC_ATTR_ENTRY *p_entry; UINT32 *p_u32; UINT8 *p_u8; UINT16 size_needed; UINT8 eventid=0; BE_STREAM_TO_UINT8 (p_result->pdu, p); p++; /* skip the reserved/packe_type byte */ BE_STREAM_TO_UINT16 (len, p); AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); if (p_msg->hdr.ctype == AVRC_RSP_REJ) { p_result->rsp.status = *p; return p_result->rsp.status; } switch (p_result->pdu) { /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ if (len != 1) status = AVRC_STS_INTERNAL_ERR; else { BE_STREAM_TO_UINT8 (p_result->volume.volume, p); } break; case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */ BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p); AVRC_TRACE_API("num_attr: %d", p_result->get_elem_attrs.num_attr); if (len == 0) status = AVRC_STS_INTERNAL_ERR; else { status = avrc_prs_get_elem_attrs_rsp(&p_result->get_elem_attrs, p); } break; #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) BE_STREAM_TO_UINT8 (eventid, p); if(AVRC_EVT_VOLUME_CHANGE==eventid && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype)) { p_result->reg_notif.status=p_msg->hdr.ctype; p_result->reg_notif.event_id=eventid; BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); } AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid, p_result->reg_notif.param.volume); #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ break; default: status = AVRC_STS_BAD_CMD; break; } return status; }
/******************************************************************************* ** ** Function AVRC_BldCommand ** ** Description This function builds the given AVRCP command to the given ** GKI buffer ** ** Returns AVRC_STS_NO_ERROR, if the command is built successfully ** Otherwise, the error code. ** *******************************************************************************/ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt) { tAVRC_STS status = AVRC_STS_BAD_PARAM; BT_HDR *p_pkt; BOOLEAN alloc = FALSE; AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status); if (!p_cmd || !pp_pkt) { AVRC_TRACE_API("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p", p_cmd, pp_pkt); return AVRC_STS_BAD_PARAM; } if (*pp_pkt == NULL) { if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL) { AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer"); return AVRC_STS_INTERNAL_ERR; } alloc = TRUE; } status = AVRC_STS_NO_ERROR; p_pkt = *pp_pkt; switch (p_cmd->pdu) { case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt); break; case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt); break; #if (AVRC_ADV_CTRL_INCLUDED == TRUE) case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt); break; case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */ status = avrc_bld_get_element_attr_cmd(&p_cmd->get_elem_attrs, p_pkt); break; #endif case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) if(AVRC_EVT_VOLUME_CHANGE==p_cmd->reg_notif.event_id) status=avrc_bld_vol_change_notfn(p_pkt); #endif break; } if (alloc && (status != AVRC_STS_NO_ERROR) ) { GKI_freebuf(p_pkt); *pp_pkt = NULL; } AVRC_TRACE_API("AVRC_BldCommand: returning %d", status); return status; }