xref: /btstack/src/classic/avrcp.c (revision 235946f152c66eb4ba735043adb492f7a538d15c)
1be32e7f1SMilanka Ringwald /*
2be32e7f1SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3be32e7f1SMilanka Ringwald  *
4be32e7f1SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5be32e7f1SMilanka Ringwald  * modification, are permitted provided that the following conditions
6be32e7f1SMilanka Ringwald  * are met:
7be32e7f1SMilanka Ringwald  *
8be32e7f1SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9be32e7f1SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10be32e7f1SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11be32e7f1SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12be32e7f1SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13be32e7f1SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14be32e7f1SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15be32e7f1SMilanka Ringwald  *    from this software without specific prior written permission.
16be32e7f1SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17be32e7f1SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18be32e7f1SMilanka Ringwald  *    monetary gain.
19be32e7f1SMilanka Ringwald  *
20be32e7f1SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21be32e7f1SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22be32e7f1SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23be32e7f1SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24be32e7f1SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25be32e7f1SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26be32e7f1SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27be32e7f1SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28be32e7f1SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29be32e7f1SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30be32e7f1SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31be32e7f1SMilanka Ringwald  * SUCH DAMAGE.
32be32e7f1SMilanka Ringwald  *
33be32e7f1SMilanka Ringwald  * Please inquire about commercial licensing options at
34be32e7f1SMilanka Ringwald  * [email protected]
35be32e7f1SMilanka Ringwald  *
36be32e7f1SMilanka Ringwald  */
37be32e7f1SMilanka Ringwald 
38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "avrcp.c"
39ab2c6ae4SMatthias Ringwald 
40be32e7f1SMilanka Ringwald #include <stdint.h>
41be32e7f1SMilanka Ringwald #include <stdio.h>
42be32e7f1SMilanka Ringwald #include <stdlib.h>
43be32e7f1SMilanka Ringwald #include <string.h>
44be32e7f1SMilanka Ringwald #include <unistd.h>
45be32e7f1SMilanka Ringwald 
46be32e7f1SMilanka Ringwald #include "btstack.h"
47be32e7f1SMilanka Ringwald #include "classic/avrcp.h"
48be32e7f1SMilanka Ringwald 
49be32e7f1SMilanka Ringwald #define AV_REMOTE_CONTROL_TARGET        0x110C
50be32e7f1SMilanka Ringwald #define AV_REMOTE_CONTROL               0x110E
51be32e7f1SMilanka Ringwald #define AV_REMOTE_CONTROL_CONTROLLER    0x110F
52be32e7f1SMilanka Ringwald 
53*235946f1SMatthias Ringwald #define PSM_AVCTP                       BLUETOOTH_PROTOCOL_AVCTP
54be32e7f1SMilanka Ringwald #define PSM_AVCTP_BROWSING              0xFF17
55be32e7f1SMilanka Ringwald 
56be32e7f1SMilanka Ringwald /*
57be32e7f1SMilanka Ringwald Category 1: Player/Recorder
58be32e7f1SMilanka Ringwald Category 2: Monitor/Amplifier
59be32e7f1SMilanka Ringwald Category 3: Tuner
60be32e7f1SMilanka Ringwald Category 4: Menu
61be32e7f1SMilanka Ringwald */
62be32e7f1SMilanka Ringwald 
63be32e7f1SMilanka Ringwald /* controller supported features
64be32e7f1SMilanka Ringwald Bit 0 = Category 1
65be32e7f1SMilanka Ringwald Bit 1 = Category 2
66be32e7f1SMilanka Ringwald Bit 2 = Category 3
67be32e7f1SMilanka Ringwald Bit 3 = Category 4
68be32e7f1SMilanka Ringwald Bit 4-5 = RFA
69be32e7f1SMilanka Ringwald Bit 6 = Supports browsing
70be32e7f1SMilanka Ringwald Bit 7-15 = RFA
71be32e7f1SMilanka Ringwald The bits for supported categories are set to 1. Others are set to 0.
72be32e7f1SMilanka Ringwald */
73be32e7f1SMilanka Ringwald 
74be32e7f1SMilanka Ringwald /* target supported features
75be32e7f1SMilanka Ringwald Bit 0 = Category 1
76be32e7f1SMilanka Ringwald Bit 1 = Category 2
77be32e7f1SMilanka Ringwald Bit 2 = Category 3
78be32e7f1SMilanka Ringwald Bit 3 = Category 4
79be32e7f1SMilanka Ringwald Bit 4 = Player Application Settings. Bit 0 should be set for this bit to be set.
80be32e7f1SMilanka Ringwald Bit 5 = Group Navigation. Bit 0 should be set for this bit to be set.
81be32e7f1SMilanka Ringwald Bit 6 = Supports browsing*4
82be32e7f1SMilanka Ringwald Bit 7 = Supports multiple media player applications
83be32e7f1SMilanka Ringwald Bit 8-15 = RFA
84be32e7f1SMilanka Ringwald The bits for supported categories are set to 1. Others are set to 0.
85be32e7f1SMilanka Ringwald */
86be32e7f1SMilanka Ringwald 
87be32e7f1SMilanka Ringwald // TODO: merge with avdtp_packet_type_t
88be32e7f1SMilanka Ringwald typedef enum {
89be32e7f1SMilanka Ringwald     AVRCP_SINGLE_PACKET= 0,
90be32e7f1SMilanka Ringwald     AVRCP_START_PACKET    ,
91be32e7f1SMilanka Ringwald     AVRCP_CONTINUE_PACKET ,
92be32e7f1SMilanka Ringwald     AVRCP_END_PACKET
93be32e7f1SMilanka Ringwald } avrcp_packet_type_t;
94be32e7f1SMilanka Ringwald 
95be32e7f1SMilanka Ringwald typedef enum {
96be32e7f1SMilanka Ringwald     AVRCP_COMMAND_FRAME = 0,
97be32e7f1SMilanka Ringwald     AVRCP_RESPONSE_FRAME
98be32e7f1SMilanka Ringwald } avrcp_frame_type_t;
99be32e7f1SMilanka Ringwald 
100be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service";
101be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider";
102be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_name = "BTstack AVRCP Target Service";
103be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP Target Service Provider";
104be32e7f1SMilanka Ringwald 
105be32e7f1SMilanka Ringwald static btstack_linked_list_t avrcp_connections;
106be32e7f1SMilanka Ringwald static btstack_packet_handler_t avrcp_callback;
107be32e7f1SMilanka Ringwald 
108be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = {
109be32e7f1SMilanka Ringwald     "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER",
110be32e7f1SMilanka Ringwald     "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE",
111be32e7f1SMilanka Ringwald     "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES",
112be32e7f1SMilanka Ringwald     "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR"
113be32e7f1SMilanka Ringwald };
114be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){
115be32e7f1SMilanka Ringwald     if (index <= 11) return avrcp_subunit_type_name[index];
116be32e7f1SMilanka Ringwald     if (index >= 0x1C && index <= 0x1F) return avrcp_subunit_type_name[index - 0x10];
117be32e7f1SMilanka Ringwald     return avrcp_subunit_type_name[16];
118be32e7f1SMilanka Ringwald }
119be32e7f1SMilanka Ringwald 
120be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = {
121be32e7f1SMilanka Ringwald     "ERROR", "PLAYBACK_STATUS_CHANGED",
122be32e7f1SMilanka Ringwald     "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START",
123be32e7f1SMilanka Ringwald     "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED",
124be32e7f1SMilanka Ringwald     "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED",
125be32e7f1SMilanka Ringwald     "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED"
126be32e7f1SMilanka Ringwald };
127be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){
128be32e7f1SMilanka Ringwald     if (index <= 0x0d) return avrcp_event_name[index];
129be32e7f1SMilanka Ringwald     return avrcp_event_name[0];
130be32e7f1SMilanka Ringwald }
131be32e7f1SMilanka Ringwald 
132be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = {
133be32e7f1SMilanka Ringwald     "NOT SUPPORTED", // 0x3B
134be32e7f1SMilanka Ringwald     "SKIP", "NOT SUPPORTED", "NOT SUPPORTED", "NOT SUPPORTED", "NOT SUPPORTED",
135be32e7f1SMilanka Ringwald     "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", "NOT SUPPORTED",
136be32e7f1SMilanka Ringwald     "REWIND", "FAST_FORWARD", "NOT SUPPORTED", "FORWARD", "BACKWARD" // 0x4C
137be32e7f1SMilanka Ringwald };
138be32e7f1SMilanka Ringwald const char * avrcp_operation2str(uint8_t index){
139be32e7f1SMilanka Ringwald     if (index >= 0x3B && index <= 0x4C) return avrcp_operation_name[index - 0x3B];
140be32e7f1SMilanka Ringwald     return avrcp_operation_name[0];
141be32e7f1SMilanka Ringwald }
142be32e7f1SMilanka Ringwald 
143be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = {
144be32e7f1SMilanka Ringwald     "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH"
145be32e7f1SMilanka Ringwald };
146be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){
147be32e7f1SMilanka Ringwald     if (index >= 1 && index <= 7) return avrcp_media_attribute_id_name[index];
148be32e7f1SMilanka Ringwald     return avrcp_media_attribute_id_name[0];
149be32e7f1SMilanka Ringwald }
150be32e7f1SMilanka Ringwald 
151be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = {
152be32e7f1SMilanka Ringwald     "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK",
153be32e7f1SMilanka Ringwald     "ERROR" // 0xFF
154be32e7f1SMilanka Ringwald };
155be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){
156be32e7f1SMilanka Ringwald     if (index >= 1 && index <= 4) return avrcp_play_status_name[index];
157be32e7f1SMilanka Ringwald     return avrcp_play_status_name[5];
158be32e7f1SMilanka Ringwald }
159be32e7f1SMilanka Ringwald 
160be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = {
161be32e7f1SMilanka Ringwald     "CONTROL",
162be32e7f1SMilanka Ringwald     "STATUS",
163be32e7f1SMilanka Ringwald     "SPECIFIC_INQUIRY",
164be32e7f1SMilanka Ringwald     "NOTIFY",
165be32e7f1SMilanka Ringwald     "GENERAL_INQUIRY",
166be32e7f1SMilanka Ringwald     "RESERVED5",
167be32e7f1SMilanka Ringwald     "RESERVED6",
168be32e7f1SMilanka Ringwald     "RESERVED7",
169be32e7f1SMilanka Ringwald     "NOT_IMPLEMENTED",
170be32e7f1SMilanka Ringwald     "ACCEPTED",
171be32e7f1SMilanka Ringwald     "REJECTED",
172be32e7f1SMilanka Ringwald     "IN_TRANSITION",
173be32e7f1SMilanka Ringwald     "IMPLEMENTED_STABLE",
174be32e7f1SMilanka Ringwald     "CHANGED_STABLE",
175be32e7f1SMilanka Ringwald     "RESERVED",
176be32e7f1SMilanka Ringwald     "INTERIM"
177be32e7f1SMilanka Ringwald };
178be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){
179be32e7f1SMilanka Ringwald     if (index >= 0 && index < sizeof(avrcp_ctype_name)){
180be32e7f1SMilanka Ringwald         return avrcp_ctype_name[index];
181be32e7f1SMilanka Ringwald     }
182be32e7f1SMilanka Ringwald     return "NONE";
183be32e7f1SMilanka Ringwald }
184be32e7f1SMilanka Ringwald 
185be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = {
186be32e7f1SMilanka Ringwald     "SHUFFLE OFF",
187be32e7f1SMilanka Ringwald     "SHUFFLE ALL TRACKS",
188be32e7f1SMilanka Ringwald     "SHUFFLE GROUP"
189be32e7f1SMilanka Ringwald };
190be32e7f1SMilanka Ringwald 
191be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){
192be32e7f1SMilanka Ringwald     if (index >= 1 && index <= 3) return avrcp_shuffle_mode_name[index-1];
193be32e7f1SMilanka Ringwald     return "NONE";
194be32e7f1SMilanka Ringwald }
195be32e7f1SMilanka Ringwald 
196be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = {
197be32e7f1SMilanka Ringwald     "REPEAT OFF",
198be32e7f1SMilanka Ringwald     "REPEAT SINGLE TRACK",
199be32e7f1SMilanka Ringwald     "REPEAT ALL TRACKS",
200be32e7f1SMilanka Ringwald     "REPEAT GROUP"
201be32e7f1SMilanka Ringwald };
202be32e7f1SMilanka Ringwald 
203be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){
204be32e7f1SMilanka Ringwald     if (index >= 1 && index <= 4) return avrcp_repeat_mode_name[index-1];
205be32e7f1SMilanka Ringwald     return "NONE";
206be32e7f1SMilanka Ringwald }
207be32e7f1SMilanka Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
208be32e7f1SMilanka Ringwald 
209be32e7f1SMilanka Ringwald static void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name){
210be32e7f1SMilanka Ringwald     uint8_t* attribute;
211be32e7f1SMilanka Ringwald     de_create_sequence(service);
212be32e7f1SMilanka Ringwald 
213be32e7f1SMilanka Ringwald     // 0x0000 "Service Record Handle"
214*235946f1SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
215be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
216be32e7f1SMilanka Ringwald 
217be32e7f1SMilanka Ringwald     // 0x0001 "Service Class ID List"
218*235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
219be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
220be32e7f1SMilanka Ringwald     {
221be32e7f1SMilanka Ringwald         if (controller){
222be32e7f1SMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, AV_REMOTE_CONTROL);
223be32e7f1SMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, AV_REMOTE_CONTROL_CONTROLLER);
224be32e7f1SMilanka Ringwald         } else {
225be32e7f1SMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, AV_REMOTE_CONTROL_TARGET);
226be32e7f1SMilanka Ringwald         }
227be32e7f1SMilanka Ringwald     }
228be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
229be32e7f1SMilanka Ringwald 
230be32e7f1SMilanka Ringwald     // 0x0004 "Protocol Descriptor List"
231*235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
232be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
233be32e7f1SMilanka Ringwald     {
234be32e7f1SMilanka Ringwald         uint8_t* l2cpProtocol = de_push_sequence(attribute);
235be32e7f1SMilanka Ringwald         {
236*235946f1SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
237*235946f1SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);
238be32e7f1SMilanka Ringwald         }
239be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, l2cpProtocol);
240be32e7f1SMilanka Ringwald 
241be32e7f1SMilanka Ringwald         uint8_t* avctpProtocol = de_push_sequence(attribute);
242be32e7f1SMilanka Ringwald         {
243*235946f1SMatthias Ringwald             de_add_number(avctpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);  // avctpProtocol_service
244be32e7f1SMilanka Ringwald             de_add_number(avctpProtocol,  DE_UINT, DE_SIZE_16,  0x0103);    // version
245be32e7f1SMilanka Ringwald         }
246be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, avctpProtocol);
247be32e7f1SMilanka Ringwald 
248be32e7f1SMilanka Ringwald         if (browsing){
249*235946f1SMatthias Ringwald             de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
250be32e7f1SMilanka Ringwald             attribute = de_push_sequence(service);
251be32e7f1SMilanka Ringwald             {
252be32e7f1SMilanka Ringwald                 uint8_t* browsing_l2cpProtocol = de_push_sequence(attribute);
253be32e7f1SMilanka Ringwald                 {
254*235946f1SMatthias Ringwald                     de_add_number(browsing_l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
255be32e7f1SMilanka Ringwald                     de_add_number(browsing_l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_AVCTP_BROWSING);
256be32e7f1SMilanka Ringwald                 }
257be32e7f1SMilanka Ringwald                 de_pop_sequence(attribute, browsing_l2cpProtocol);
258be32e7f1SMilanka Ringwald 
259be32e7f1SMilanka Ringwald                 uint8_t* browsing_avctpProtocol = de_push_sequence(attribute);
260be32e7f1SMilanka Ringwald                 {
261*235946f1SMatthias Ringwald                     de_add_number(browsing_avctpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);  // browsing_avctpProtocol_service
262be32e7f1SMilanka Ringwald                     de_add_number(browsing_avctpProtocol,  DE_UINT, DE_SIZE_16,  0x0103);    // version
263be32e7f1SMilanka Ringwald                 }
264be32e7f1SMilanka Ringwald                 de_pop_sequence(attribute, browsing_avctpProtocol);
265be32e7f1SMilanka Ringwald             }
266be32e7f1SMilanka Ringwald             de_pop_sequence(service, attribute);
267be32e7f1SMilanka Ringwald         }
268be32e7f1SMilanka Ringwald     }
269be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
270be32e7f1SMilanka Ringwald 
271be32e7f1SMilanka Ringwald     // 0x0005 "Public Browse Group"
272*235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
273be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
274be32e7f1SMilanka Ringwald     {
275*235946f1SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
276be32e7f1SMilanka Ringwald     }
277be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
278be32e7f1SMilanka Ringwald 
279be32e7f1SMilanka Ringwald     // 0x0009 "Bluetooth Profile Descriptor List"
280*235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
281be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
282be32e7f1SMilanka Ringwald     {
283be32e7f1SMilanka Ringwald         uint8_t *avrcProfile = de_push_sequence(attribute);
284be32e7f1SMilanka Ringwald         {
285be32e7f1SMilanka Ringwald             de_add_number(avrcProfile,  DE_UUID, DE_SIZE_16, AV_REMOTE_CONTROL);
286be32e7f1SMilanka Ringwald             de_add_number(avrcProfile,  DE_UINT, DE_SIZE_16, 0x0105);
287be32e7f1SMilanka Ringwald         }
288be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, avrcProfile);
289be32e7f1SMilanka Ringwald     }
290be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
291be32e7f1SMilanka Ringwald 
292be32e7f1SMilanka Ringwald 
293be32e7f1SMilanka Ringwald     // 0x0100 "Service Name"
294be32e7f1SMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
295be32e7f1SMilanka Ringwald     if (service_name){
296be32e7f1SMilanka Ringwald         de_add_data(service,  DE_STRING, strlen(service_name), (uint8_t *) service_name);
297be32e7f1SMilanka Ringwald     } else {
298be32e7f1SMilanka Ringwald         if (controller){
299be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_controller_service_name), (uint8_t *) default_avrcp_controller_service_name);
300be32e7f1SMilanka Ringwald         } else {
301be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_target_service_name), (uint8_t *) default_avrcp_target_service_name);
302be32e7f1SMilanka Ringwald         }
303be32e7f1SMilanka Ringwald     }
304be32e7f1SMilanka Ringwald 
305be32e7f1SMilanka Ringwald     // 0x0100 "Provider Name"
306be32e7f1SMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0102);
307be32e7f1SMilanka Ringwald     if (service_provider_name){
308be32e7f1SMilanka Ringwald         de_add_data(service,  DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name);
309be32e7f1SMilanka Ringwald     } else {
310be32e7f1SMilanka Ringwald         if (controller){
311be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_controller_service_provider_name), (uint8_t *) default_avrcp_controller_service_provider_name);
312be32e7f1SMilanka Ringwald         } else {
313be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_target_service_provider_name), (uint8_t *) default_avrcp_target_service_provider_name);
314be32e7f1SMilanka Ringwald         }
315be32e7f1SMilanka Ringwald     }
316be32e7f1SMilanka Ringwald 
317be32e7f1SMilanka Ringwald     // 0x0311 "Supported Features"
318be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
319be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
320be32e7f1SMilanka Ringwald }
321be32e7f1SMilanka Ringwald 
322be32e7f1SMilanka Ringwald void avrcp_controller_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name){
323be32e7f1SMilanka Ringwald     avrcp_create_sdp_record(1, service, service_record_handle, browsing, supported_features, service_name, service_provider_name);
324be32e7f1SMilanka Ringwald }
325be32e7f1SMilanka Ringwald 
326be32e7f1SMilanka Ringwald void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name){
327be32e7f1SMilanka Ringwald     avrcp_create_sdp_record(0, service, service_record_handle, browsing, supported_features, service_name, service_provider_name);
328be32e7f1SMilanka Ringwald }
329be32e7f1SMilanka Ringwald 
330be32e7f1SMilanka Ringwald static void avrcp_emit_repeat_and_shuffle_mode(btstack_packet_handler_t callback, uint16_t con_handle, uint8_t status, avrcp_repeat_mode_t repeat_mode, avrcp_shuffle_mode_t shuffle_mode){
331be32e7f1SMilanka Ringwald     if (!callback) return;
332be32e7f1SMilanka Ringwald     uint8_t event[8];
333be32e7f1SMilanka Ringwald     int pos = 0;
334be32e7f1SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
335be32e7f1SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
336be32e7f1SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE;
337be32e7f1SMilanka Ringwald     little_endian_store_16(event, pos, con_handle);
338be32e7f1SMilanka Ringwald     pos += 2;
339be32e7f1SMilanka Ringwald     event[pos++] = status;
340be32e7f1SMilanka Ringwald     event[pos++] = repeat_mode;
341be32e7f1SMilanka Ringwald     event[pos++] = shuffle_mode;
342be32e7f1SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
343be32e7f1SMilanka Ringwald }
344be32e7f1SMilanka Ringwald 
345be32e7f1SMilanka Ringwald static void avrcp_emit_connection_established(btstack_packet_handler_t callback, uint16_t con_handle, uint8_t status, uint16_t local_cid, bd_addr_t addr){
346be32e7f1SMilanka Ringwald     if (!callback) return;
347be32e7f1SMilanka Ringwald     uint8_t event[14];
348be32e7f1SMilanka Ringwald     int pos = 0;
349be32e7f1SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
350be32e7f1SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
351be32e7f1SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED;
352be32e7f1SMilanka Ringwald     little_endian_store_16(event, pos, con_handle);
353be32e7f1SMilanka Ringwald     pos += 2;
354be32e7f1SMilanka Ringwald     event[pos++] = status;
355be32e7f1SMilanka Ringwald     little_endian_store_16(event, pos, local_cid);
356be32e7f1SMilanka Ringwald     pos += 2;
357be32e7f1SMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
358be32e7f1SMilanka Ringwald     pos += 6;
359be32e7f1SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
360be32e7f1SMilanka Ringwald }
361be32e7f1SMilanka Ringwald 
362be32e7f1SMilanka Ringwald static void avrcp_emit_operation_status(btstack_packet_handler_t callback, uint8_t subevent, uint16_t con_handle, uint8_t status, uint8_t operation_id){
363be32e7f1SMilanka Ringwald     if (!callback) return;
364be32e7f1SMilanka Ringwald     uint8_t event[7];
365be32e7f1SMilanka Ringwald     int pos = 0;
366be32e7f1SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
367be32e7f1SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
368be32e7f1SMilanka Ringwald     event[pos++] = subevent;
369be32e7f1SMilanka Ringwald     little_endian_store_16(event, pos, con_handle);
370be32e7f1SMilanka Ringwald     pos += 2;
371be32e7f1SMilanka Ringwald     event[pos++] = status;
372be32e7f1SMilanka Ringwald     event[pos++] = operation_id;
373be32e7f1SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
374be32e7f1SMilanka Ringwald }
375be32e7f1SMilanka Ringwald 
376be32e7f1SMilanka Ringwald static void avrcp_emit_connection_closed(btstack_packet_handler_t callback, uint16_t con_handle){
377be32e7f1SMilanka Ringwald     if (!callback) return;
378be32e7f1SMilanka Ringwald     uint8_t event[5];
379be32e7f1SMilanka Ringwald     int pos = 0;
380be32e7f1SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
381be32e7f1SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
382be32e7f1SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED;
383be32e7f1SMilanka Ringwald     little_endian_store_16(event, pos, con_handle);
384be32e7f1SMilanka Ringwald     pos += 2;
385be32e7f1SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
386be32e7f1SMilanka Ringwald }
387be32e7f1SMilanka Ringwald 
388be32e7f1SMilanka Ringwald static avrcp_connection_t * get_avrcp_connection_for_bd_addr(bd_addr_t addr){
389be32e7f1SMilanka Ringwald     btstack_linked_list_iterator_t it;
390be32e7f1SMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
391be32e7f1SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
392be32e7f1SMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
393be32e7f1SMilanka Ringwald         if (memcmp(addr, connection->remote_addr, 6) != 0) continue;
394be32e7f1SMilanka Ringwald         return connection;
395be32e7f1SMilanka Ringwald     }
396be32e7f1SMilanka Ringwald     return NULL;
397be32e7f1SMilanka Ringwald }
398be32e7f1SMilanka Ringwald 
399be32e7f1SMilanka Ringwald static avrcp_connection_t * get_avrcp_connection_for_con_handle(hci_con_handle_t con_handle){
400be32e7f1SMilanka Ringwald     btstack_linked_list_iterator_t it;
401be32e7f1SMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
402be32e7f1SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
403be32e7f1SMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
404be32e7f1SMilanka Ringwald         if (connection->con_handle != con_handle) continue;
405be32e7f1SMilanka Ringwald         return connection;
406be32e7f1SMilanka Ringwald     }
407be32e7f1SMilanka Ringwald     return NULL;
408be32e7f1SMilanka Ringwald }
409be32e7f1SMilanka Ringwald 
410be32e7f1SMilanka Ringwald static avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){
411be32e7f1SMilanka Ringwald     btstack_linked_list_iterator_t it;
412be32e7f1SMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
413be32e7f1SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
414be32e7f1SMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
415be32e7f1SMilanka Ringwald         if (connection->l2cap_signaling_cid != l2cap_cid) continue;
416be32e7f1SMilanka Ringwald         return connection;
417be32e7f1SMilanka Ringwald     }
418be32e7f1SMilanka Ringwald     return NULL;
419be32e7f1SMilanka Ringwald }
420be32e7f1SMilanka Ringwald 
421be32e7f1SMilanka Ringwald static void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){
422be32e7f1SMilanka Ringwald     connection->wait_to_send = 1;
423be32e7f1SMilanka Ringwald     l2cap_request_can_send_now_event(l2cap_cid);
424be32e7f1SMilanka Ringwald }
425be32e7f1SMilanka Ringwald 
426be32e7f1SMilanka Ringwald static void avrcp_press_and_hold_timeout_handler(btstack_timer_source_t * timer){
427be32e7f1SMilanka Ringwald     UNUSED(timer);
428be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = btstack_run_loop_get_timer_context(timer);
429be32e7f1SMilanka Ringwald     btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout
430be32e7f1SMilanka Ringwald     btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer);
431be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_PRESS_COMMAND;
432be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
433be32e7f1SMilanka Ringwald }
434be32e7f1SMilanka Ringwald 
435be32e7f1SMilanka Ringwald static void avrcp_press_and_hold_timer_start(avrcp_connection_t * connection){
436be32e7f1SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer);
437be32e7f1SMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->press_and_hold_cmd_timer, avrcp_press_and_hold_timeout_handler);
438be32e7f1SMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->press_and_hold_cmd_timer, connection);
439be32e7f1SMilanka Ringwald     btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout
440be32e7f1SMilanka Ringwald     btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer);
441be32e7f1SMilanka Ringwald }
442be32e7f1SMilanka Ringwald 
443be32e7f1SMilanka Ringwald static void avrcp_press_and_hold_timer_stop(avrcp_connection_t * connection){
444be32e7f1SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer);
445be32e7f1SMilanka Ringwald }
446be32e7f1SMilanka Ringwald 
447be32e7f1SMilanka Ringwald static void request_pass_through_release_control_cmd(avrcp_connection_t * connection){
448be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_RELEASE_COMMAND;
449be32e7f1SMilanka Ringwald     switch (connection->cmd_operands[0]){
450be32e7f1SMilanka Ringwald         case AVRCP_OPERATION_ID_REWIND:
451be32e7f1SMilanka Ringwald         case AVRCP_OPERATION_ID_FAST_FORWARD:
452be32e7f1SMilanka Ringwald             avrcp_press_and_hold_timer_stop(connection);
453be32e7f1SMilanka Ringwald             break;
454be32e7f1SMilanka Ringwald         default:
455be32e7f1SMilanka Ringwald             break;
456be32e7f1SMilanka Ringwald     }
457be32e7f1SMilanka Ringwald     connection->cmd_operands[0] = 0x80 | connection->cmd_operands[0];
458be32e7f1SMilanka Ringwald     connection->transaction_label++;
459be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
460be32e7f1SMilanka Ringwald }
461be32e7f1SMilanka Ringwald 
462be32e7f1SMilanka Ringwald static void request_pass_through_press_control_cmd(uint16_t con_handle, avrcp_operation_id_t opid, uint16_t playback_speed){
463be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
464be32e7f1SMilanka Ringwald     if (!connection){
465be32e7f1SMilanka Ringwald         log_error("avrcp: could not find a connection.");
466be32e7f1SMilanka Ringwald         return;
467be32e7f1SMilanka Ringwald     }
468be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
469be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_PRESS_COMMAND;
470be32e7f1SMilanka Ringwald     connection->cmd_to_send =  AVRCP_CMD_OPCODE_PASS_THROUGH;
471be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_CONTROL;
472be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
473be32e7f1SMilanka Ringwald     connection->subunit_id =   0;
474be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = 0;
475be32e7f1SMilanka Ringwald 
476be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = 2;
477be32e7f1SMilanka Ringwald     connection->cmd_operands[0] = opid;
478be32e7f1SMilanka Ringwald     if (playback_speed > 0){
479be32e7f1SMilanka Ringwald         connection->cmd_operands[2] = playback_speed;
480be32e7f1SMilanka Ringwald         connection->cmd_operands_lenght++;
481be32e7f1SMilanka Ringwald     }
482be32e7f1SMilanka Ringwald     connection->cmd_operands[1] = connection->cmd_operands_lenght - 2;
483be32e7f1SMilanka Ringwald 
484be32e7f1SMilanka Ringwald     switch (connection->cmd_operands[0]){
485be32e7f1SMilanka Ringwald         case AVRCP_OPERATION_ID_REWIND:
486be32e7f1SMilanka Ringwald         case AVRCP_OPERATION_ID_FAST_FORWARD:
487be32e7f1SMilanka Ringwald             avrcp_press_and_hold_timer_start(connection);
488be32e7f1SMilanka Ringwald             break;
489be32e7f1SMilanka Ringwald         default:
490be32e7f1SMilanka Ringwald             break;
491be32e7f1SMilanka Ringwald     }
492be32e7f1SMilanka Ringwald     connection->transaction_label++;
493be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
494be32e7f1SMilanka Ringwald }
495be32e7f1SMilanka Ringwald 
496be32e7f1SMilanka Ringwald 
497be32e7f1SMilanka Ringwald static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){
498be32e7f1SMilanka Ringwald     uint8_t command[20];
499be32e7f1SMilanka Ringwald     int pos = 0;
500be32e7f1SMilanka Ringwald     // transport header
501be32e7f1SMilanka Ringwald     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
502be32e7f1SMilanka Ringwald     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
503be32e7f1SMilanka Ringwald     // Profile IDentifier (PID)
504be32e7f1SMilanka Ringwald     command[pos++] = AV_REMOTE_CONTROL >> 8;
505be32e7f1SMilanka Ringwald     command[pos++] = AV_REMOTE_CONTROL & 0x00FF;
506be32e7f1SMilanka Ringwald 
507be32e7f1SMilanka Ringwald     // command_type
508be32e7f1SMilanka Ringwald     command[pos++] = connection->command_type;
509be32e7f1SMilanka Ringwald     // subunit_type | subunit ID
510be32e7f1SMilanka Ringwald     command[pos++] = (connection->subunit_type << 3) | connection->subunit_id;
511be32e7f1SMilanka Ringwald     // opcode
512be32e7f1SMilanka Ringwald     command[pos++] = (uint8_t)connection->cmd_to_send;
513be32e7f1SMilanka Ringwald     // operands
514be32e7f1SMilanka Ringwald     memcpy(command+pos, connection->cmd_operands, connection->cmd_operands_lenght);
515be32e7f1SMilanka Ringwald     pos += connection->cmd_operands_lenght;
516be32e7f1SMilanka Ringwald 
517be32e7f1SMilanka Ringwald     return l2cap_send(cid, command, pos);
518be32e7f1SMilanka Ringwald }
519be32e7f1SMilanka Ringwald 
520be32e7f1SMilanka Ringwald static int avrcp_register_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id){
521be32e7f1SMilanka Ringwald     if (connection->notifications_to_deregister & (1 << event_id)) return 0;
522be32e7f1SMilanka Ringwald     if (connection->notifications_enabled & (1 << event_id)) return 0;
523be32e7f1SMilanka Ringwald     if (connection->notifications_to_register & (1 << event_id)) return 0;
524be32e7f1SMilanka Ringwald     connection->notifications_to_register |= (1 << event_id);
525be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
526be32e7f1SMilanka Ringwald     return 1;
527be32e7f1SMilanka Ringwald }
528be32e7f1SMilanka Ringwald 
529be32e7f1SMilanka Ringwald static void avrcp_prepare_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id){
530be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
531be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
532be32e7f1SMilanka Ringwald 
533be32e7f1SMilanka Ringwald     connection->transaction_label++;
534be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
535be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_NOTIFY;
536be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
537be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
538be32e7f1SMilanka Ringwald     int pos = 0;
539be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
540be32e7f1SMilanka Ringwald     pos += 3;
541be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = AVRCP_PDU_ID_REGISTER_NOTIFICATION;
542be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = 0;                     // reserved(upper 6) | packet_type -> 0
543be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, pos, 5);     // parameter length
544be32e7f1SMilanka Ringwald     pos += 2;
545be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = event_id;
546be32e7f1SMilanka Ringwald     big_endian_store_32(connection->cmd_operands, pos, 0);
547be32e7f1SMilanka Ringwald     pos += 4;
548be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = pos;
549be32e7f1SMilanka Ringwald     // AVRCP_SPEC_V14.pdf 166
550be32e7f1SMilanka Ringwald     // answer page 61
551be32e7f1SMilanka Ringwald }
552be32e7f1SMilanka Ringwald 
553be32e7f1SMilanka Ringwald static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
554be32e7f1SMilanka Ringwald     switch (connection->state){
555be32e7f1SMilanka Ringwald         case AVCTP_W2_RECEIVE_PRESS_RESPONSE:
556be32e7f1SMilanka Ringwald             switch (connection->cmd_operands[0]){
557be32e7f1SMilanka Ringwald                 case AVRCP_OPERATION_ID_REWIND:
558be32e7f1SMilanka Ringwald                 case AVRCP_OPERATION_ID_FAST_FORWARD:
559be32e7f1SMilanka Ringwald                     connection->state = AVCTP_W4_STOP;
560be32e7f1SMilanka Ringwald                     break;
561be32e7f1SMilanka Ringwald                 default:
562be32e7f1SMilanka Ringwald                     connection->state = AVCTP_W2_SEND_RELEASE_COMMAND;
563be32e7f1SMilanka Ringwald                     break;
564be32e7f1SMilanka Ringwald             }
565be32e7f1SMilanka Ringwald             break;
566be32e7f1SMilanka Ringwald         case AVCTP_W2_RECEIVE_RESPONSE:
567be32e7f1SMilanka Ringwald             connection->state = AVCTP_CONNECTION_OPENED;
568be32e7f1SMilanka Ringwald             break;
569be32e7f1SMilanka Ringwald         default:
570be32e7f1SMilanka Ringwald             // check for notifications? move state transition down
571be32e7f1SMilanka Ringwald             break;
572be32e7f1SMilanka Ringwald     }
573be32e7f1SMilanka Ringwald 
574be32e7f1SMilanka Ringwald     avrcp_command_type_t ctype;
575be32e7f1SMilanka Ringwald     avrcp_subunit_type_t subunit_type;
576be32e7f1SMilanka Ringwald     avrcp_subunit_type_t subunit_id;
577be32e7f1SMilanka Ringwald 
578be32e7f1SMilanka Ringwald     uint8_t operands[20];
579be32e7f1SMilanka Ringwald     uint8_t opcode;
580be32e7f1SMilanka Ringwald     int pos = 0;
581be32e7f1SMilanka Ringwald     // uint8_t transport_header = packet[0];
582be32e7f1SMilanka Ringwald     // uint8_t transaction_label = transport_header >> 4;
583be32e7f1SMilanka Ringwald     // uint8_t packet_type = (transport_header & 0x0F) >> 2;
584be32e7f1SMilanka Ringwald     // uint8_t frame_type = (transport_header & 0x03) >> 1;
585be32e7f1SMilanka Ringwald     // uint8_t ipid = transport_header & 0x01;
586be32e7f1SMilanka Ringwald     uint8_t byte_value = packet[2];
587be32e7f1SMilanka Ringwald     // uint16_t pid = (byte_value << 8) | packet[2];
588be32e7f1SMilanka Ringwald     pos = 3;
589be32e7f1SMilanka Ringwald 
590be32e7f1SMilanka Ringwald     // printf("    Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n",
591be32e7f1SMilanka Ringwald     //     transport_header, transaction_label, packet_type, frame_type, ipid, pid);
592be32e7f1SMilanka Ringwald     // // printf_hexdump(packet+pos, size-pos);
593be32e7f1SMilanka Ringwald 
594be32e7f1SMilanka Ringwald     switch (connection->cmd_to_send){
595be32e7f1SMilanka Ringwald         case AVRCP_CMD_OPCODE_UNIT_INFO:{
596be32e7f1SMilanka Ringwald             ctype = packet[pos++];
597be32e7f1SMilanka Ringwald             byte_value = packet[pos++];
598be32e7f1SMilanka Ringwald             subunit_type = byte_value >> 3;
599be32e7f1SMilanka Ringwald             subunit_id = byte_value & 0x07;
600be32e7f1SMilanka Ringwald             opcode = packet[pos++];
601be32e7f1SMilanka Ringwald 
602be32e7f1SMilanka Ringwald             // operands:
603be32e7f1SMilanka Ringwald             memcpy(operands, packet+pos, 5);
604be32e7f1SMilanka Ringwald             uint8_t unit_type = operands[1] >> 3;
605be32e7f1SMilanka Ringwald             uint8_t unit = operands[1] & 0x07;
606be32e7f1SMilanka Ringwald             uint32_t company_id = operands[2] << 16 | operands[3] << 8 | operands[4];
607be32e7f1SMilanka Ringwald             log_info("    UNIT INFO response: ctype 0x%02x (0C), subunit_type 0x%02x (1F), subunit_id 0x%02x (07), opcode 0x%02x (30), unit_type 0x%02x, unit %d, company_id 0x%06x",
608be32e7f1SMilanka Ringwald                 ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id );
609be32e7f1SMilanka Ringwald             break;
610be32e7f1SMilanka Ringwald         }
611be32e7f1SMilanka Ringwald         case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
612be32e7f1SMilanka Ringwald             ctype = packet[pos++];
613be32e7f1SMilanka Ringwald             byte_value = packet[pos++];
614be32e7f1SMilanka Ringwald             subunit_type = byte_value >> 3;
615be32e7f1SMilanka Ringwald             subunit_id = byte_value & 0x07;
616be32e7f1SMilanka Ringwald             opcode = packet[pos++];
617be32e7f1SMilanka Ringwald 
618be32e7f1SMilanka Ringwald             if (size - pos < 7) {
619be32e7f1SMilanka Ringwald                 log_error("avrcp: wrong packet size");
620be32e7f1SMilanka Ringwald                 return;
621be32e7f1SMilanka Ringwald             };
622be32e7f1SMilanka Ringwald             // operands:
623be32e7f1SMilanka Ringwald             memcpy(operands, packet+pos, 7);
624be32e7f1SMilanka Ringwald             pos += 7;
625be32e7f1SMilanka Ringwald             // uint32_t company_id = operands[0] << 16 | operands[1] << 8 | operands[2];
626be32e7f1SMilanka Ringwald             uint8_t pdu_id = operands[3];
627be32e7f1SMilanka Ringwald             // uint8_t unit_type = operands[4] >> 3;
628be32e7f1SMilanka Ringwald             // uint8_t unit = operands[4] & 0x07;
629be32e7f1SMilanka Ringwald             uint16_t param_length = big_endian_read_16(operands, 5);
630be32e7f1SMilanka Ringwald 
631be32e7f1SMilanka Ringwald             // printf("    VENDOR DEPENDENT response: ctype 0x%02x (0C), subunit_type 0x%02x (1F), subunit_id 0x%02x (07), opcode 0x%02x (30), unit_type 0x%02x, unit %d, company_id 0x%06x\n",
632be32e7f1SMilanka Ringwald             //     ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id );
633be32e7f1SMilanka Ringwald 
634be32e7f1SMilanka Ringwald             // if (ctype == AVRCP_CTYPE_RESPONSE_INTERIM) return;
635be32e7f1SMilanka Ringwald             log_info("        VENDOR DEPENDENT response: pdu id 0x%02x, param_length %d, status %s", pdu_id, param_length, avrcp_ctype2str(ctype));
636be32e7f1SMilanka Ringwald             switch (pdu_id){
637be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue:{
638be32e7f1SMilanka Ringwald                     uint8_t num_attributes = packet[pos++];
639be32e7f1SMilanka Ringwald                     int i;
640be32e7f1SMilanka Ringwald                     uint8_t repeat_mode = 0;
641be32e7f1SMilanka Ringwald                     uint8_t shuffle_mode = 0;
642be32e7f1SMilanka Ringwald                     for (i = 0; i < num_attributes; i++){
643be32e7f1SMilanka Ringwald                         uint8_t attribute_id    = packet[pos++];
644be32e7f1SMilanka Ringwald                         uint8_t attribute_value = packet[pos++];
645be32e7f1SMilanka Ringwald                         switch (attribute_id){
646be32e7f1SMilanka Ringwald                             case 0x02:
647be32e7f1SMilanka Ringwald                                 repeat_mode = attribute_value;
648be32e7f1SMilanka Ringwald                                 break;
649be32e7f1SMilanka Ringwald                             case 0x03:
650be32e7f1SMilanka Ringwald                                 shuffle_mode = attribute_value;
651be32e7f1SMilanka Ringwald                                 break;
652be32e7f1SMilanka Ringwald                             default:
653be32e7f1SMilanka Ringwald                                 break;
654be32e7f1SMilanka Ringwald                         }
655be32e7f1SMilanka Ringwald                     }
656be32e7f1SMilanka Ringwald                     avrcp_emit_repeat_and_shuffle_mode(avrcp_callback, connection->con_handle, ctype, repeat_mode, shuffle_mode);
657be32e7f1SMilanka Ringwald                     break;
658be32e7f1SMilanka Ringwald                 }
659be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_SetPlayerApplicationSettingValue:{
660be32e7f1SMilanka Ringwald                     uint8_t event[6];
661be32e7f1SMilanka Ringwald                     int offset = 0;
662be32e7f1SMilanka Ringwald                     event[offset++] = HCI_EVENT_AVRCP_META;
663be32e7f1SMilanka Ringwald                     event[offset++] = sizeof(event) - 2;
664be32e7f1SMilanka Ringwald                     event[offset++] = AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE;
665be32e7f1SMilanka Ringwald                     little_endian_store_16(event, offset, connection->con_handle);
666be32e7f1SMilanka Ringwald                     offset += 2;
667be32e7f1SMilanka Ringwald                     event[offset++] = ctype;
668be32e7f1SMilanka Ringwald                     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
669be32e7f1SMilanka Ringwald                     break;
670be32e7f1SMilanka Ringwald                 }
671be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME:{
672be32e7f1SMilanka Ringwald                     uint8_t event[7];
673be32e7f1SMilanka Ringwald                     int offset = 0;
674be32e7f1SMilanka Ringwald                     event[offset++] = HCI_EVENT_AVRCP_META;
675be32e7f1SMilanka Ringwald                     event[offset++] = sizeof(event) - 2;
676be32e7f1SMilanka Ringwald                     event[offset++] = AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE;
677be32e7f1SMilanka Ringwald                     little_endian_store_16(event, offset, connection->con_handle);
678be32e7f1SMilanka Ringwald                     offset += 2;
679be32e7f1SMilanka Ringwald                     event[offset++] = ctype;
680be32e7f1SMilanka Ringwald                     event[offset++] = packet[pos++];
681be32e7f1SMilanka Ringwald                     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
682be32e7f1SMilanka Ringwald                     break;
683be32e7f1SMilanka Ringwald                 }
684be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_GET_CAPABILITIES:{
685be32e7f1SMilanka Ringwald                     avrcp_capability_id_t capability_id = packet[pos++];
686be32e7f1SMilanka Ringwald                     uint8_t capability_count = packet[pos++];
687be32e7f1SMilanka Ringwald                     int i;
688be32e7f1SMilanka Ringwald                     switch (capability_id){
689be32e7f1SMilanka Ringwald                         case AVRCP_CAPABILITY_ID_COMPANY:
690be32e7f1SMilanka Ringwald                             // log_info("Supported companies %d: ", capability_count);
691be32e7f1SMilanka Ringwald                             for (i = 0; i < capability_count; i++){
692be32e7f1SMilanka Ringwald                                 uint32_t company_id = big_endian_read_24(packet, pos);
693be32e7f1SMilanka Ringwald                                 pos += 3;
694be32e7f1SMilanka Ringwald                                 log_info("  0x%06x, ", company_id);
695be32e7f1SMilanka Ringwald                             }
696be32e7f1SMilanka Ringwald                             break;
697be32e7f1SMilanka Ringwald                         case AVRCP_CAPABILITY_ID_EVENT:
698be32e7f1SMilanka Ringwald                             // log_info("Supported events %d: ", capability_count);
699be32e7f1SMilanka Ringwald                             for (i = 0; i < capability_count; i++){
700be32e7f1SMilanka Ringwald                                 uint8_t event_id = packet[pos++];
701be32e7f1SMilanka Ringwald                                 log_info("  0x%02x %s", event_id, avrcp_event2str(event_id));
702be32e7f1SMilanka Ringwald                             }
703be32e7f1SMilanka Ringwald                             break;
704be32e7f1SMilanka Ringwald                     }
705be32e7f1SMilanka Ringwald                     break;
706be32e7f1SMilanka Ringwald                 }
707be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_GET_PLAY_STATUS:{
708be32e7f1SMilanka Ringwald                     uint32_t song_length = big_endian_read_32(packet, pos);
709be32e7f1SMilanka Ringwald                     pos += 4;
710be32e7f1SMilanka Ringwald                     uint32_t song_position = big_endian_read_32(packet, pos);
711be32e7f1SMilanka Ringwald                     pos += 4;
712be32e7f1SMilanka Ringwald                     uint8_t play_status = packet[pos];
713be32e7f1SMilanka Ringwald                     // log_info("        GET_PLAY_STATUS length 0x%04X, position 0x%04X, status %s", song_length, song_position, avrcp_play_status2str(play_status));
714be32e7f1SMilanka Ringwald 
715be32e7f1SMilanka Ringwald                     uint8_t event[15];
716be32e7f1SMilanka Ringwald                     int offset = 0;
717be32e7f1SMilanka Ringwald                     event[offset++] = HCI_EVENT_AVRCP_META;
718be32e7f1SMilanka Ringwald                     event[offset++] = sizeof(event) - 2;
719be32e7f1SMilanka Ringwald                     event[offset++] = AVRCP_SUBEVENT_PLAY_STATUS;
720be32e7f1SMilanka Ringwald                     little_endian_store_16(event, offset, connection->con_handle);
721be32e7f1SMilanka Ringwald                     offset += 2;
722be32e7f1SMilanka Ringwald                     event[offset++] = ctype;
723be32e7f1SMilanka Ringwald                     little_endian_store_32(event, offset, song_length);
724be32e7f1SMilanka Ringwald                     offset += 4;
725be32e7f1SMilanka Ringwald                     little_endian_store_32(event, offset, song_position);
726be32e7f1SMilanka Ringwald                     offset += 4;
727be32e7f1SMilanka Ringwald                     event[offset++] = play_status;
728be32e7f1SMilanka Ringwald                     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
729be32e7f1SMilanka Ringwald                     break;
730be32e7f1SMilanka Ringwald                 }
731be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_REGISTER_NOTIFICATION:{
732be32e7f1SMilanka Ringwald                     uint8_t  event_id = packet[pos++];
733be32e7f1SMilanka Ringwald                     uint16_t event_mask = (1 << event_id);
734be32e7f1SMilanka Ringwald                     uint16_t reset_event_mask = ~event_mask;
735be32e7f1SMilanka Ringwald                     switch (ctype){
736be32e7f1SMilanka Ringwald                         case AVRCP_CTYPE_RESPONSE_INTERIM:
737be32e7f1SMilanka Ringwald                             // register as enabled
738be32e7f1SMilanka Ringwald                             connection->notifications_enabled |= event_mask;
739be32e7f1SMilanka Ringwald                             // clear registration bit
740be32e7f1SMilanka Ringwald                             connection->notifications_to_register &= reset_event_mask;
741be32e7f1SMilanka Ringwald                             connection->state = AVCTP_CONNECTION_OPENED;
742be32e7f1SMilanka Ringwald                             // printf("INTERIM notifications_enabled 0x%2x, notifications_to_register 0x%2x\n", connection->notifications_enabled,  connection->notifications_to_register);
743be32e7f1SMilanka Ringwald                             break;
744be32e7f1SMilanka Ringwald                         case AVRCP_CTYPE_RESPONSE_CHANGED_STABLE:
745be32e7f1SMilanka Ringwald                             // received change, event is considered deregistered
746be32e7f1SMilanka Ringwald                             // we are re-enabling it automatically, if it is not
747be32e7f1SMilanka Ringwald                             // explicitly disabled
748be32e7f1SMilanka Ringwald                             connection->notifications_enabled &= reset_event_mask;
749be32e7f1SMilanka Ringwald                             if (! (connection->notifications_to_deregister & event_mask)){
750be32e7f1SMilanka Ringwald                                 avrcp_register_notification(connection, event_id);
751be32e7f1SMilanka Ringwald                                 // printf("CHANGED_STABLE notifications_enabled 0x%2x, notifications_to_register 0x%2x\n", connection->notifications_enabled,  connection->notifications_to_register);
752be32e7f1SMilanka Ringwald                             } else {
753be32e7f1SMilanka Ringwald                                 connection->notifications_to_deregister &= reset_event_mask;
754be32e7f1SMilanka Ringwald                             }
755be32e7f1SMilanka Ringwald                             break;
756be32e7f1SMilanka Ringwald                         default:
757be32e7f1SMilanka Ringwald                             connection->notifications_to_register &= reset_event_mask;
758be32e7f1SMilanka Ringwald                             connection->notifications_enabled &= reset_event_mask;
759be32e7f1SMilanka Ringwald                             connection->notifications_to_deregister &= reset_event_mask;
760be32e7f1SMilanka Ringwald                             break;
761be32e7f1SMilanka Ringwald                     }
762be32e7f1SMilanka Ringwald 
763be32e7f1SMilanka Ringwald                     switch (event_id){
764be32e7f1SMilanka Ringwald                         case AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED:{
765be32e7f1SMilanka Ringwald                             uint8_t event[7];
766be32e7f1SMilanka Ringwald                             int offset = 0;
767be32e7f1SMilanka Ringwald                             event[offset++] = HCI_EVENT_AVRCP_META;
768be32e7f1SMilanka Ringwald                             event[offset++] = sizeof(event) - 2;
769be32e7f1SMilanka Ringwald                             event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED;
770be32e7f1SMilanka Ringwald                             little_endian_store_16(event, offset, connection->con_handle);
771be32e7f1SMilanka Ringwald                             offset += 2;
772be32e7f1SMilanka Ringwald                             event[offset++] = ctype;
773be32e7f1SMilanka Ringwald                             event[offset++] = packet[pos];
774be32e7f1SMilanka Ringwald                             (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
775be32e7f1SMilanka Ringwald                             break;
776be32e7f1SMilanka Ringwald                         }
777be32e7f1SMilanka Ringwald                         case AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED:{
778be32e7f1SMilanka Ringwald                             uint8_t event[7];
779be32e7f1SMilanka Ringwald                             int offset = 0;
780be32e7f1SMilanka Ringwald                             event[offset++] = HCI_EVENT_AVRCP_META;
781be32e7f1SMilanka Ringwald                             event[offset++] = sizeof(event) - 2;
782be32e7f1SMilanka Ringwald                             event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED;
783be32e7f1SMilanka Ringwald                             little_endian_store_16(event, offset, connection->con_handle);
784be32e7f1SMilanka Ringwald                             offset += 2;
785be32e7f1SMilanka Ringwald                             event[offset++] = ctype;
786be32e7f1SMilanka Ringwald                             event[offset++] = packet[pos];
787be32e7f1SMilanka Ringwald                             (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
788be32e7f1SMilanka Ringwald                             break;
789be32e7f1SMilanka Ringwald                         }
790be32e7f1SMilanka Ringwald                         case AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED:{
791be32e7f1SMilanka Ringwald                             uint8_t event[6];
792be32e7f1SMilanka Ringwald                             int offset = 0;
793be32e7f1SMilanka Ringwald                             event[offset++] = HCI_EVENT_AVRCP_META;
794be32e7f1SMilanka Ringwald                             event[offset++] = sizeof(event) - 2;
795be32e7f1SMilanka Ringwald                             event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_NOW_PLAYING_CONTENT_CHANGED;
796be32e7f1SMilanka Ringwald                             little_endian_store_16(event, offset, connection->con_handle);
797be32e7f1SMilanka Ringwald                             offset += 2;
798be32e7f1SMilanka Ringwald                             event[offset++] = ctype;
799be32e7f1SMilanka Ringwald                             (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
800be32e7f1SMilanka Ringwald                             break;
801be32e7f1SMilanka Ringwald                         }
802be32e7f1SMilanka Ringwald                         case AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED:{
803be32e7f1SMilanka Ringwald                             uint8_t event[6];
804be32e7f1SMilanka Ringwald                             int offset = 0;
805be32e7f1SMilanka Ringwald                             event[offset++] = HCI_EVENT_AVRCP_META;
806be32e7f1SMilanka Ringwald                             event[offset++] = sizeof(event) - 2;
807be32e7f1SMilanka Ringwald                             event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_AVAILABLE_PLAYERS_CHANGED;
808be32e7f1SMilanka Ringwald                             little_endian_store_16(event, offset, connection->con_handle);
809be32e7f1SMilanka Ringwald                             offset += 2;
810be32e7f1SMilanka Ringwald                             event[offset++] = ctype;
811be32e7f1SMilanka Ringwald                             (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
812be32e7f1SMilanka Ringwald                             break;
813be32e7f1SMilanka Ringwald                         }
814be32e7f1SMilanka Ringwald                         case AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED:{
815be32e7f1SMilanka Ringwald                             uint8_t event[7];
816be32e7f1SMilanka Ringwald                             int offset = 0;
817be32e7f1SMilanka Ringwald                             event[offset++] = HCI_EVENT_AVRCP_META;
818be32e7f1SMilanka Ringwald                             event[offset++] = sizeof(event) - 2;
819be32e7f1SMilanka Ringwald                             event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED;
820be32e7f1SMilanka Ringwald                             little_endian_store_16(event, offset, connection->con_handle);
821be32e7f1SMilanka Ringwald                             offset += 2;
822be32e7f1SMilanka Ringwald                             event[offset++] = ctype;
823be32e7f1SMilanka Ringwald                             event[offset++] = packet[pos++] & 0x7F;
824be32e7f1SMilanka Ringwald                             (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
825be32e7f1SMilanka Ringwald                             break;
826be32e7f1SMilanka Ringwald                         }
827be32e7f1SMilanka Ringwald                         // case AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:{
828be32e7f1SMilanka Ringwald                         //     uint8_t num_PlayerApplicationSettingAttributes = packet[pos++];
829be32e7f1SMilanka Ringwald                         //     int i;
830be32e7f1SMilanka Ringwald                         //     for (i = 0; i < num_PlayerApplicationSettingAttributes; i++){
831be32e7f1SMilanka Ringwald                         //         uint8_t PlayerApplicationSetting_AttributeID = packet[pos++];
832be32e7f1SMilanka Ringwald                         //         uint8_t PlayerApplicationSettingValueID = packet[pos++];
833be32e7f1SMilanka Ringwald                         //     }
834be32e7f1SMilanka Ringwald                         //     break;
835be32e7f1SMilanka Ringwald                         // }
836be32e7f1SMilanka Ringwald                         // case AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED:
837be32e7f1SMilanka Ringwald                         //     uint16_t player_id = big_endian_read_16(packet, pos);
838be32e7f1SMilanka Ringwald                         //     pos += 2;
839be32e7f1SMilanka Ringwald                         //     uint16_t uid_counter = big_endian_read_16(packet, pos);
840be32e7f1SMilanka Ringwald                         //     pos += 2;
841be32e7f1SMilanka Ringwald                         //     break;
842be32e7f1SMilanka Ringwald                         // case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED:
843be32e7f1SMilanka Ringwald                         //     uint16_t uid_counter = big_endian_read_16(packet, pos);
844be32e7f1SMilanka Ringwald                         //     pos += 2;
845be32e7f1SMilanka Ringwald                         //     break;
846be32e7f1SMilanka Ringwald                         default:
847be32e7f1SMilanka Ringwald                             log_info("avrcp: not implemented");
848be32e7f1SMilanka Ringwald                             break;
849be32e7f1SMilanka Ringwald                     }
850be32e7f1SMilanka Ringwald                     if (connection->notifications_to_register != 0){
851be32e7f1SMilanka Ringwald                         avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
852be32e7f1SMilanka Ringwald                     }
853be32e7f1SMilanka Ringwald                     break;
854be32e7f1SMilanka Ringwald                 }
855be32e7f1SMilanka Ringwald 
856be32e7f1SMilanka Ringwald                 case AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES:{
857be32e7f1SMilanka Ringwald                     uint8_t num_attributes = packet[pos++];
858be32e7f1SMilanka Ringwald                     int i;
859be32e7f1SMilanka Ringwald                     struct item {
860be32e7f1SMilanka Ringwald                         uint16_t len;
861be32e7f1SMilanka Ringwald                         uint8_t  * value;
862be32e7f1SMilanka Ringwald                     } items[AVRCP_MEDIA_ATTR_COUNT];
863be32e7f1SMilanka Ringwald                     memset(items, 0, sizeof(items));
864be32e7f1SMilanka Ringwald 
865be32e7f1SMilanka Ringwald                     uint16_t string_attributes_len = 0;
866be32e7f1SMilanka Ringwald                     uint8_t  num_string_attributes = 0;
867be32e7f1SMilanka Ringwald                     uint16_t total_event_payload_for_string_attributes = HCI_EVENT_PAYLOAD_SIZE-2;
868be32e7f1SMilanka Ringwald                     uint16_t max_string_attribute_value_len = 0;
869be32e7f1SMilanka Ringwald                     for (i = 0; i < num_attributes; i++){
870be32e7f1SMilanka Ringwald                         avrcp_media_attribute_id_t attr_id = big_endian_read_32(packet, pos);
871be32e7f1SMilanka Ringwald                         pos += 4;
872be32e7f1SMilanka Ringwald                         // uint16_t character_set = big_endian_read_16(packet, pos);
873be32e7f1SMilanka Ringwald                         pos += 2;
874be32e7f1SMilanka Ringwald                         uint16_t attr_value_length = big_endian_read_16(packet, pos);
875be32e7f1SMilanka Ringwald                         pos += 2;
876be32e7f1SMilanka Ringwald 
877be32e7f1SMilanka Ringwald                         // debug - to remove later
878be32e7f1SMilanka Ringwald                         uint8_t  value[100];
879be32e7f1SMilanka Ringwald                         uint16_t value_len = sizeof(value) <= attr_value_length? sizeof(value) - 1 : attr_value_length;
880be32e7f1SMilanka Ringwald                         memcpy(value, packet+pos, value_len);
881be32e7f1SMilanka Ringwald                         value[value_len] = 0;
882be32e7f1SMilanka Ringwald                         // printf("Now Playing Info %s: %s \n", attribute2str(attr_id), value);
883be32e7f1SMilanka Ringwald                         // end debug
884be32e7f1SMilanka Ringwald 
885be32e7f1SMilanka Ringwald                         if ((attr_id >= 1) || (attr_id <= AVRCP_MEDIA_ATTR_COUNT)) {
886be32e7f1SMilanka Ringwald                             items[attr_id-1].len = attr_value_length;
887be32e7f1SMilanka Ringwald                             items[attr_id-1].value = &packet[pos];
888be32e7f1SMilanka Ringwald                             switch (attr_id){
889be32e7f1SMilanka Ringwald                                 case AVRCP_MEDIA_ATTR_TITLE:
890be32e7f1SMilanka Ringwald                                 case AVRCP_MEDIA_ATTR_ARTIST:
891be32e7f1SMilanka Ringwald                                 case AVRCP_MEDIA_ATTR_ALBUM:
892be32e7f1SMilanka Ringwald                                 case AVRCP_MEDIA_ATTR_GENRE:
893be32e7f1SMilanka Ringwald                                     num_string_attributes++;
894be32e7f1SMilanka Ringwald                                     string_attributes_len += attr_value_length;
895be32e7f1SMilanka Ringwald                                     if (max_string_attribute_value_len < attr_value_length){
896be32e7f1SMilanka Ringwald                                         max_string_attribute_value_len = attr_value_length;
897be32e7f1SMilanka Ringwald                                     }
898be32e7f1SMilanka Ringwald                                     break;
899be32e7f1SMilanka Ringwald                                 default:
900be32e7f1SMilanka Ringwald                                     break;
901be32e7f1SMilanka Ringwald                             }
902be32e7f1SMilanka Ringwald                         }
903be32e7f1SMilanka Ringwald                         pos += attr_value_length;
904be32e7f1SMilanka Ringwald                     }
905be32e7f1SMilanka Ringwald                     // subtract space for fixed fields
906be32e7f1SMilanka Ringwald                     total_event_payload_for_string_attributes -= 14 + 4;    // 4 for '\0'
907be32e7f1SMilanka Ringwald 
908be32e7f1SMilanka Ringwald                     // @TODO optimize space by repeatedly decreasing max_string_attribute_value_len until it fits into buffer instead of crude divion
909be32e7f1SMilanka Ringwald                     uint16_t max_value_len = total_event_payload_for_string_attributes > string_attributes_len? max_string_attribute_value_len : total_event_payload_for_string_attributes/(string_attributes_len+1) - 1;
910be32e7f1SMilanka Ringwald                     // printf("num_string_attributes %d, string_attributes_len %d, total_event_payload_for_string_attributes %d, max_value_len %d \n", num_string_attributes, string_attributes_len, total_event_payload_for_string_attributes, max_value_len);
911be32e7f1SMilanka Ringwald 
912be32e7f1SMilanka Ringwald                     const uint8_t attribute_order[] = {
913be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_TRACK,
914be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_TOTAL_TRACKS,
915be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_SONG_LENGTH,
916be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_TITLE,
917be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_ARTIST,
918be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_ALBUM,
919be32e7f1SMilanka Ringwald                         AVRCP_MEDIA_ATTR_GENRE
920be32e7f1SMilanka Ringwald                     };
921be32e7f1SMilanka Ringwald 
922be32e7f1SMilanka Ringwald                     uint8_t event[HCI_EVENT_BUFFER_SIZE];
923be32e7f1SMilanka Ringwald                     event[0] = HCI_EVENT_AVRCP_META;
924be32e7f1SMilanka Ringwald                     pos = 2;
925be32e7f1SMilanka Ringwald                     event[pos++] = AVRCP_SUBEVENT_NOW_PLAYING_INFO;
926be32e7f1SMilanka Ringwald                     little_endian_store_16(event, pos, connection->con_handle);
927be32e7f1SMilanka Ringwald                     pos += 2;
928be32e7f1SMilanka Ringwald                     event[pos++] = ctype;
929be32e7f1SMilanka Ringwald                     for (i = 0; i < sizeof(attribute_order); i++){
930be32e7f1SMilanka Ringwald                         avrcp_media_attribute_id_t attr_id = attribute_order[i];
931be32e7f1SMilanka Ringwald                         uint16_t value_len = 0;
932be32e7f1SMilanka Ringwald                         switch (attr_id){
933be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_TITLE:
934be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_ARTIST:
935be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_ALBUM:
936be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_GENRE:
937be32e7f1SMilanka Ringwald                                 if (items[attr_id-1].value){
938be32e7f1SMilanka Ringwald                                     value_len = items[attr_id-1].len <= max_value_len ? items[attr_id-1].len : max_value_len;
939be32e7f1SMilanka Ringwald                                 }
940be32e7f1SMilanka Ringwald                                 event[pos++] = value_len + 1;
941be32e7f1SMilanka Ringwald                                 if (value_len){
942be32e7f1SMilanka Ringwald                                     memcpy(event+pos, items[attr_id-1].value, value_len);
943be32e7f1SMilanka Ringwald                                     pos += value_len;
944be32e7f1SMilanka Ringwald                                 }
945be32e7f1SMilanka Ringwald                                 event[pos++] = 0;
946be32e7f1SMilanka Ringwald                                 break;
947be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_SONG_LENGTH:
948be32e7f1SMilanka Ringwald                                 if (items[attr_id-1].value){
949be32e7f1SMilanka Ringwald                                     little_endian_store_32(event, pos, btstack_atoi((char *)items[attr_id-1].value));
950be32e7f1SMilanka Ringwald                                 } else {
951be32e7f1SMilanka Ringwald                                     little_endian_store_32(event, pos, 0);
952be32e7f1SMilanka Ringwald                                 }
953be32e7f1SMilanka Ringwald                                 pos += 4;
954be32e7f1SMilanka Ringwald                                 break;
955be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_TRACK:
956be32e7f1SMilanka Ringwald                             case AVRCP_MEDIA_ATTR_TOTAL_TRACKS:
957be32e7f1SMilanka Ringwald                                 if (items[attr_id-1].value){
958be32e7f1SMilanka Ringwald                                     event[pos++] = btstack_atoi((char *)items[attr_id-1].value);
959be32e7f1SMilanka Ringwald                                 } else {
960be32e7f1SMilanka Ringwald                                     event[pos++] = 0;
961be32e7f1SMilanka Ringwald                                 }
962be32e7f1SMilanka Ringwald                                 break;
963be32e7f1SMilanka Ringwald                         }
964be32e7f1SMilanka Ringwald                     }
965be32e7f1SMilanka Ringwald                     event[1] = pos - 2;
966be32e7f1SMilanka Ringwald                     // printf_hexdump(event, pos);
967be32e7f1SMilanka Ringwald                     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, pos);
968be32e7f1SMilanka Ringwald                     break;
969be32e7f1SMilanka Ringwald                 }
970be32e7f1SMilanka Ringwald                 default:
971be32e7f1SMilanka Ringwald                     break;
972be32e7f1SMilanka Ringwald             }
973be32e7f1SMilanka Ringwald             break;
974be32e7f1SMilanka Ringwald         case AVRCP_CMD_OPCODE_PASS_THROUGH:{
975be32e7f1SMilanka Ringwald             // 0x80 | connection->cmd_operands[0]
976be32e7f1SMilanka Ringwald             ctype = packet[pos++];
977be32e7f1SMilanka Ringwald             byte_value = packet[pos++];
978be32e7f1SMilanka Ringwald             subunit_type = byte_value >> 3;
979be32e7f1SMilanka Ringwald             subunit_id = byte_value & 0x07;
980be32e7f1SMilanka Ringwald             opcode = packet[pos++];
981be32e7f1SMilanka Ringwald             uint8_t operation_id = packet[pos++];
982be32e7f1SMilanka Ringwald 
983be32e7f1SMilanka Ringwald             if (connection->state == AVCTP_W4_STOP){
984be32e7f1SMilanka Ringwald                 avrcp_emit_operation_status(avrcp_callback, AVRCP_SUBEVENT_OPERATION_START, connection->con_handle, ctype, operation_id);
985be32e7f1SMilanka Ringwald             }
986be32e7f1SMilanka Ringwald             if (connection->state == AVCTP_CONNECTION_OPENED) {
987be32e7f1SMilanka Ringwald                 // RELEASE response
988be32e7f1SMilanka Ringwald                 operation_id = operation_id & 0x7F;
989be32e7f1SMilanka Ringwald                 avrcp_emit_operation_status(avrcp_callback, AVRCP_SUBEVENT_OPERATION_COMPLETE, connection->con_handle, ctype, operation_id);
990be32e7f1SMilanka Ringwald             }
991be32e7f1SMilanka Ringwald             if (connection->state == AVCTP_W2_SEND_RELEASE_COMMAND){
992be32e7f1SMilanka Ringwald                 // PRESS response
993be32e7f1SMilanka Ringwald                 request_pass_through_release_control_cmd(connection);
994be32e7f1SMilanka Ringwald             }
995be32e7f1SMilanka Ringwald             break;
996be32e7f1SMilanka Ringwald         }
997be32e7f1SMilanka Ringwald         default:
998be32e7f1SMilanka Ringwald             break;
999be32e7f1SMilanka Ringwald     }
1000be32e7f1SMilanka Ringwald }
1001be32e7f1SMilanka Ringwald 
1002be32e7f1SMilanka Ringwald static void avrcp_handle_can_send_now(avrcp_connection_t * connection){
1003be32e7f1SMilanka Ringwald     int i;
1004be32e7f1SMilanka Ringwald     switch (connection->state){
1005be32e7f1SMilanka Ringwald         case AVCTP_W2_SEND_PRESS_COMMAND:
1006be32e7f1SMilanka Ringwald             connection->state = AVCTP_W2_RECEIVE_PRESS_RESPONSE;
1007be32e7f1SMilanka Ringwald             break;
1008be32e7f1SMilanka Ringwald         case AVCTP_W2_SEND_COMMAND:
1009be32e7f1SMilanka Ringwald         case AVCTP_W2_SEND_RELEASE_COMMAND:
1010be32e7f1SMilanka Ringwald             connection->state = AVCTP_W2_RECEIVE_RESPONSE;
1011be32e7f1SMilanka Ringwald             break;
1012be32e7f1SMilanka Ringwald         case AVCTP_CONNECTION_OPENED:
1013be32e7f1SMilanka Ringwald             if (connection->disconnect){
1014be32e7f1SMilanka Ringwald                 connection->wait_to_send = 0;
1015be32e7f1SMilanka Ringwald                 connection->disconnect = 0;
1016be32e7f1SMilanka Ringwald                 connection->state = AVCTP_CONNECTION_W4_L2CAP_DISCONNECTED;
1017be32e7f1SMilanka Ringwald                 l2cap_disconnect(connection->l2cap_signaling_cid, 0);
1018be32e7f1SMilanka Ringwald                 return;
1019be32e7f1SMilanka Ringwald             }
1020be32e7f1SMilanka Ringwald             if (connection->notifications_to_register != 0){
1021be32e7f1SMilanka Ringwald                 for (i = 1; i < 13; i++){
1022be32e7f1SMilanka Ringwald                     if (connection->notifications_to_register & (1<<i)){
1023be32e7f1SMilanka Ringwald                         avrcp_prepare_notification(connection, i);
1024be32e7f1SMilanka Ringwald                         avrcp_send_cmd(connection->l2cap_signaling_cid, connection);
1025be32e7f1SMilanka Ringwald                         return;
1026be32e7f1SMilanka Ringwald                     }
1027be32e7f1SMilanka Ringwald                 }
1028be32e7f1SMilanka Ringwald             }
1029be32e7f1SMilanka Ringwald             return;
1030be32e7f1SMilanka Ringwald         default:
1031be32e7f1SMilanka Ringwald             return;
1032be32e7f1SMilanka Ringwald     }
1033be32e7f1SMilanka Ringwald     avrcp_send_cmd(connection->l2cap_signaling_cid, connection);
1034be32e7f1SMilanka Ringwald }
1035be32e7f1SMilanka Ringwald 
1036be32e7f1SMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(bd_addr_t remote_addr){
1037be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = btstack_memory_avrcp_connection_get();
1038be32e7f1SMilanka Ringwald     memset(connection, 0, sizeof(avrcp_connection_t));
1039be32e7f1SMilanka Ringwald     connection->state = AVCTP_CONNECTION_IDLE;
1040be32e7f1SMilanka Ringwald     connection->transaction_label = 0xFF;
1041be32e7f1SMilanka Ringwald     memcpy(connection->remote_addr, remote_addr, 6);
1042be32e7f1SMilanka Ringwald     btstack_linked_list_add(&avrcp_connections, (btstack_linked_item_t *) connection);
1043be32e7f1SMilanka Ringwald     return connection;
1044be32e7f1SMilanka Ringwald }
1045be32e7f1SMilanka Ringwald 
1046be32e7f1SMilanka Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
1047be32e7f1SMilanka Ringwald     bd_addr_t event_addr;
1048be32e7f1SMilanka Ringwald     hci_con_handle_t con_handle;
1049be32e7f1SMilanka Ringwald     uint16_t psm;
1050be32e7f1SMilanka Ringwald     uint16_t local_cid;
1051be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = NULL;
1052be32e7f1SMilanka Ringwald 
1053be32e7f1SMilanka Ringwald     switch (packet_type) {
1054be32e7f1SMilanka Ringwald         case L2CAP_DATA_PACKET:
1055be32e7f1SMilanka Ringwald             connection = get_avrcp_connection_for_l2cap_signaling_cid(channel);
1056be32e7f1SMilanka Ringwald             if (!connection) break;
1057be32e7f1SMilanka Ringwald             avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
1058be32e7f1SMilanka Ringwald             break;
1059be32e7f1SMilanka Ringwald 
1060be32e7f1SMilanka Ringwald         case HCI_EVENT_PACKET:
1061be32e7f1SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
1062be32e7f1SMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
1063be32e7f1SMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
1064be32e7f1SMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
1065be32e7f1SMilanka Ringwald 
1066be32e7f1SMilanka Ringwald                     connection = get_avrcp_connection_for_bd_addr(event_addr);
1067be32e7f1SMilanka Ringwald                     if (!connection){
1068be32e7f1SMilanka Ringwald                         connection = avrcp_create_connection(event_addr);
1069be32e7f1SMilanka Ringwald                         connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
1070be32e7f1SMilanka Ringwald                         l2cap_accept_connection(local_cid);
1071be32e7f1SMilanka Ringwald                         break;
1072be32e7f1SMilanka Ringwald                     }
1073be32e7f1SMilanka Ringwald                     break;
1074be32e7f1SMilanka Ringwald 
1075be32e7f1SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
1076be32e7f1SMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
1077be32e7f1SMilanka Ringwald 
1078be32e7f1SMilanka Ringwald                     if (l2cap_event_channel_opened_get_status(packet)){
1079be32e7f1SMilanka Ringwald                         log_error("L2CAP connection to connection %s failed. status code 0x%02x",
1080be32e7f1SMilanka Ringwald                             bd_addr_to_str(event_addr), l2cap_event_channel_opened_get_status(packet));
1081be32e7f1SMilanka Ringwald                         break;
1082be32e7f1SMilanka Ringwald                     }
1083be32e7f1SMilanka Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
1084*235946f1SMatthias Ringwald                     if (psm != BLUETOOTH_PROTOCOL_AVCTP){
1085be32e7f1SMilanka Ringwald                         log_error("unexpected PSM - Not implemented yet: L2CAP_EVENT_CHANNEL_OPENED");
1086be32e7f1SMilanka Ringwald                         return;
1087be32e7f1SMilanka Ringwald                     }
1088be32e7f1SMilanka Ringwald 
1089be32e7f1SMilanka Ringwald                     connection = get_avrcp_connection_for_bd_addr(event_addr);
1090be32e7f1SMilanka Ringwald                     if (!connection) break;
1091be32e7f1SMilanka Ringwald 
1092be32e7f1SMilanka Ringwald                     con_handle = l2cap_event_channel_opened_get_handle(packet);
1093be32e7f1SMilanka Ringwald                     local_cid  = l2cap_event_channel_opened_get_local_cid(packet);
1094be32e7f1SMilanka Ringwald                     // printf("L2CAP_EVENT_CHANNEL_OPENED: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
1095be32e7f1SMilanka Ringwald                     //        bd_addr_to_str(event_addr), con_handle, psm, local_cid,  l2cap_event_channel_opened_get_remote_cid(packet));
1096be32e7f1SMilanka Ringwald                     if (connection->l2cap_signaling_cid == 0) {
1097be32e7f1SMilanka Ringwald                         connection->l2cap_signaling_cid = local_cid;
1098be32e7f1SMilanka Ringwald                         connection->con_handle = con_handle;
1099be32e7f1SMilanka Ringwald                         connection->state = AVCTP_CONNECTION_OPENED;
1100be32e7f1SMilanka Ringwald                         avrcp_emit_connection_established(avrcp_callback, con_handle, 0, local_cid, event_addr);
1101be32e7f1SMilanka Ringwald                         break;
1102be32e7f1SMilanka Ringwald                     }
1103be32e7f1SMilanka Ringwald                     break;
1104be32e7f1SMilanka Ringwald 
1105be32e7f1SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
1106be32e7f1SMilanka Ringwald                     connection = get_avrcp_connection_for_l2cap_signaling_cid(channel);
1107be32e7f1SMilanka Ringwald                     if (!connection) break;
1108be32e7f1SMilanka Ringwald                     avrcp_handle_can_send_now(connection);
1109be32e7f1SMilanka Ringwald                     break;
1110be32e7f1SMilanka Ringwald 
1111be32e7f1SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
1112be32e7f1SMilanka Ringwald                     // data: event (8), len(8), channel (16)
1113be32e7f1SMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
1114be32e7f1SMilanka Ringwald                     connection = get_avrcp_connection_for_l2cap_signaling_cid(local_cid);
1115be32e7f1SMilanka Ringwald                     if (connection){
1116be32e7f1SMilanka Ringwald                         avrcp_emit_connection_closed(avrcp_callback, connection->con_handle);
1117be32e7f1SMilanka Ringwald                         btstack_linked_list_remove(&avrcp_connections, (btstack_linked_item_t*) connection);
1118be32e7f1SMilanka Ringwald                         break;
1119be32e7f1SMilanka Ringwald                     }
1120be32e7f1SMilanka Ringwald                     break;
1121be32e7f1SMilanka Ringwald                 default:
1122be32e7f1SMilanka Ringwald                     break;
1123be32e7f1SMilanka Ringwald             }
1124be32e7f1SMilanka Ringwald             break;
1125be32e7f1SMilanka Ringwald         default:
1126be32e7f1SMilanka Ringwald             break;
1127be32e7f1SMilanka Ringwald     }
1128be32e7f1SMilanka Ringwald }
1129be32e7f1SMilanka Ringwald 
1130be32e7f1SMilanka Ringwald void avrcp_init(void){
1131be32e7f1SMilanka Ringwald     avrcp_connections = NULL;
1132*235946f1SMatthias Ringwald     l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0);
1133be32e7f1SMilanka Ringwald }
1134be32e7f1SMilanka Ringwald 
1135be32e7f1SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){
1136be32e7f1SMilanka Ringwald     if (callback == NULL){
1137be32e7f1SMilanka Ringwald         log_error("avrcp_register_packet_handler called with NULL callback");
1138be32e7f1SMilanka Ringwald         return;
1139be32e7f1SMilanka Ringwald     }
1140be32e7f1SMilanka Ringwald     avrcp_callback = callback;
1141be32e7f1SMilanka Ringwald }
1142be32e7f1SMilanka Ringwald 
1143be32e7f1SMilanka Ringwald void avrcp_connect(bd_addr_t bd_addr){
1144be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_bd_addr(bd_addr);
1145be32e7f1SMilanka Ringwald     if (!connection){
1146be32e7f1SMilanka Ringwald         connection = avrcp_create_connection(bd_addr);
1147be32e7f1SMilanka Ringwald     }
1148be32e7f1SMilanka Ringwald     if (!connection){
1149be32e7f1SMilanka Ringwald         log_error("avrcp: could not find or create a connection.");
1150be32e7f1SMilanka Ringwald         return;
1151be32e7f1SMilanka Ringwald     }
1152be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_IDLE) return;
1153be32e7f1SMilanka Ringwald     connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
1154*235946f1SMatthias Ringwald     l2cap_create_channel(packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, NULL);
1155be32e7f1SMilanka Ringwald }
1156be32e7f1SMilanka Ringwald 
1157be32e7f1SMilanka Ringwald void avrcp_unit_info(uint16_t con_handle){
1158be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1159be32e7f1SMilanka Ringwald     if (!connection){
1160be32e7f1SMilanka Ringwald         log_error("avrcp_unit_info: could not find a connection.");
1161be32e7f1SMilanka Ringwald         return;
1162be32e7f1SMilanka Ringwald     }
1163be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1164be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1165be32e7f1SMilanka Ringwald 
1166be32e7f1SMilanka Ringwald     connection->transaction_label++;
1167be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_UNIT_INFO;
1168be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_STATUS;
1169be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique
1170be32e7f1SMilanka Ringwald     connection->subunit_id =   AVRCP_SUBUNIT_ID_IGNORE;
1171be32e7f1SMilanka Ringwald     memset(connection->cmd_operands, 0xFF, connection->cmd_operands_lenght);
1172be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = 5;
1173be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1174be32e7f1SMilanka Ringwald }
1175be32e7f1SMilanka Ringwald 
1176be32e7f1SMilanka Ringwald static void avrcp_get_capabilities(uint16_t con_handle, uint8_t capability_id){
1177be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1178be32e7f1SMilanka Ringwald     if (!connection){
1179be32e7f1SMilanka Ringwald         log_error("avrcp_get_capabilities: could not find a connection.");
1180be32e7f1SMilanka Ringwald         return;
1181be32e7f1SMilanka Ringwald     }
1182be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1183be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1184be32e7f1SMilanka Ringwald 
1185be32e7f1SMilanka Ringwald     connection->transaction_label++;
1186be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
1187be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_STATUS;
1188be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
1189be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
1190be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID);
1191be32e7f1SMilanka Ringwald     connection->cmd_operands[3] = AVRCP_PDU_ID_GET_CAPABILITIES; // PDU ID
1192be32e7f1SMilanka Ringwald     connection->cmd_operands[4] = 0;
1193be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, 5, 1); // parameter length
1194be32e7f1SMilanka Ringwald     connection->cmd_operands[7] = capability_id;                  // capability ID
1195be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = 8;
1196be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1197be32e7f1SMilanka Ringwald }
1198be32e7f1SMilanka Ringwald 
1199be32e7f1SMilanka Ringwald void avrcp_get_supported_company_ids(uint16_t con_handle){
1200be32e7f1SMilanka Ringwald     avrcp_get_capabilities(con_handle, AVRCP_CAPABILITY_ID_COMPANY);
1201be32e7f1SMilanka Ringwald }
1202be32e7f1SMilanka Ringwald 
1203be32e7f1SMilanka Ringwald void avrcp_get_supported_events(uint16_t con_handle){
1204be32e7f1SMilanka Ringwald     avrcp_get_capabilities(con_handle, AVRCP_CAPABILITY_ID_EVENT);
1205be32e7f1SMilanka Ringwald }
1206be32e7f1SMilanka Ringwald 
1207be32e7f1SMilanka Ringwald 
1208be32e7f1SMilanka Ringwald void avrcp_play(uint16_t con_handle){
1209be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_PLAY, 0);
1210be32e7f1SMilanka Ringwald }
1211be32e7f1SMilanka Ringwald 
1212be32e7f1SMilanka Ringwald void avrcp_stop(uint16_t con_handle){
1213be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_STOP, 0);
1214be32e7f1SMilanka Ringwald }
1215be32e7f1SMilanka Ringwald 
1216be32e7f1SMilanka Ringwald void avrcp_pause(uint16_t con_handle){
1217be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_PAUSE, 0);
1218be32e7f1SMilanka Ringwald }
1219be32e7f1SMilanka Ringwald 
1220be32e7f1SMilanka Ringwald void avrcp_forward(uint16_t con_handle){
1221be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_FORWARD, 0);
1222be32e7f1SMilanka Ringwald }
1223be32e7f1SMilanka Ringwald 
1224be32e7f1SMilanka Ringwald void avrcp_backward(uint16_t con_handle){
1225be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_BACKWARD, 0);
1226be32e7f1SMilanka Ringwald }
1227be32e7f1SMilanka Ringwald 
1228be32e7f1SMilanka Ringwald void avrcp_start_rewind(uint16_t con_handle){
1229be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_REWIND, 0);
1230be32e7f1SMilanka Ringwald }
1231be32e7f1SMilanka Ringwald 
1232be32e7f1SMilanka Ringwald void avrcp_volume_up(uint16_t con_handle){
1233be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_VOLUME_UP, 0);
1234be32e7f1SMilanka Ringwald }
1235be32e7f1SMilanka Ringwald 
1236be32e7f1SMilanka Ringwald void avrcp_volume_down(uint16_t con_handle){
1237be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_VOLUME_DOWN, 0);
1238be32e7f1SMilanka Ringwald }
1239be32e7f1SMilanka Ringwald 
1240be32e7f1SMilanka Ringwald void avrcp_mute(uint16_t con_handle){
1241be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_MUTE, 0);
1242be32e7f1SMilanka Ringwald }
1243be32e7f1SMilanka Ringwald 
1244be32e7f1SMilanka Ringwald void avrcp_skip(uint16_t con_handle){
1245be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_SKIP, 0);
1246be32e7f1SMilanka Ringwald }
1247be32e7f1SMilanka Ringwald 
1248be32e7f1SMilanka Ringwald void avrcp_stop_rewind(uint16_t con_handle){
1249be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1250be32e7f1SMilanka Ringwald     if (!connection){
1251be32e7f1SMilanka Ringwald         log_error("avrcp_stop_rewind: could not find a connection.");
1252be32e7f1SMilanka Ringwald         return;
1253be32e7f1SMilanka Ringwald     }
1254be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_W4_STOP) return;
1255be32e7f1SMilanka Ringwald     request_pass_through_release_control_cmd(connection);
1256be32e7f1SMilanka Ringwald }
1257be32e7f1SMilanka Ringwald 
1258be32e7f1SMilanka Ringwald void avrcp_start_fast_forward(uint16_t con_handle){
1259be32e7f1SMilanka Ringwald     request_pass_through_press_control_cmd(con_handle, AVRCP_OPERATION_ID_FAST_FORWARD, 0);
1260be32e7f1SMilanka Ringwald }
1261be32e7f1SMilanka Ringwald 
1262be32e7f1SMilanka Ringwald void avrcp_stop_fast_forward(uint16_t con_handle){
1263be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1264be32e7f1SMilanka Ringwald     if (!connection){
1265be32e7f1SMilanka Ringwald         log_error("avrcp_stop_fast_forward: could not find a connection.");
1266be32e7f1SMilanka Ringwald         return;
1267be32e7f1SMilanka Ringwald     }
1268be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_W4_STOP) return;
1269be32e7f1SMilanka Ringwald     request_pass_through_release_control_cmd(connection);
1270be32e7f1SMilanka Ringwald }
1271be32e7f1SMilanka Ringwald 
1272be32e7f1SMilanka Ringwald void avrcp_get_play_status(uint16_t con_handle){
1273be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1274be32e7f1SMilanka Ringwald     if (!connection){
1275be32e7f1SMilanka Ringwald         log_error("avrcp_get_play_status: could not find a connection.");
1276be32e7f1SMilanka Ringwald         return;
1277be32e7f1SMilanka Ringwald     }
1278be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1279be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1280be32e7f1SMilanka Ringwald 
1281be32e7f1SMilanka Ringwald     connection->transaction_label++;
1282be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
1283be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_STATUS;
1284be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
1285be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
1286be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID);
1287be32e7f1SMilanka Ringwald     connection->cmd_operands[3] = AVRCP_PDU_ID_GET_PLAY_STATUS;
1288be32e7f1SMilanka Ringwald     connection->cmd_operands[4] = 0;                     // reserved(upper 6) | packet_type -> 0
1289be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, 5, 0); // parameter length
1290be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = 7;
1291be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1292be32e7f1SMilanka Ringwald }
1293be32e7f1SMilanka Ringwald 
1294be32e7f1SMilanka Ringwald void avrcp_enable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id){
1295be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1296be32e7f1SMilanka Ringwald     if (!connection){
1297be32e7f1SMilanka Ringwald         log_error("avrcp_get_play_status: could not find a connection.");
1298be32e7f1SMilanka Ringwald         return;
1299be32e7f1SMilanka Ringwald     }
1300be32e7f1SMilanka Ringwald     avrcp_register_notification(connection, event_id);
1301be32e7f1SMilanka Ringwald }
1302be32e7f1SMilanka Ringwald 
1303be32e7f1SMilanka Ringwald void avrcp_disable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id){
1304be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1305be32e7f1SMilanka Ringwald     if (!connection){
1306be32e7f1SMilanka Ringwald         log_error("avrcp_get_play_status: could not find a connection.");
1307be32e7f1SMilanka Ringwald         return;
1308be32e7f1SMilanka Ringwald     }
1309be32e7f1SMilanka Ringwald     connection->notifications_to_deregister |= (1 << event_id);
1310be32e7f1SMilanka Ringwald }
1311be32e7f1SMilanka Ringwald 
1312be32e7f1SMilanka Ringwald void avrcp_get_now_playing_info(uint16_t con_handle){
1313be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1314be32e7f1SMilanka Ringwald     if (!connection){
1315be32e7f1SMilanka Ringwald         log_error("avrcp_get_capabilities: could not find a connection.");
1316be32e7f1SMilanka Ringwald         return;
1317be32e7f1SMilanka Ringwald     }
1318be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1319be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1320be32e7f1SMilanka Ringwald 
1321be32e7f1SMilanka Ringwald     connection->transaction_label++;
1322be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
1323be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_STATUS;
1324be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
1325be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
1326be32e7f1SMilanka Ringwald     int pos = 0;
1327be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
1328be32e7f1SMilanka Ringwald     pos += 3;
1329be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES; // PDU ID
1330be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = 0;
1331be32e7f1SMilanka Ringwald 
1332be32e7f1SMilanka Ringwald     // Parameter Length
1333be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, pos, 9);
1334be32e7f1SMilanka Ringwald     pos += 2;
1335be32e7f1SMilanka Ringwald 
1336be32e7f1SMilanka Ringwald     // write 8 bytes value
1337be32e7f1SMilanka Ringwald     memset(connection->cmd_operands + pos, 0, 8); // identifier: PLAYING
1338be32e7f1SMilanka Ringwald     pos += 8;
1339be32e7f1SMilanka Ringwald 
1340be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = 0; // attribute count, if 0 get all attributes
1341be32e7f1SMilanka Ringwald     // every attribute is 4 bytes long
1342be32e7f1SMilanka Ringwald 
1343be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = pos;
1344be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1345be32e7f1SMilanka Ringwald 
1346be32e7f1SMilanka Ringwald }
1347be32e7f1SMilanka Ringwald 
1348be32e7f1SMilanka Ringwald void avrcp_set_absolute_volume(uint16_t con_handle, uint8_t volume){
1349be32e7f1SMilanka Ringwald      avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1350be32e7f1SMilanka Ringwald     if (!connection){
1351be32e7f1SMilanka Ringwald         log_error("avrcp_get_capabilities: could not find a connection.");
1352be32e7f1SMilanka Ringwald         return;
1353be32e7f1SMilanka Ringwald     }
1354be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1355be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1356be32e7f1SMilanka Ringwald 
1357be32e7f1SMilanka Ringwald     connection->transaction_label++;
1358be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
1359be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_CONTROL;
1360be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
1361be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
1362be32e7f1SMilanka Ringwald     int pos = 0;
1363be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
1364be32e7f1SMilanka Ringwald     pos += 3;
1365be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME; // PDU ID
1366be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = 0;
1367be32e7f1SMilanka Ringwald 
1368be32e7f1SMilanka Ringwald     // Parameter Length
1369be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, pos, 1);
1370be32e7f1SMilanka Ringwald     pos += 2;
1371be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = volume;
1372be32e7f1SMilanka Ringwald 
1373be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = pos;
1374be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1375be32e7f1SMilanka Ringwald }
1376be32e7f1SMilanka Ringwald 
1377be32e7f1SMilanka Ringwald void avrcp_query_shuffle_and_repeat_modes(uint16_t con_handle){
1378be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1379be32e7f1SMilanka Ringwald     if (!connection){
1380be32e7f1SMilanka Ringwald         log_error("avrcp_get_capabilities: could not find a connection.");
1381be32e7f1SMilanka Ringwald         return;
1382be32e7f1SMilanka Ringwald     }
1383be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1384be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1385be32e7f1SMilanka Ringwald 
1386be32e7f1SMilanka Ringwald     connection->transaction_label++;
1387be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
1388be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_STATUS;
1389be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
1390be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
1391be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID);
1392be32e7f1SMilanka Ringwald     connection->cmd_operands[3] = AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue; // PDU ID
1393be32e7f1SMilanka Ringwald     connection->cmd_operands[4] = 0;
1394be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, 5, 5); // parameter length
1395be32e7f1SMilanka Ringwald     connection->cmd_operands[7] = 4;                     // NumPlayerApplicationSettingAttributeID
1396be32e7f1SMilanka Ringwald     // PlayerApplicationSettingAttributeID1 AVRCP Spec, Appendix F, 133
1397be32e7f1SMilanka Ringwald     connection->cmd_operands[8]  = 0x01;    // equalizer  (1-OFF, 2-ON)
1398be32e7f1SMilanka Ringwald     connection->cmd_operands[9]  = 0x02;    // repeat     (1-off, 2-single track, 3-all tracks, 4-group repeat)
1399be32e7f1SMilanka Ringwald     connection->cmd_operands[10] = 0x03;    // shuffle    (1-off, 2-all tracks, 3-group shuffle)
1400be32e7f1SMilanka Ringwald     connection->cmd_operands[11] = 0x04;    // scan       (1-off, 2-all tracks, 3-group scan)
1401be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = 12;
1402be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1403be32e7f1SMilanka Ringwald }
1404be32e7f1SMilanka Ringwald 
1405be32e7f1SMilanka Ringwald 
1406be32e7f1SMilanka Ringwald static void avrcp_set_current_player_application_setting_value(uint16_t con_handle, uint8_t attribute_id, uint8_t attribute_value){
1407be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1408be32e7f1SMilanka Ringwald     if (!connection){
1409be32e7f1SMilanka Ringwald         log_error("avrcp_get_capabilities: could not find a connection.");
1410be32e7f1SMilanka Ringwald         return;
1411be32e7f1SMilanka Ringwald     }
1412be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1413be32e7f1SMilanka Ringwald     connection->state = AVCTP_W2_SEND_COMMAND;
1414be32e7f1SMilanka Ringwald 
1415be32e7f1SMilanka Ringwald     connection->transaction_label++;
1416be32e7f1SMilanka Ringwald     connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
1417be32e7f1SMilanka Ringwald     connection->command_type = AVRCP_CTYPE_CONTROL;
1418be32e7f1SMilanka Ringwald     connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
1419be32e7f1SMilanka Ringwald     connection->subunit_id = 0;
1420be32e7f1SMilanka Ringwald     int pos = 0;
1421be32e7f1SMilanka Ringwald     big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
1422be32e7f1SMilanka Ringwald     pos += 3;
1423be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = AVRCP_PDU_ID_SetPlayerApplicationSettingValue; // PDU ID
1424be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = 0;
1425be32e7f1SMilanka Ringwald     // Parameter Length
1426be32e7f1SMilanka Ringwald     big_endian_store_16(connection->cmd_operands, pos, 3);
1427be32e7f1SMilanka Ringwald     pos += 2;
1428be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++] = 2;
1429be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = pos;
1430be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++]  = attribute_id;
1431be32e7f1SMilanka Ringwald     connection->cmd_operands[pos++]  = attribute_value;
1432be32e7f1SMilanka Ringwald     connection->cmd_operands_lenght = pos;
1433be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1434be32e7f1SMilanka Ringwald }
1435be32e7f1SMilanka Ringwald 
1436be32e7f1SMilanka Ringwald void avrcp_set_shuffle_mode(uint16_t con_handle, avrcp_shuffle_mode_t mode){
1437be32e7f1SMilanka Ringwald     if (mode < AVRCP_SHUFFLE_MODE_OFF || mode > AVRCP_SHUFFLE_MODE_GROUP) return;
1438be32e7f1SMilanka Ringwald     avrcp_set_current_player_application_setting_value(con_handle, 0x03, mode);
1439be32e7f1SMilanka Ringwald }
1440be32e7f1SMilanka Ringwald 
1441be32e7f1SMilanka Ringwald void avrcp_set_repeat_mode(uint16_t con_handle, avrcp_repeat_mode_t mode){
1442be32e7f1SMilanka Ringwald     if (mode < AVRCP_REPEAT_MODE_OFF || mode > AVRCP_REPEAT_MODE_GROUP) return;
1443be32e7f1SMilanka Ringwald     avrcp_set_current_player_application_setting_value(con_handle, 0x02, mode);
1444be32e7f1SMilanka Ringwald }
1445be32e7f1SMilanka Ringwald 
1446be32e7f1SMilanka Ringwald void avrcp_disconnect(uint16_t con_handle){
1447be32e7f1SMilanka Ringwald     avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
1448be32e7f1SMilanka Ringwald     if (!connection){
1449be32e7f1SMilanka Ringwald         log_error("avrcp_get_capabilities: could not find a connection.");
1450be32e7f1SMilanka Ringwald         return;
1451be32e7f1SMilanka Ringwald     }
1452be32e7f1SMilanka Ringwald     if (connection->state != AVCTP_CONNECTION_OPENED) return;
1453be32e7f1SMilanka Ringwald     if (connection->state == AVCTP_CONNECTION_W4_L2CAP_DISCONNECTED) return;
1454be32e7f1SMilanka Ringwald 
1455be32e7f1SMilanka Ringwald     connection->disconnect = 1;
1456be32e7f1SMilanka Ringwald     avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
1457be32e7f1SMilanka Ringwald }