1*ac726063SMatthias Ringwald /* 2*ac726063SMatthias Ringwald * Copyright (C) 2023 BlueKitchen GmbH 3*ac726063SMatthias Ringwald * 4*ac726063SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*ac726063SMatthias Ringwald * modification, are permitted provided that the following conditions 6*ac726063SMatthias Ringwald * are met: 7*ac726063SMatthias Ringwald * 8*ac726063SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*ac726063SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*ac726063SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*ac726063SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*ac726063SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*ac726063SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*ac726063SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*ac726063SMatthias Ringwald * from this software without specific prior written permission. 16*ac726063SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*ac726063SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*ac726063SMatthias Ringwald * monetary gain. 19*ac726063SMatthias Ringwald * 20*ac726063SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*ac726063SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*ac726063SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*ac726063SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24*ac726063SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*ac726063SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*ac726063SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*ac726063SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*ac726063SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*ac726063SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*ac726063SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*ac726063SMatthias Ringwald * SUCH DAMAGE. 32*ac726063SMatthias Ringwald * 33*ac726063SMatthias Ringwald * Please inquire about commercial licensing options at 34*ac726063SMatthias Ringwald * [email protected] 35*ac726063SMatthias Ringwald * 36*ac726063SMatthias Ringwald */ 37*ac726063SMatthias Ringwald 38*ac726063SMatthias Ringwald #define BTSTACK_FILE__ "avrcp_cover_art_client.c" 39*ac726063SMatthias Ringwald 40*ac726063SMatthias Ringwald #include <string.h> 41*ac726063SMatthias Ringwald 42*ac726063SMatthias Ringwald #include "btstack_debug.h" 43*ac726063SMatthias Ringwald #include "btstack_event.h" 44*ac726063SMatthias Ringwald #include "classic/avrcp.h" 45*ac726063SMatthias Ringwald #include "classic/avrcp_cover_art_client.h" 46*ac726063SMatthias Ringwald #include "classic/obex.h" 47*ac726063SMatthias Ringwald #include "hci_event.h" 48*ac726063SMatthias Ringwald 49*ac726063SMatthias Ringwald #ifdef ENABLE_AVRCP_COVER_ART 50*ac726063SMatthias Ringwald 51*ac726063SMatthias Ringwald static const hci_event_t avrcp_cover_art_client_connected = { 52*ac726063SMatthias Ringwald .event_code = HCI_EVENT_AVRCP_META, 53*ac726063SMatthias Ringwald .subevent_code = AVRCP_SUBEVENT_COVER_ART_CONNECTION_ESTABLISHED, 54*ac726063SMatthias Ringwald .format = "1B22" 55*ac726063SMatthias Ringwald }; 56*ac726063SMatthias Ringwald 57*ac726063SMatthias Ringwald static const hci_event_t avrcp_cover_art_client_disconnected = { 58*ac726063SMatthias Ringwald .event_code = HCI_EVENT_AVRCP_META, 59*ac726063SMatthias Ringwald .subevent_code = AVRCP_SUBEVENT_COVER_ART_CONNECTION_RELEASED, 60*ac726063SMatthias Ringwald .format = "2" 61*ac726063SMatthias Ringwald }; 62*ac726063SMatthias Ringwald 63*ac726063SMatthias Ringwald static const hci_event_t avrcp_cover_art_client_operation_complete = { 64*ac726063SMatthias Ringwald .event_code = HCI_EVENT_AVRCP_META, 65*ac726063SMatthias Ringwald .subevent_code = AVRCP_SUBEVENT_COVER_ART_OPERATION_COMPLETE, 66*ac726063SMatthias Ringwald .format = "21" 67*ac726063SMatthias Ringwald }; 68*ac726063SMatthias Ringwald 69*ac726063SMatthias Ringwald // 7163DD54-4A7E-11E2-B47C-0050C2490048 70*ac726063SMatthias Ringwald static const uint8_t avrcp_cover_art_uuid[] = { 0x71, 0x63, 0xDD, 0x54, 0x4A, 0x7E, 0x11, 0xE2, 0xB4, 0x7C, 0x00, 0x50, 0xC2, 0x49, 0x00, 0x48 }; 71*ac726063SMatthias Ringwald 72*ac726063SMatthias Ringwald // OBEX types 73*ac726063SMatthias Ringwald const char * avrcp_cover_art_image_properties_type = "x-bt/img-properties"; 74*ac726063SMatthias Ringwald const char * avrcp_cover_art_image_type = "x-bt/img-img"; 75*ac726063SMatthias Ringwald const char * avrcp_cover_art_linked_thumbnail_type = "x-bt/img-thm"; 76*ac726063SMatthias Ringwald 77*ac726063SMatthias Ringwald static btstack_linked_list_t avrcp_cover_art_client_connections; 78*ac726063SMatthias Ringwald 79*ac726063SMatthias Ringwald static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 80*ac726063SMatthias Ringwald 81*ac726063SMatthias Ringwald static uint16_t avrcp_cover_art_client_next_cid() { 82*ac726063SMatthias Ringwald static uint16_t cid = 0; 83*ac726063SMatthias Ringwald cid++; 84*ac726063SMatthias Ringwald if (cid == 0){ 85*ac726063SMatthias Ringwald cid = 1; 86*ac726063SMatthias Ringwald } 87*ac726063SMatthias Ringwald return cid; 88*ac726063SMatthias Ringwald } 89*ac726063SMatthias Ringwald 90*ac726063SMatthias Ringwald static avrcp_cover_art_client_t * avrcp_cover_art_client_for_goep_cid(uint16_t goep_cid){ 91*ac726063SMatthias Ringwald btstack_linked_list_iterator_t it; 92*ac726063SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_cover_art_client_connections); 93*ac726063SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 94*ac726063SMatthias Ringwald avrcp_cover_art_client_t * connection = (avrcp_cover_art_client_t *)btstack_linked_list_iterator_next(&it); 95*ac726063SMatthias Ringwald if (connection->goep_cid == goep_cid) { 96*ac726063SMatthias Ringwald return connection; 97*ac726063SMatthias Ringwald }; 98*ac726063SMatthias Ringwald } 99*ac726063SMatthias Ringwald return NULL; 100*ac726063SMatthias Ringwald } 101*ac726063SMatthias Ringwald 102*ac726063SMatthias Ringwald static avrcp_cover_art_client_t * avrcp_cover_art_client_for_avrcp_cid(uint16_t avrcp_cid){ 103*ac726063SMatthias Ringwald btstack_linked_list_iterator_t it; 104*ac726063SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_cover_art_client_connections); 105*ac726063SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 106*ac726063SMatthias Ringwald avrcp_cover_art_client_t * connection = (avrcp_cover_art_client_t *)btstack_linked_list_iterator_next(&it); 107*ac726063SMatthias Ringwald if (connection->avrcp_cid == avrcp_cid) { 108*ac726063SMatthias Ringwald return connection; 109*ac726063SMatthias Ringwald }; 110*ac726063SMatthias Ringwald } 111*ac726063SMatthias Ringwald return NULL; 112*ac726063SMatthias Ringwald } 113*ac726063SMatthias Ringwald 114*ac726063SMatthias Ringwald static avrcp_cover_art_client_t * avrcp_cover_art_client_for_cover_art_cid(uint16_t cover_art_cid){ 115*ac726063SMatthias Ringwald btstack_linked_list_iterator_t it; 116*ac726063SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_cover_art_client_connections); 117*ac726063SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 118*ac726063SMatthias Ringwald avrcp_cover_art_client_t * connection = (avrcp_cover_art_client_t *)btstack_linked_list_iterator_next(&it); 119*ac726063SMatthias Ringwald if (connection->cover_art_cid == cover_art_cid) { 120*ac726063SMatthias Ringwald return connection; 121*ac726063SMatthias Ringwald }; 122*ac726063SMatthias Ringwald } 123*ac726063SMatthias Ringwald return NULL; 124*ac726063SMatthias Ringwald } 125*ac726063SMatthias Ringwald 126*ac726063SMatthias Ringwald static void avrcp_cover_art_client_emit_connection_established(btstack_packet_handler_t packet_handler, uint8_t status, 127*ac726063SMatthias Ringwald bd_addr_t addr, uint16_t avrcp_cid, 128*ac726063SMatthias Ringwald uint16_t cover_art_cid) { 129*ac726063SMatthias Ringwald uint8_t buffer[20]; 130*ac726063SMatthias Ringwald uint16_t size = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &avrcp_cover_art_client_connected, status, addr, avrcp_cid, cover_art_cid); 131*ac726063SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, buffer, size); 132*ac726063SMatthias Ringwald } 133*ac726063SMatthias Ringwald 134*ac726063SMatthias Ringwald static void cover_art_client_emit_operation_complete_event(avrcp_cover_art_client_t * cover_art_client, uint8_t status) { 135*ac726063SMatthias Ringwald uint8_t buffer[20]; 136*ac726063SMatthias Ringwald uint16_t size = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &avrcp_cover_art_client_operation_complete, cover_art_client->cover_art_cid, status); 137*ac726063SMatthias Ringwald (*cover_art_client->packet_handler)(HCI_EVENT_PACKET, 0, buffer, size); 138*ac726063SMatthias Ringwald } 139*ac726063SMatthias Ringwald 140*ac726063SMatthias Ringwald static void avrcp_cover_art_client_emit_connection_released(btstack_packet_handler_t packet_handler, uint16_t cover_art_cid) { 141*ac726063SMatthias Ringwald uint8_t buffer[20]; 142*ac726063SMatthias Ringwald uint16_t size = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &avrcp_cover_art_client_disconnected, cover_art_cid); 143*ac726063SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, buffer, size); 144*ac726063SMatthias Ringwald } 145*ac726063SMatthias Ringwald 146*ac726063SMatthias Ringwald static void avrcp_cover_art_finalize_connection(avrcp_cover_art_client_t *cover_art_client) { 147*ac726063SMatthias Ringwald btstack_assert(cover_art_client != NULL); 148*ac726063SMatthias Ringwald memset(cover_art_client, 0, sizeof(avrcp_cover_art_client_t)); 149*ac726063SMatthias Ringwald btstack_linked_list_remove(&avrcp_cover_art_client_connections, (btstack_linked_item_t *) cover_art_client); 150*ac726063SMatthias Ringwald } 151*ac726063SMatthias Ringwald 152*ac726063SMatthias Ringwald static void avrcp_cover_art_client_parser_callback_connect(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){ 153*ac726063SMatthias Ringwald avrcp_cover_art_client_t * client = (avrcp_cover_art_client_t *) user_data; 154*ac726063SMatthias Ringwald switch (header_id){ 155*ac726063SMatthias Ringwald case OBEX_HEADER_CONNECTION_ID: 156*ac726063SMatthias Ringwald if (obex_parser_header_store(client->obex_header_buffer, sizeof(client->obex_header_buffer), total_len, data_offset, data_buffer, data_len) == OBEX_PARSER_HEADER_COMPLETE){ 157*ac726063SMatthias Ringwald goep_client_set_connection_id(client->goep_cid, big_endian_read_32(client->obex_header_buffer, 0)); 158*ac726063SMatthias Ringwald } 159*ac726063SMatthias Ringwald break; 160*ac726063SMatthias Ringwald default: 161*ac726063SMatthias Ringwald break; 162*ac726063SMatthias Ringwald } 163*ac726063SMatthias Ringwald } 164*ac726063SMatthias Ringwald 165*ac726063SMatthias Ringwald static void avrcp_cover_art_client_prepare_srm_header(avrcp_cover_art_client_t * cover_art_client){ 166*ac726063SMatthias Ringwald if (cover_art_client->flow_control_enabled == false){ 167*ac726063SMatthias Ringwald goep_client_header_add_srm_enable(cover_art_client->goep_cid); 168*ac726063SMatthias Ringwald cover_art_client->srm_state = SRM_W4_CONFIRM; 169*ac726063SMatthias Ringwald } 170*ac726063SMatthias Ringwald } 171*ac726063SMatthias Ringwald 172*ac726063SMatthias Ringwald static void obex_srm_init(avrcp_cover_art_obex_srm_t * obex_srm){ 173*ac726063SMatthias Ringwald obex_srm->srm_value = OBEX_SRM_DISABLE; 174*ac726063SMatthias Ringwald obex_srm->srmp_value = OBEX_SRMP_NEXT; 175*ac726063SMatthias Ringwald } 176*ac726063SMatthias Ringwald 177*ac726063SMatthias Ringwald static void avrcp_cover_art_client_handle_srm_headers(avrcp_cover_art_client_t *context) { 178*ac726063SMatthias Ringwald const avrcp_cover_art_obex_srm_t * obex_srm = &context->obex_srm; 179*ac726063SMatthias Ringwald // Update SRM state based on SRM headers 180*ac726063SMatthias Ringwald switch (context->srm_state){ 181*ac726063SMatthias Ringwald case SRM_W4_CONFIRM: 182*ac726063SMatthias Ringwald switch (obex_srm->srm_value){ 183*ac726063SMatthias Ringwald case OBEX_SRM_ENABLE: 184*ac726063SMatthias Ringwald switch (obex_srm->srmp_value){ 185*ac726063SMatthias Ringwald case OBEX_SRMP_WAIT: 186*ac726063SMatthias Ringwald context->srm_state = SRM_ENABLED_BUT_WAITING; 187*ac726063SMatthias Ringwald break; 188*ac726063SMatthias Ringwald default: 189*ac726063SMatthias Ringwald context->srm_state = SRM_ENABLED; 190*ac726063SMatthias Ringwald break; 191*ac726063SMatthias Ringwald } 192*ac726063SMatthias Ringwald break; 193*ac726063SMatthias Ringwald default: 194*ac726063SMatthias Ringwald context->srm_state = SRM_DISABLED; 195*ac726063SMatthias Ringwald break; 196*ac726063SMatthias Ringwald } 197*ac726063SMatthias Ringwald break; 198*ac726063SMatthias Ringwald case SRM_ENABLED_BUT_WAITING: 199*ac726063SMatthias Ringwald switch (obex_srm->srmp_value){ 200*ac726063SMatthias Ringwald case OBEX_SRMP_WAIT: 201*ac726063SMatthias Ringwald context->srm_state = SRM_ENABLED_BUT_WAITING; 202*ac726063SMatthias Ringwald break; 203*ac726063SMatthias Ringwald default: 204*ac726063SMatthias Ringwald context->srm_state = SRM_ENABLED; 205*ac726063SMatthias Ringwald break; 206*ac726063SMatthias Ringwald } 207*ac726063SMatthias Ringwald break; 208*ac726063SMatthias Ringwald default: 209*ac726063SMatthias Ringwald break; 210*ac726063SMatthias Ringwald } 211*ac726063SMatthias Ringwald log_info("SRM state %u", context->srm_state); 212*ac726063SMatthias Ringwald } 213*ac726063SMatthias Ringwald 214*ac726063SMatthias Ringwald static void avrcp_cover_art_client_parser_callback_get_operation(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){ 215*ac726063SMatthias Ringwald avrcp_cover_art_client_t *client = (avrcp_cover_art_client_t *) user_data; 216*ac726063SMatthias Ringwald switch (header_id) { 217*ac726063SMatthias Ringwald case OBEX_HEADER_SINGLE_RESPONSE_MODE: 218*ac726063SMatthias Ringwald obex_parser_header_store(&client->obex_srm.srm_value, 1, total_len, data_offset, data_buffer, data_len); 219*ac726063SMatthias Ringwald break; 220*ac726063SMatthias Ringwald case OBEX_HEADER_SINGLE_RESPONSE_MODE_PARAMETER: 221*ac726063SMatthias Ringwald obex_parser_header_store(&client->obex_srm.srmp_value, 1, total_len, data_offset, data_buffer, data_len); 222*ac726063SMatthias Ringwald break; 223*ac726063SMatthias Ringwald case OBEX_HEADER_BODY: 224*ac726063SMatthias Ringwald case OBEX_HEADER_END_OF_BODY: 225*ac726063SMatthias Ringwald switch(client->state){ 226*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W4_OBJECT: 227*ac726063SMatthias Ringwald client->packet_handler(BIP_DATA_PACKET, client->cover_art_cid, (uint8_t *) data_buffer, data_len); 228*ac726063SMatthias Ringwald if (data_offset + data_len == total_len){ 229*ac726063SMatthias Ringwald client->flow_wait_for_user = true; 230*ac726063SMatthias Ringwald } 231*ac726063SMatthias Ringwald break; 232*ac726063SMatthias Ringwald default: 233*ac726063SMatthias Ringwald btstack_unreachable(); 234*ac726063SMatthias Ringwald break; 235*ac726063SMatthias Ringwald } 236*ac726063SMatthias Ringwald break; 237*ac726063SMatthias Ringwald default: 238*ac726063SMatthias Ringwald // ignore other headers 239*ac726063SMatthias Ringwald break; 240*ac726063SMatthias Ringwald } 241*ac726063SMatthias Ringwald } 242*ac726063SMatthias Ringwald 243*ac726063SMatthias Ringwald static void avrcp_cover_art_client_prepare_get_operation(avrcp_cover_art_client_t * cover_art_client){ 244*ac726063SMatthias Ringwald obex_parser_init_for_response(&cover_art_client->obex_parser, OBEX_OPCODE_GET, avrcp_cover_art_client_parser_callback_get_operation, cover_art_client); 245*ac726063SMatthias Ringwald obex_srm_init(&cover_art_client->obex_srm); 246*ac726063SMatthias Ringwald cover_art_client->obex_parser_waiting_for_response = true; 247*ac726063SMatthias Ringwald } 248*ac726063SMatthias Ringwald 249*ac726063SMatthias Ringwald static void avrcp_cover_art_client_handle_can_send_now(avrcp_cover_art_client_t * cover_art_client){ 250*ac726063SMatthias Ringwald switch (cover_art_client->state) { 251*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W2_SEND_CONNECT_REQUEST: 252*ac726063SMatthias Ringwald // prepare request 253*ac726063SMatthias Ringwald goep_client_request_create_connect(cover_art_client->goep_cid, OBEX_VERSION, 0, OBEX_MAX_PACKETLEN_DEFAULT); 254*ac726063SMatthias Ringwald goep_client_header_add_target(cover_art_client->goep_cid, avrcp_cover_art_uuid, 16); 255*ac726063SMatthias Ringwald // state 256*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W4_CONNECT_RESPONSE; 257*ac726063SMatthias Ringwald // prepare response 258*ac726063SMatthias Ringwald obex_parser_init_for_response(&cover_art_client->obex_parser, OBEX_OPCODE_CONNECT, 259*ac726063SMatthias Ringwald avrcp_cover_art_client_parser_callback_connect, cover_art_client); 260*ac726063SMatthias Ringwald obex_srm_init(&cover_art_client->obex_srm); 261*ac726063SMatthias Ringwald cover_art_client->obex_parser_waiting_for_response = true; 262*ac726063SMatthias Ringwald // send packet 263*ac726063SMatthias Ringwald goep_client_execute(cover_art_client->goep_cid); 264*ac726063SMatthias Ringwald break; 265*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W2_SEND_GET_OBJECT: 266*ac726063SMatthias Ringwald goep_client_request_create_get(cover_art_client->goep_cid); 267*ac726063SMatthias Ringwald if (cover_art_client->first_request){ 268*ac726063SMatthias Ringwald cover_art_client->first_request = false; 269*ac726063SMatthias Ringwald avrcp_cover_art_client_prepare_srm_header(cover_art_client); 270*ac726063SMatthias Ringwald goep_client_header_add_type(cover_art_client->goep_cid, cover_art_client->object_type); 271*ac726063SMatthias Ringwald if (cover_art_client->image_descriptor != NULL){ 272*ac726063SMatthias Ringwald goep_client_header_add_variable(cover_art_client->goep_cid, OBEX_HEADER_IMG_DESCRIPTOR, (const uint8_t *) cover_art_client->image_descriptor, strlen(cover_art_client->image_descriptor)); 273*ac726063SMatthias Ringwald } 274*ac726063SMatthias Ringwald uint8_t image_handle_len = btstack_max(7, strlen(cover_art_client->image_handle)); 275*ac726063SMatthias Ringwald goep_client_header_add_unicode_prefix(cover_art_client->goep_cid, OBEX_HEADER_IMG_HANDLE, cover_art_client->image_handle, image_handle_len); 276*ac726063SMatthias Ringwald } 277*ac726063SMatthias Ringwald // state 278*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W4_OBJECT; 279*ac726063SMatthias Ringwald cover_art_client->flow_next_triggered = 0; 280*ac726063SMatthias Ringwald cover_art_client->flow_wait_for_user = 0; 281*ac726063SMatthias Ringwald // prepare response 282*ac726063SMatthias Ringwald avrcp_cover_art_client_prepare_get_operation(cover_art_client); 283*ac726063SMatthias Ringwald // send packet 284*ac726063SMatthias Ringwald goep_client_execute(cover_art_client->goep_cid); 285*ac726063SMatthias Ringwald break; 286*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W2_SEND_DISCONNECT_REQUEST: 287*ac726063SMatthias Ringwald // prepare request 288*ac726063SMatthias Ringwald goep_client_request_create_disconnect(cover_art_client->goep_cid); 289*ac726063SMatthias Ringwald // state 290*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W4_DISCONNECT_RESPONSE; 291*ac726063SMatthias Ringwald // prepare response 292*ac726063SMatthias Ringwald obex_parser_init_for_response(&cover_art_client->obex_parser, OBEX_OPCODE_DISCONNECT, NULL, cover_art_client); 293*ac726063SMatthias Ringwald cover_art_client->obex_parser_waiting_for_response = true; 294*ac726063SMatthias Ringwald // send packet 295*ac726063SMatthias Ringwald goep_client_execute(cover_art_client->goep_cid); 296*ac726063SMatthias Ringwald return; 297*ac726063SMatthias Ringwald default: 298*ac726063SMatthias Ringwald break; 299*ac726063SMatthias Ringwald } 300*ac726063SMatthias Ringwald } 301*ac726063SMatthias Ringwald 302*ac726063SMatthias Ringwald static void avrcp_cover_art_goep_event_handler(const uint8_t *packet, uint16_t size) { 303*ac726063SMatthias Ringwald UNUSED(size); 304*ac726063SMatthias Ringwald uint8_t status; 305*ac726063SMatthias Ringwald avrcp_cover_art_client_t * cover_art_client; 306*ac726063SMatthias Ringwald btstack_packet_handler_t packet_handler; 307*ac726063SMatthias Ringwald uint16_t cover_art_cid; 308*ac726063SMatthias Ringwald 309*ac726063SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 310*ac726063SMatthias Ringwald case HCI_EVENT_GOEP_META: 311*ac726063SMatthias Ringwald switch (hci_event_goep_meta_get_subevent_code(packet)){ 312*ac726063SMatthias Ringwald case GOEP_SUBEVENT_CONNECTION_OPENED: 313*ac726063SMatthias Ringwald cover_art_client = avrcp_cover_art_client_for_goep_cid(goep_subevent_connection_opened_get_goep_cid(packet)); 314*ac726063SMatthias Ringwald btstack_assert(cover_art_client != NULL); 315*ac726063SMatthias Ringwald status = goep_subevent_connection_opened_get_status(packet); 316*ac726063SMatthias Ringwald if (status){ 317*ac726063SMatthias Ringwald log_info("connection failed %u", status); 318*ac726063SMatthias Ringwald avrcp_cover_art_finalize_connection(cover_art_client); 319*ac726063SMatthias Ringwald avrcp_cover_art_client_emit_connection_established(cover_art_client->packet_handler, status, 320*ac726063SMatthias Ringwald cover_art_client->addr, 321*ac726063SMatthias Ringwald cover_art_client->avrcp_cid, 322*ac726063SMatthias Ringwald cover_art_client->cover_art_cid); 323*ac726063SMatthias Ringwald } else { 324*ac726063SMatthias Ringwald log_info("connection established"); 325*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W2_SEND_CONNECT_REQUEST; 326*ac726063SMatthias Ringwald goep_client_request_can_send_now(cover_art_client->goep_cid); 327*ac726063SMatthias Ringwald } 328*ac726063SMatthias Ringwald break; 329*ac726063SMatthias Ringwald case GOEP_SUBEVENT_CONNECTION_CLOSED: 330*ac726063SMatthias Ringwald cover_art_client = avrcp_cover_art_client_for_goep_cid(goep_subevent_connection_opened_get_goep_cid(packet)); 331*ac726063SMatthias Ringwald btstack_assert(cover_art_client != NULL); 332*ac726063SMatthias Ringwald if (cover_art_client->state > AVRCP_COVER_ART_CONNECTED){ 333*ac726063SMatthias Ringwald cover_art_client_emit_operation_complete_event(cover_art_client, OBEX_DISCONNECTED); 334*ac726063SMatthias Ringwald } 335*ac726063SMatthias Ringwald cover_art_cid = cover_art_client->cover_art_cid; 336*ac726063SMatthias Ringwald packet_handler = cover_art_client->packet_handler; 337*ac726063SMatthias Ringwald avrcp_cover_art_finalize_connection(cover_art_client); 338*ac726063SMatthias Ringwald avrcp_cover_art_client_emit_connection_released(packet_handler, cover_art_cid); 339*ac726063SMatthias Ringwald break; 340*ac726063SMatthias Ringwald case GOEP_SUBEVENT_CAN_SEND_NOW: 341*ac726063SMatthias Ringwald cover_art_client = avrcp_cover_art_client_for_goep_cid(goep_subevent_can_send_now_get_goep_cid(packet)); 342*ac726063SMatthias Ringwald btstack_assert(cover_art_client != NULL); 343*ac726063SMatthias Ringwald avrcp_cover_art_client_handle_can_send_now(cover_art_client); 344*ac726063SMatthias Ringwald break; 345*ac726063SMatthias Ringwald default: 346*ac726063SMatthias Ringwald break; 347*ac726063SMatthias Ringwald } 348*ac726063SMatthias Ringwald break; 349*ac726063SMatthias Ringwald default: 350*ac726063SMatthias Ringwald break; 351*ac726063SMatthias Ringwald } 352*ac726063SMatthias Ringwald } 353*ac726063SMatthias Ringwald 354*ac726063SMatthias Ringwald static void avrcp_cover_art_client_goep_data_handler(avrcp_cover_art_client_t * cover_art_client, uint8_t *packet, uint16_t size){ 355*ac726063SMatthias Ringwald btstack_assert(cover_art_client->obex_parser_waiting_for_response); 356*ac726063SMatthias Ringwald 357*ac726063SMatthias Ringwald obex_parser_object_state_t parser_state; 358*ac726063SMatthias Ringwald parser_state = obex_parser_process_data(&cover_art_client->obex_parser, packet, size); 359*ac726063SMatthias Ringwald if (parser_state == OBEX_PARSER_OBJECT_STATE_COMPLETE){ 360*ac726063SMatthias Ringwald cover_art_client->obex_parser_waiting_for_response = false; 361*ac726063SMatthias Ringwald obex_parser_operation_info_t op_info; 362*ac726063SMatthias Ringwald obex_parser_get_operation_info(&cover_art_client->obex_parser, &op_info); 363*ac726063SMatthias Ringwald switch (cover_art_client->state){ 364*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W4_CONNECT_RESPONSE: 365*ac726063SMatthias Ringwald switch (op_info.response_code) { 366*ac726063SMatthias Ringwald case OBEX_RESP_SUCCESS: 367*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_CONNECTED; 368*ac726063SMatthias Ringwald avrcp_cover_art_client_emit_connection_established(cover_art_client->packet_handler, 369*ac726063SMatthias Ringwald ERROR_CODE_SUCCESS, 370*ac726063SMatthias Ringwald cover_art_client->addr, 371*ac726063SMatthias Ringwald cover_art_client->avrcp_cid, 372*ac726063SMatthias Ringwald cover_art_client->cover_art_cid); 373*ac726063SMatthias Ringwald break; 374*ac726063SMatthias Ringwald default: 375*ac726063SMatthias Ringwald log_info("pbap: obex connect failed, result 0x%02x", packet[0]); 376*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_INIT; 377*ac726063SMatthias Ringwald avrcp_cover_art_client_emit_connection_established(cover_art_client->packet_handler, 378*ac726063SMatthias Ringwald OBEX_CONNECT_FAILED, 379*ac726063SMatthias Ringwald cover_art_client->addr, 380*ac726063SMatthias Ringwald cover_art_client->avrcp_cid, 381*ac726063SMatthias Ringwald cover_art_client->cover_art_cid); 382*ac726063SMatthias Ringwald break; 383*ac726063SMatthias Ringwald } 384*ac726063SMatthias Ringwald break; 385*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W4_OBJECT: 386*ac726063SMatthias Ringwald switch (op_info.response_code) { 387*ac726063SMatthias Ringwald case OBEX_RESP_CONTINUE: 388*ac726063SMatthias Ringwald avrcp_cover_art_client_handle_srm_headers(cover_art_client); 389*ac726063SMatthias Ringwald if (cover_art_client->srm_state == SRM_ENABLED) { 390*ac726063SMatthias Ringwald // prepare response 391*ac726063SMatthias Ringwald avrcp_cover_art_client_prepare_get_operation(cover_art_client); 392*ac726063SMatthias Ringwald break; 393*ac726063SMatthias Ringwald } 394*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W2_SEND_GET_OBJECT; 395*ac726063SMatthias Ringwald if (!cover_art_client->flow_control_enabled || !cover_art_client->flow_wait_for_user || 396*ac726063SMatthias Ringwald cover_art_client->flow_next_triggered) { 397*ac726063SMatthias Ringwald goep_client_request_can_send_now(cover_art_client->goep_cid); 398*ac726063SMatthias Ringwald } 399*ac726063SMatthias Ringwald break; 400*ac726063SMatthias Ringwald case OBEX_RESP_SUCCESS: 401*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_CONNECTED; 402*ac726063SMatthias Ringwald cover_art_client_emit_operation_complete_event(cover_art_client, ERROR_CODE_SUCCESS); 403*ac726063SMatthias Ringwald break; 404*ac726063SMatthias Ringwald default: 405*ac726063SMatthias Ringwald log_info("unexpected response 0x%02x", packet[0]); 406*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_CONNECTED; 407*ac726063SMatthias Ringwald cover_art_client_emit_operation_complete_event(cover_art_client, OBEX_UNKNOWN_ERROR); 408*ac726063SMatthias Ringwald break; 409*ac726063SMatthias Ringwald } 410*ac726063SMatthias Ringwald break; 411*ac726063SMatthias Ringwald case AVRCP_COVER_ART_W4_DISCONNECT_RESPONSE: 412*ac726063SMatthias Ringwald goep_client_disconnect(cover_art_client->goep_cid); 413*ac726063SMatthias Ringwald break; 414*ac726063SMatthias Ringwald default: 415*ac726063SMatthias Ringwald btstack_unreachable(); 416*ac726063SMatthias Ringwald break; 417*ac726063SMatthias Ringwald } 418*ac726063SMatthias Ringwald } 419*ac726063SMatthias Ringwald } 420*ac726063SMatthias Ringwald 421*ac726063SMatthias Ringwald static void avrcp_cover_art_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 422*ac726063SMatthias Ringwald UNUSED(channel); // ok: there is no channel 423*ac726063SMatthias Ringwald UNUSED(size); // ok: handling own goep events 424*ac726063SMatthias Ringwald avrcp_cover_art_client_t * cover_art_client; 425*ac726063SMatthias Ringwald switch (packet_type){ 426*ac726063SMatthias Ringwald case HCI_EVENT_PACKET: 427*ac726063SMatthias Ringwald avrcp_cover_art_goep_event_handler(packet, size); 428*ac726063SMatthias Ringwald break; 429*ac726063SMatthias Ringwald case GOEP_DATA_PACKET: 430*ac726063SMatthias Ringwald cover_art_client = avrcp_cover_art_client_for_goep_cid(channel); 431*ac726063SMatthias Ringwald btstack_assert(cover_art_client != NULL); 432*ac726063SMatthias Ringwald avrcp_cover_art_client_goep_data_handler(cover_art_client, packet, size); 433*ac726063SMatthias Ringwald break; 434*ac726063SMatthias Ringwald default: 435*ac726063SMatthias Ringwald break; 436*ac726063SMatthias Ringwald } 437*ac726063SMatthias Ringwald } 438*ac726063SMatthias Ringwald 439*ac726063SMatthias Ringwald static uint8_t avrcp_cover_art_client_setup_connection(avrcp_cover_art_client_t * cover_art_client, uint16_t l2cap_psm){ 440*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W4_GOEP_CONNECTION; 441*ac726063SMatthias Ringwald return goep_client_connect_l2cap(&cover_art_client->goep_client, 442*ac726063SMatthias Ringwald (l2cap_ertm_config_t *) cover_art_client->ertm_config, 443*ac726063SMatthias Ringwald cover_art_client->ertm_buffer, 444*ac726063SMatthias Ringwald cover_art_client->ertm_buffer_size, 445*ac726063SMatthias Ringwald &avrcp_cover_art_packet_handler, 446*ac726063SMatthias Ringwald cover_art_client->addr, 447*ac726063SMatthias Ringwald l2cap_psm, 448*ac726063SMatthias Ringwald &cover_art_client->goep_cid); 449*ac726063SMatthias Ringwald } 450*ac726063SMatthias Ringwald 451*ac726063SMatthias Ringwald static void avrcp_cover_art_handle_sdp_query_complete(avrcp_connection_t * connection, uint8_t status){ 452*ac726063SMatthias Ringwald avrcp_cover_art_client_t * cover_art_client = avrcp_cover_art_client_for_avrcp_cid(connection->avrcp_cid); 453*ac726063SMatthias Ringwald 454*ac726063SMatthias Ringwald if (cover_art_client == NULL) { 455*ac726063SMatthias Ringwald return; 456*ac726063SMatthias Ringwald } 457*ac726063SMatthias Ringwald if (cover_art_client->state != AVRCP_COVER_ART_W4_SDP_QUERY_COMPLETE){ 458*ac726063SMatthias Ringwald return; 459*ac726063SMatthias Ringwald } 460*ac726063SMatthias Ringwald 461*ac726063SMatthias Ringwald // l2cap available? 462*ac726063SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 463*ac726063SMatthias Ringwald if (connection->cover_art_psm == 0){ 464*ac726063SMatthias Ringwald status = SDP_SERVICE_NOT_FOUND; 465*ac726063SMatthias Ringwald } 466*ac726063SMatthias Ringwald } 467*ac726063SMatthias Ringwald 468*ac726063SMatthias Ringwald if (status == ERROR_CODE_SUCCESS) { 469*ac726063SMatthias Ringwald // ready to connect 470*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W2_GOEP_CONNECT; 471*ac726063SMatthias Ringwald avrcp_cover_art_client_setup_connection(cover_art_client, connection->cover_art_psm); 472*ac726063SMatthias Ringwald } else { 473*ac726063SMatthias Ringwald btstack_packet_handler_t packet_handler = cover_art_client->packet_handler; 474*ac726063SMatthias Ringwald uint16_t cover_art_cid = cover_art_client->cover_art_cid; 475*ac726063SMatthias Ringwald uint16_t avrcp_cid = cover_art_client->avrcp_cid; 476*ac726063SMatthias Ringwald avrcp_cover_art_finalize_connection(cover_art_client); 477*ac726063SMatthias Ringwald avrcp_cover_art_client_emit_connection_established(packet_handler, status, connection->remote_addr, 478*ac726063SMatthias Ringwald avrcp_cid, cover_art_cid); 479*ac726063SMatthias Ringwald } 480*ac726063SMatthias Ringwald } 481*ac726063SMatthias Ringwald 482*ac726063SMatthias Ringwald void avrcp_cover_art_client_init(void){ 483*ac726063SMatthias Ringwald avrcp_register_cover_art_sdp_query_complete_handler(&avrcp_cover_art_handle_sdp_query_complete); 484*ac726063SMatthias Ringwald } 485*ac726063SMatthias Ringwald 486*ac726063SMatthias Ringwald uint8_t 487*ac726063SMatthias Ringwald avrcp_cover_art_client_connect(avrcp_cover_art_client_t *cover_art_client, btstack_packet_handler_t packet_handler, 488*ac726063SMatthias Ringwald bd_addr_t remote_addr, uint8_t *ertm_buffer, uint32_t ertm_buffer_size, 489*ac726063SMatthias Ringwald const l2cap_ertm_config_t *ertm_config, uint16_t *avrcp_cover_art_cid) { 490*ac726063SMatthias Ringwald 491*ac726063SMatthias Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 492*ac726063SMatthias Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 493*ac726063SMatthias Ringwald if ((connection_target == NULL) || (connection_controller == NULL)){ 494*ac726063SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 495*ac726063SMatthias Ringwald } 496*ac726063SMatthias Ringwald 497*ac726063SMatthias Ringwald cover_art_client->cover_art_cid = avrcp_cover_art_client_next_cid(); 498*ac726063SMatthias Ringwald memcpy(cover_art_client->addr, remote_addr, 6); 499*ac726063SMatthias Ringwald cover_art_client->avrcp_cid = connection_controller->avrcp_cid; 500*ac726063SMatthias Ringwald cover_art_client->packet_handler = packet_handler; 501*ac726063SMatthias Ringwald cover_art_client->flow_control_enabled = false; 502*ac726063SMatthias Ringwald 503*ac726063SMatthias Ringwald // store ERTM config 504*ac726063SMatthias Ringwald cover_art_client->ertm_config = ertm_config; 505*ac726063SMatthias Ringwald cover_art_client->ertm_buffer = ertm_buffer; 506*ac726063SMatthias Ringwald cover_art_client->ertm_buffer_size = ertm_buffer_size; 507*ac726063SMatthias Ringwald 508*ac726063SMatthias Ringwald if (avrcp_cover_art_cid != NULL){ 509*ac726063SMatthias Ringwald *avrcp_cover_art_cid = cover_art_client->cover_art_cid; 510*ac726063SMatthias Ringwald } 511*ac726063SMatthias Ringwald 512*ac726063SMatthias Ringwald btstack_linked_list_add(&avrcp_cover_art_client_connections, (btstack_linked_item_t *) cover_art_client); 513*ac726063SMatthias Ringwald 514*ac726063SMatthias Ringwald if (connection_controller->cover_art_psm == 0){ 515*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W4_SDP_QUERY_COMPLETE; 516*ac726063SMatthias Ringwald avrcp_trigger_sdp_query(connection_controller, connection_controller); 517*ac726063SMatthias Ringwald return ERROR_CODE_SUCCESS; 518*ac726063SMatthias Ringwald } else { 519*ac726063SMatthias Ringwald return avrcp_cover_art_client_setup_connection(cover_art_client, connection_controller->cover_art_psm); 520*ac726063SMatthias Ringwald } 521*ac726063SMatthias Ringwald } 522*ac726063SMatthias Ringwald 523*ac726063SMatthias Ringwald static uint8_t avrcp_cover_art_client_get_object(uint16_t avrcp_cover_art_cid, const char * object_type, const char * image_handle, const char * image_descriptor){ 524*ac726063SMatthias Ringwald avrcp_cover_art_client_t * cover_art_client = avrcp_cover_art_client_for_cover_art_cid(avrcp_cover_art_cid); 525*ac726063SMatthias Ringwald if (cover_art_client == NULL){ 526*ac726063SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 527*ac726063SMatthias Ringwald } 528*ac726063SMatthias Ringwald if (cover_art_client->state != AVRCP_COVER_ART_CONNECTED){ 529*ac726063SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 530*ac726063SMatthias Ringwald } 531*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W2_SEND_GET_OBJECT; 532*ac726063SMatthias Ringwald cover_art_client->first_request = true; 533*ac726063SMatthias Ringwald cover_art_client->image_handle = image_handle; 534*ac726063SMatthias Ringwald cover_art_client->image_descriptor = image_descriptor; 535*ac726063SMatthias Ringwald cover_art_client->object_type = object_type; 536*ac726063SMatthias Ringwald goep_client_request_can_send_now(cover_art_client->goep_cid); 537*ac726063SMatthias Ringwald return ERROR_CODE_SUCCESS; 538*ac726063SMatthias Ringwald } 539*ac726063SMatthias Ringwald 540*ac726063SMatthias Ringwald uint8_t avrcp_cover_art_client_get_linked_thumbnail(uint16_t avrcp_cover_art_cid, const char * image_handle){ 541*ac726063SMatthias Ringwald return avrcp_cover_art_client_get_object(avrcp_cover_art_cid, 542*ac726063SMatthias Ringwald avrcp_cover_art_linked_thumbnail_type, 543*ac726063SMatthias Ringwald image_handle, 544*ac726063SMatthias Ringwald NULL); 545*ac726063SMatthias Ringwald } 546*ac726063SMatthias Ringwald 547*ac726063SMatthias Ringwald uint8_t avrcp_cover_art_client_get_image(uint16_t avrcp_cover_art_cid, const char * image_handle, const char * image_descriptor){ 548*ac726063SMatthias Ringwald return avrcp_cover_art_client_get_object(avrcp_cover_art_cid, 549*ac726063SMatthias Ringwald avrcp_cover_art_image_type, 550*ac726063SMatthias Ringwald image_handle, 551*ac726063SMatthias Ringwald image_descriptor); 552*ac726063SMatthias Ringwald } 553*ac726063SMatthias Ringwald 554*ac726063SMatthias Ringwald uint8_t avrcp_cover_art_client_get_image_properties(uint16_t avrcp_cover_art_cid, const char * image_handle){ 555*ac726063SMatthias Ringwald return avrcp_cover_art_client_get_object(avrcp_cover_art_cid, 556*ac726063SMatthias Ringwald avrcp_cover_art_image_properties_type, 557*ac726063SMatthias Ringwald image_handle, 558*ac726063SMatthias Ringwald NULL); 559*ac726063SMatthias Ringwald } 560*ac726063SMatthias Ringwald 561*ac726063SMatthias Ringwald uint8_t avrcp_cover_art_client_disconnect(uint16_t avrcp_cover_art_cid){ 562*ac726063SMatthias Ringwald avrcp_cover_art_client_t * cover_art_client = avrcp_cover_art_client_for_cover_art_cid(avrcp_cover_art_cid); 563*ac726063SMatthias Ringwald if (cover_art_client == NULL){ 564*ac726063SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 565*ac726063SMatthias Ringwald } 566*ac726063SMatthias Ringwald if (cover_art_client->state < AVRCP_COVER_ART_CONNECTED){ 567*ac726063SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 568*ac726063SMatthias Ringwald } 569*ac726063SMatthias Ringwald cover_art_client->state = AVRCP_COVER_ART_W2_SEND_DISCONNECT_REQUEST; 570*ac726063SMatthias Ringwald goep_client_request_can_send_now(cover_art_client->goep_cid); 571*ac726063SMatthias Ringwald return ERROR_CODE_SUCCESS; 572*ac726063SMatthias Ringwald } 573*ac726063SMatthias Ringwald 574*ac726063SMatthias Ringwald void avrcp_cover_art_client_deinit(void){ 575*ac726063SMatthias Ringwald avrcp_cover_art_client_connections = NULL; 576*ac726063SMatthias Ringwald } 577*ac726063SMatthias Ringwald 578*ac726063SMatthias Ringwald #endif /* ENABLE_AVRCP_COVER_ART */ 579