/*******************************************************************************
**
** Function         bta_pan_set_role
**
** Description
**
** Returns          void
**
*******************************************************************************/
void bta_pan_set_role(tBTA_PAN_DATA *p_data)
{
    tPAN_RESULT status;
    tBTA_PAN_SET_ROLE set_role;
    UINT8  sec[3];


    bta_pan_cb.app_id[0] = p_data->api_set_role.user_app_id;
    bta_pan_cb.app_id[1] = p_data->api_set_role.gn_app_id;
    bta_pan_cb.app_id[2] = p_data->api_set_role.nap_app_id;

    sec[0] = p_data->api_set_role.user_sec_mask;
    sec[1] = p_data->api_set_role.gn_sec_mask;
    sec[2] = p_data->api_set_role.nap_sec_mask;

    /* set security correctly in api and here */
    status = PAN_SetRole(p_data->api_set_role.role, sec,
                                     p_data->api_set_role.user_name,
                                     p_data->api_set_role.gn_name,
                                     p_data->api_set_role.nap_name);

    set_role.role = p_data->api_set_role.role;
    if(status == PAN_SUCCESS)
    {
        if(p_data->api_set_role.role & PAN_ROLE_NAP_SERVER )
            bta_sys_add_uuid(UUID_SERVCLASS_NAP);
        else
            bta_sys_remove_uuid(UUID_SERVCLASS_NAP);

        if(p_data->api_set_role.role & PAN_ROLE_GN_SERVER )
            bta_sys_add_uuid(UUID_SERVCLASS_GN);
        else
            bta_sys_remove_uuid(UUID_SERVCLASS_GN);

        if(p_data->api_set_role.role & PAN_ROLE_CLIENT )
            bta_sys_add_uuid(UUID_SERVCLASS_PANU);
        else
            bta_sys_remove_uuid(UUID_SERVCLASS_PANU);

        set_role.status = BTA_PAN_SUCCESS;
    }
    /* if status is not success clear everything */
    else
    {
        PAN_SetRole(0, 0, NULL, NULL, NULL);
        bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
        bta_sys_remove_uuid(UUID_SERVCLASS_GN);
        bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
        set_role.status = BTA_PAN_FAIL;
    }
    bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, (tBTA_PAN *)&set_role);
}
/*******************************************************************************
**
** Function         bta_ag_create_records
**
** Description      Create SDP records for registered services.
**
**
** Returns          void
**
*******************************************************************************/
void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
{
    int                 i;
    tBTA_SERVICE_MASK   services;

    services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
    {
        /* if service is set in mask */
        if (services & 1)
        {
            /* add sdp record if not already registered */
            if (bta_ag_cb.profile[i].sdp_handle == 0)
            {
                bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
                bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
                bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
                    bta_ag_cb.profile[i].scn, p_data->api_register.features,
                    bta_ag_cb.profile[i].sdp_handle);
                bta_sys_add_uuid(bta_ag_uuid[i]);
            }
        }
    }

    p_scb->hsp_version = HSP_VERSION_1_2;

}
예제 #3
0
/*******************************************************************************
**
** Function         bta_hf_client_create_record
**
** Description      Create SDP record for registered service.
**
**
** Returns          void
**
*******************************************************************************/
void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA *p_data)
{
    /* add sdp record if not already registered */
    if (bta_hf_client_cb.sdp_handle == 0) {
        bta_hf_client_cb.sdp_handle = SDP_CreateRecord();
        bta_hf_client_cb.scn = BTM_AllocateSCN();
        bta_hf_client_add_record(p_data->api_register.name,
                                 bta_hf_client_cb.scn,
                                 p_data->api_register.features,
                                 bta_hf_client_cb.sdp_handle);

        bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
    }

}
예제 #4
0
파일: bta_ar.c 프로젝트: tve/esp-idf
/******************************************************************************
**
** Function         bta_ar_reg_avrc
**
** Description      This function is called to register an SDP record for AVRCP.
**
** Returns          void
**
******************************************************************************/
void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_name,
                     UINT16 categories, tBTA_SYS_ID sys_id)
{
    UINT8   mask = bta_ar_id (sys_id);
    UINT8   temp[8], *p;

    if (!mask || !categories) {
        return;
    }

    if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {
        if (bta_ar_cb.sdp_tg_handle == 0) {
            bta_ar_cb.tg_registered = mask;
            bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
            AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle);
            bta_sys_add_uuid(service_uuid);
        }
        /* only one TG is allowed (first-come, first-served).
         * If sdp_tg_handle is non-0, ignore this request */
    } else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL)) {
        bta_ar_cb.ct_categories [mask - 1] = categories;
        categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];
        if (bta_ar_cb.sdp_ct_handle == 0) {
            bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
            AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle);
            bta_sys_add_uuid(service_uuid);
        } else {
            /* multiple CTs are allowed.
             * Change supported categories on the second one */
            p = temp;
            UINT16_TO_BE_STREAM(p, categories);
            SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
                             (UINT32)2, (UINT8 *)temp);
        }
    }
}
/*******************************************************************************
**
** Function         PAN_SetRole
**
** Description      This function is called by the application to set the PAN
**                  profile role. This should be called after PAN_Register.
**                  This can be called any time to change the PAN role
**
** Parameters:      role        - is bit map of roles to be active
**                                      PAN_ROLE_CLIENT is for PANU role
**                                      PAN_ROLE_GN_SERVER is for GN role
**                                      PAN_ROLE_NAP_SERVER is for NAP role
**                  sec_mask    - Security mask for different roles
**                                      It is array of UINT8. The byte represent the
**                                      security for roles PANU, GN and NAP in order
**                  p_user_name - Service name for PANU role
**                  p_gn_name   - Service name for GN role
**                  p_nap_name  - Service name for NAP role
**                                      Can be NULL if user wants it to be default
**
** Returns          PAN_SUCCESS     - if the role is set successfully
**                  PAN_FAILURE     - if the role is not valid
**
*******************************************************************************/
tPAN_RESULT PAN_SetRole (UINT8 role,
                         UINT8 *sec_mask,
                         char *p_user_name,
                         char *p_gn_name,
                         char *p_nap_name)
{
    char                *p_desc;
    UINT8               security[3] = {PAN_PANU_SECURITY_LEVEL,
                                       PAN_GN_SECURITY_LEVEL,
                                       PAN_NAP_SECURITY_LEVEL};
    UINT8               *p_sec;

    /* If the role is not a valid combination reject it */
    if ((!(role & (PAN_ROLE_CLIENT | PAN_ROLE_GN_SERVER | PAN_ROLE_NAP_SERVER))) &&
        role != PAN_ROLE_INACTIVE)
    {
        PAN_TRACE_ERROR1 ("PAN role %d is invalid", role);
        return PAN_FAILURE;
    }

    /* If the current active role is same as the role being set do nothing */
    if (pan_cb.role == role)
    {
        PAN_TRACE_EVENT1 ("PAN role already was set to: %d", role);
        return PAN_SUCCESS;
    }

    if (!sec_mask)
        p_sec = security;
    else
        p_sec = sec_mask;

    /* Register all the roles with SDP */
    PAN_TRACE_API1 ("PAN_SetRole() called with role 0x%x", role);
#if (defined (PAN_SUPPORTS_ROLE_NAP) && PAN_SUPPORTS_ROLE_NAP == TRUE)
    /* Check the service name */
    if ((p_nap_name == NULL) || (*p_nap_name == 0))
        p_nap_name = PAN_NAP_DEFAULT_SERVICE_NAME;

    if (role & PAN_ROLE_NAP_SERVER)
    {
        /* Registering for NAP service with SDP */
        p_desc = PAN_NAP_DEFAULT_DESCRIPTION;

        if (pan_cb.pan_nap_sdp_handle != 0)
            SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle);

        pan_cb.pan_nap_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_NAP, p_sec[2], p_nap_name, p_desc);
// btla-specific ++
        bta_sys_add_uuid(UUID_SERVCLASS_NAP);
// btla-specific --
    }
    /* If the NAP role is already active and now being cleared delete the record */
    else if (pan_cb.role & PAN_ROLE_NAP_SERVER)
    {
        if (pan_cb.pan_nap_sdp_handle != 0)
        {
            SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle);
            pan_cb.pan_nap_sdp_handle = 0;
// btla-specific ++
            bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
// btla-specific --
        }
    }
#endif

#if (defined (PAN_SUPPORTS_ROLE_GN) && PAN_SUPPORTS_ROLE_GN == TRUE)
    /* Check the service name */
    if ((p_gn_name == NULL) || (*p_gn_name == 0))
        p_gn_name = PAN_GN_DEFAULT_SERVICE_NAME;

    if (role & PAN_ROLE_GN_SERVER)
    {
        /* Registering for GN service with SDP */
        p_desc = PAN_GN_DEFAULT_DESCRIPTION;

        if (pan_cb.pan_gn_sdp_handle != 0)
            SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle);

        pan_cb.pan_gn_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_GN, p_sec[1], p_gn_name, p_desc);
// btla-specific ++
        bta_sys_add_uuid(UUID_SERVCLASS_GN);
// btla-specific --
    }
    /* If the GN role is already active and now being cleared delete the record */
    else if (pan_cb.role & PAN_ROLE_GN_SERVER)
    {
        if (pan_cb.pan_gn_sdp_handle != 0)
        {
            SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle);
            pan_cb.pan_gn_sdp_handle = 0;
// btla-specific ++
            bta_sys_remove_uuid(UUID_SERVCLASS_GN);
// btla-specific --
        }
    }
#endif

#if (defined (PAN_SUPPORTS_ROLE_PANU) && PAN_SUPPORTS_ROLE_PANU == TRUE)
    /* Check the service name */
    if ((p_user_name == NULL) || (*p_user_name == 0))
        p_user_name = PAN_PANU_DEFAULT_SERVICE_NAME;

    if (role & PAN_ROLE_CLIENT)
    {
        /* Registering for PANU service with SDP */
        p_desc = PAN_PANU_DEFAULT_DESCRIPTION;
        if (pan_cb.pan_user_sdp_handle != 0)
            SDP_DeleteRecord (pan_cb.pan_user_sdp_handle);

        pan_cb.pan_user_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_PANU, p_sec[0], p_user_name, p_desc);
// btla-specific ++
        bta_sys_add_uuid(UUID_SERVCLASS_PANU);
// btla-specific --
    }
    /* If the PANU role is already active and now being cleared delete the record */
    else if (pan_cb.role & PAN_ROLE_CLIENT)
    {
        if (pan_cb.pan_user_sdp_handle != 0)
        {
            SDP_DeleteRecord (pan_cb.pan_user_sdp_handle);
            pan_cb.pan_user_sdp_handle = 0;
// btla-specific ++
            bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
// btla-specific --
        }
    }
#endif

    /* Check if it is a shutdown request */
    if (role == PAN_ROLE_INACTIVE)
        pan_close_all_connections ();

    pan_cb.role = role;
    PAN_TRACE_EVENT1 ("PAN role set to: %d", role);
    return PAN_SUCCESS;
}
예제 #6
0
/*****************************************************************************
**
**  Function:    bta_hl_sdp_register
**
**  Purpose:     Register an HDP application with SDP
**
**  Parameters:  p_cb           - Pointer to MA instance control block
**               p_service_name - MA server name
**               inst_id        - MAS instance ID
**               msg_type       - Supported message type(s)
**
**
**  Returns:     void
**
*****************************************************************************/
tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx)
{
    UINT16                          svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
    tSDP_PROTOCOL_ELEM              proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
    tSDP_PROTO_LIST_ELEM            add_proto_list;
    tBTA_HL_SUP_FEATURE_LIST_ELEM   sup_feature_list;
    UINT16                          browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
    UINT8                           i,j, cnt,mdep_id, mdep_role;
    UINT8                           data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
    UINT8                           mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
    UINT16                          profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
    UINT16                          version = BTA_HL_VERSION_01_00;
    UINT8                           num_services=1;
    tBTA_HL_APP_CB                  *p_cb = BTA_HL_GET_APP_CB_PTR(app_idx);
    BOOLEAN                         result = TRUE;
    tBTA_HL_STATUS                  status = BTA_HL_STATUS_OK;

#if BTA_HL_DEBUG == TRUE
    APPL_TRACE_DEBUG("bta_hl_sdp_register app_idx=%d",app_idx);
#endif

    if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
        (!p_cb->sup_feature.advertize_source_sdp))
    {
        return BTA_HL_STATUS_OK;
    }

    if ((p_cb->sdp_handle  = SDP_CreateRecord()) == 0)
    {
        return BTA_HL_STATUS_SDP_NO_RESOURCE;
    }

    num_services=1;
    svc_class_id_list[0]= UUID_SERVCLASS_HDP_SOURCE;
    if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK)
    {
        svc_class_id_list[0]= UUID_SERVCLASS_HDP_SINK;
    }
    else
    {
        if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE)
        {
            /* dual role */
            num_services=2;
            svc_class_id_list[1]= UUID_SERVCLASS_HDP_SINK;
        }
    }
    result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services, svc_class_id_list);

    if (result)
    {
        /* add the protocol element sequence */
        proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
        proto_elem_list[0].num_params = 1;
        proto_elem_list[0].params[0] = p_cb->ctrl_psm;
        proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
        proto_elem_list[1].num_params = 1;
        proto_elem_list[1].params[0] = version;
        result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS, proto_elem_list);

        result &= SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
    }

    if (result)
    {
        add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
        add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
        add_proto_list.list_elem[0].num_params = 1;
        add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
        add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
        add_proto_list.list_elem[1].num_params = 0;
        result &= SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
                                            (tSDP_PROTO_LIST_ELEM *)&add_proto_list);
    }

    if (result)
    {
        if (p_cb->srv_name[0] )
        {
            result &= SDP_AddAttribute(p_cb->sdp_handle,
                                       (UINT16)ATTR_ID_SERVICE_NAME,
                                       (UINT8)TEXT_STR_DESC_TYPE,
                                       (UINT32)(strlen(p_cb->srv_name) + 1),
                                       (UINT8 *)p_cb->srv_name);
        } /* end of setting optional service name */
    }

    if (result)
    {
        if (p_cb->srv_desp[0] )
        {
            result &= SDP_AddAttribute(p_cb->sdp_handle,
                                       (UINT16)ATTR_ID_SERVICE_DESCRIPTION,
                                       (UINT8)TEXT_STR_DESC_TYPE,
                                       (UINT32)(strlen(p_cb->srv_desp) + 1),
                                       (UINT8 *)p_cb->srv_desp);

        } /* end of setting optional service description */

    }

    if (result)
    {
        if (p_cb->provider_name[0] )
        {
            result &= SDP_AddAttribute(p_cb->sdp_handle,
                                       (UINT16)ATTR_ID_PROVIDER_NAME,
                                       (UINT8)TEXT_STR_DESC_TYPE,
                                       (UINT32)(strlen(p_cb->provider_name) + 1),
                                       (UINT8 *)p_cb->provider_name);
        } /* end of setting optional provider name */
    }

    /* add supported feture list */

    if (result)
    {
        cnt=0;
        for (i=1; i<= p_cb->sup_feature.num_of_mdeps; i++)
        {
            mdep_id = (UINT8)p_cb->sup_feature.mdep[i].mdep_id;
            mdep_role = (UINT8)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;

            for (j=0; j<p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types; j++)
            {
                sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
                sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
                sup_feature_list.list_elem[cnt].data_type = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
                if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0')
                {
                    sup_feature_list.list_elem[cnt].p_mdep_desp = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
                }
                else
                {
                    sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
                }

                cnt++;
                if (cnt==BTA_HL_NUM_SUP_FEATURE_ELEMS)
                {
                    result = FALSE;
                    break;
                }
            }
        }
        sup_feature_list.num_elems = cnt;
        result &=   bta_hl_add_sup_feature_list (p_cb->sdp_handle,
                                                 sup_feature_list.num_elems,
                                                 sup_feature_list.list_elem);
    }
    if (result)
    {
        result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC, UINT_DESC_TYPE,
                                   (UINT32)1, (UINT8*)&data_exchange_spec);
    }

    if (result)
    {

        result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC, UINT_DESC_TYPE,
                                   (UINT32)1, (UINT8*)&mcap_sup_proc);
    }

    if (result)
    {
        result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
    }

    if (result)
    {
        for(i=0; i < num_services; i++)
        {
            bta_sys_add_uuid(svc_class_id_list[i]);
            APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i, svc_class_id_list[i]); //todo
        }
    }
    else
    {
        if (p_cb->sdp_handle)
        {
            SDP_DeleteRecord(p_cb->sdp_handle);
            p_cb->sdp_handle = 0;
        }
        status = BTA_HL_STATUS_SDP_FAIL;
    }
#if BTA_HL_DEBUG == TRUE
    APPL_TRACE_DEBUG("bta_hl_sdp_register status=%s", bta_hl_status_code(status));
#endif
    return status;
}
/*******************************************************************************
**
** Function         bta_av_api_register
**
** Description      allocate stream control block,
**                  register the service to stack
**                  create SDP record
**
** Returns          void
**
*******************************************************************************/
static void bta_av_api_register(tBTA_AV_DATA *p_data)
{
    tBTA_AV_REGISTER    registr;
    tBTA_AV_SCB         *p_scb;    /* stream control block */
    tAVDT_REG       reg;
    tAVDT_CS        cs;
    char            *p_service_name;
    tBTA_AV_CODEC   codec_type;
    tBTA_UTL_COD    cod;
    UINT8           index = 0;

    memset(&cs,0,sizeof(tAVDT_CS));

    registr.status = BTA_AV_FAIL_RESOURCES;
    registr.app_id = p_data->api_reg.app_id;
    registr.chnl   = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
    do
    {
        p_scb = bta_av_alloc_scb(registr.chnl);
        if(p_scb == NULL)
        {
            APPL_TRACE_ERROR0("failed to alloc SCB");
            break;
        }

        registr.hndl    = p_scb->hndl;
        p_scb->app_id   = registr.app_id;

        /* initialize the stream control block */
        p_scb->timer.p_cback = (TIMER_CBACK*)&bta_av_timer_cback;
        registr.status = BTA_AV_SUCCESS;

        if((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0)
        {
            /* the first channel registered. register to AVDTP */
            reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
            reg.ret_tout = BTA_AV_RET_TOUT;
            reg.sig_tout = BTA_AV_SIG_TOUT;
            reg.idle_tout = BTA_AV_IDLE_TOUT;
            reg.sec_mask = bta_av_cb.sec_mask;
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
            bta_ar_reg_avdt(&reg, bta_av_conn_cback, BTA_ID_AV);
#endif
            bta_sys_role_chg_register(&bta_av_sys_rs_cback);

            /* create remote control TG service if required */
            if (bta_av_cb.features & (BTA_AV_FEAT_RCTG))
            {
                /* register with no authorization; let AVDTP use authorization instead */
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
                bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                bta_av_cb.sec_mask, BTA_ID_AV);
#else
                bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
#endif

                bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL,
                                p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV);
#endif
            }

            /* Set the Capturing service class bit */
            cod.service = BTM_COD_SERVICE_CAPTURING;
            utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
        } /* if 1st channel */

        /* get stream configuration and create stream */
        /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */
        cs.cfg.num_codec = 1;
#ifdef A2DP_SINK
        cs.tsep = AVDT_TSEP_SNK;
#else
        cs.tsep = AVDT_TSEP_SRC;
#endif

        /*
         * memset of cs takes care setting call back pointers to null.
        cs.p_data_cback = NULL;
        cs.p_report_cback = NULL;
        */
#ifdef A2DP_SINK
        cs.p_data_cback = bta_av_a2dp_data_cback;
#endif
        cs.nsc_mask = AVDT_NSC_RECONFIG |
              ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
        APPL_TRACE_DEBUG1("nsc_mask: 0x%x", cs.nsc_mask);

        if (p_data->api_reg.p_service_name[0] == 0)
        {
            p_service_name = NULL;
        }
        else
        {
            p_service_name = p_data->api_reg.p_service_name;
        }

        p_scb->suspend_sup  = TRUE;
        p_scb->recfg_sup    = TRUE;

        cs.p_ctrl_cback  = bta_av_dt_cback[p_scb->hdi];
        if(registr.chnl == BTA_AV_CHNL_AUDIO)
        {
            /* set up the audio stream control block */
            p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
            p_scb->p_cos     = &bta_av_a2d_cos;
            p_scb->media_type= AVDT_MEDIA_AUDIO;
            cs.cfg.psc_mask  = AVDT_PSC_TRANS;
            cs.media_type    = AVDT_MEDIA_AUDIO;
            cs.mtu           = p_bta_av_cfg->audio_mtu;
            cs.flush_to      = L2CAP_DEFAULT_FLUSH_TO;
#if AVDT_REPORTING == TRUE
            if(bta_av_cb.features & BTA_AV_FEAT_REPORT)
            {
                cs.cfg.psc_mask |= AVDT_PSC_REPORT;
                cs.p_report_cback = bta_av_a2dp_report_cback;
#if AVDT_MULTIPLEXING == TRUE
                cs.cfg.mux_tsid_report = 2;
#endif
            }
#endif
            if(bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
                cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;

            /* keep the configuration in the stream control block */
            memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
            while(index < BTA_AV_MAX_SEPS &&
                (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
                &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
            {
                if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)
                {
                    p_scb->seps[index].codec_type = codec_type;
                    APPL_TRACE_DEBUG3("audio[%d] av_handle: %d codec_type: %d",
                        index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type);
                    index++;
                }
                else
                    break;
            }

            if(!bta_av_cb.reg_audio)
            {
                /* create the SDP records on the 1st audio channel */
                bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
#ifdef A2DP_SINK
                A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
                                  A2D_SUPF_SPEAKER, bta_av_cb.sdp_a2d_handle);
                bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
#else
                A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
                                  A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle);
                bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
#endif

                /* start listening when A2DP is registered */
                if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
                    bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);

                /* if the AV and AVK are both supported, it cannot support the CT role */
                if (bta_av_cb.features & (BTA_AV_FEAT_RCCT))
                {
                    /* if TG is not supported, we need to register to AVCT now */
                    if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0)
                    {
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
                        bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                        bta_av_cb.sec_mask, BTA_ID_AV);
#else
                        bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                        (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
#endif
#endif
                    }
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
                    /* create an SDP record as AVRC CT. */
                    bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
                           p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV);
#endif
                }
            }
            bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
            APPL_TRACE_DEBUG1("reg_audio: 0x%x",bta_av_cb.reg_audio);
        }
        else
        {
            bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
            bta_av_cb.sdp_vdp_handle = SDP_CreateRecord();
            /* register the video channel */
            /* no need to verify the function pointer here. it's verified prior */
            (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb);
        }
    } while (0);

    /* call callback with register event */
    (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)&registr);
}