hsp_hs_demo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * Copyright (C) 2014 BlueKitchen GmbH
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. * 4. Any redistribution, use, or modification is done solely for
  17. * personal benefit and not for any commercial purpose or for
  18. * monetary gain.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
  24. * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * Please inquire about commercial licensing options at
  34. * contact@bluekitchen-gmbh.com
  35. *
  36. */
  37. #define BTSTACK_FILE__ "hsp_hs_demo.c"
  38. /*
  39. * hsp_hs_demo.c
  40. */
  41. // *****************************************************************************
  42. /* EXAMPLE_START(hsp_hs_demo): HSP Headset Demo
  43. *
  44. * @text This example implements a HSP Headset device that sends and receives
  45. * audio signal over HCI SCO. It demonstrates how to receive
  46. * an output from a remote audio gateway (AG), and,
  47. * if HAVE_BTSTACK_STDIN is defined, how to control the AG.
  48. */
  49. // *****************************************************************************
  50. #include "btstack_config.h"
  51. #include <stdint.h>
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include "btstack.h"
  56. #include "sco_demo_util.h"
  57. #ifdef HAVE_BTSTACK_STDIN
  58. #include "btstack_stdin.h"
  59. #endif
  60. static btstack_packet_callback_registration_t hci_event_callback_registration;
  61. static uint8_t hsp_service_buffer[150];
  62. static const uint8_t rfcomm_channel_nr = 1;
  63. static const char hsp_hs_service_name[] = "Headset Test";
  64. static hci_con_handle_t sco_handle = HCI_CON_HANDLE_INVALID;
  65. static char hs_cmd_buffer[100];
  66. // mac 2013:
  67. static const char * device_addr_string = "84:38:35:65:d1:15";
  68. static bd_addr_t device_addr;
  69. /* @section Audio Transfer Setup
  70. *
  71. * @text A pre-computed sine wave (160Hz) is used as the input audio signal. 160 Hz.
  72. * To send and receive an audio signal, ENABLE_SCO_OVER_HCI has to be defined.
  73. *
  74. * Tested working setups:
  75. * - Ubuntu 14 64-bit, CC2564B connected via FTDI USB-2-UART adapter, 921600 baud
  76. * - Ubuntu 14 64-bit, CSR USB dongle
  77. * - OS X 10.11, CSR USB dongle
  78. *
  79. * Broken setups:
  80. * - OS X 10.11, CC2564B connected via FDTI USB-2-UART adapter, 921600 baud
  81. * - select(..) blocks > 400 ms -> num completed is received to late -> gaps between audio
  82. * - looks like bug in select->FTDI driver as it works correct on Linux
  83. *
  84. * SCO not routed over HCI yet:
  85. * - CSR UART dongle
  86. * - Broadcom USB dongle
  87. * - Broadcom UART chipset
  88. * - ..
  89. *
  90. */
  91. static void show_usage(void){
  92. bd_addr_t iut_address;
  93. gap_local_bd_addr(iut_address);
  94. printf("\n--- Bluetooth HSP Headset Test Console %s ---\n", bd_addr_to_str(iut_address));
  95. printf("---\n");
  96. printf("c - Connect to %s\n", bd_addr_to_str(device_addr));
  97. printf("C - Disconnect\n");
  98. printf("a - establish audio connection\n");
  99. printf("A - release audio connection\n");
  100. printf("b - press user button\n");
  101. printf("z - set microphone gain 0\n");
  102. printf("m - set microphone gain 8\n");
  103. printf("M - set microphone gain 15\n");
  104. printf("o - set speaker gain 0\n");
  105. printf("s - set speaker gain 8\n");
  106. printf("S - set speaker gain 15\n");
  107. printf("\n");
  108. }
  109. #ifdef HAVE_BTSTACK_STDIN
  110. static void stdin_process(char c){
  111. switch (c){
  112. case 'c':
  113. printf("Connect to %s\n", bd_addr_to_str(device_addr));
  114. hsp_hs_connect(device_addr);
  115. break;
  116. case 'C':
  117. printf("Disconnect.\n");
  118. hsp_hs_disconnect();
  119. break;
  120. case 'a':
  121. printf("Establish audio connection\n");
  122. hsp_hs_establish_audio_connection();
  123. break;
  124. case 'A':
  125. printf("Release audio connection\n");
  126. hsp_hs_release_audio_connection();
  127. break;
  128. case 'z':
  129. printf("Setting microphone gain 0\n");
  130. hsp_hs_set_microphone_gain(0);
  131. break;
  132. case 'm':
  133. printf("Setting microphone gain 8\n");
  134. hsp_hs_set_microphone_gain(8);
  135. break;
  136. case 'M':
  137. printf("Setting microphone gain 15\n");
  138. hsp_hs_set_microphone_gain(15);
  139. break;
  140. case 'o':
  141. printf("Setting speaker gain 0\n");
  142. hsp_hs_set_speaker_gain(0);
  143. break;
  144. case 's':
  145. printf("Setting speaker gain 8\n");
  146. hsp_hs_set_speaker_gain(8);
  147. break;
  148. case 'S':
  149. printf("Setting speaker gain 15\n");
  150. hsp_hs_set_speaker_gain(15);
  151. break;
  152. case 'b':
  153. printf("Press user button\n");
  154. hsp_hs_send_button_press();
  155. break;
  156. default:
  157. show_usage();
  158. break;
  159. }
  160. }
  161. #endif
  162. static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){
  163. UNUSED(channel);
  164. switch (packet_type){
  165. case HCI_SCO_DATA_PACKET:
  166. sco_demo_receive(event, event_size);
  167. break;
  168. case HCI_EVENT_PACKET:
  169. switch (event[0]) {
  170. case BTSTACK_EVENT_STATE:
  171. if (btstack_event_state_get_state(event) != HCI_STATE_WORKING) break;
  172. show_usage();
  173. break;
  174. case HCI_EVENT_SCO_CAN_SEND_NOW:
  175. if (READ_SCO_CONNECTION_HANDLE(event) != sco_handle) break;
  176. sco_demo_send(sco_handle);
  177. break;
  178. case HCI_EVENT_HSP_META:
  179. switch (event[2]) {
  180. case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE:
  181. if (hsp_subevent_rfcomm_connection_complete_get_status(event)){
  182. printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_rfcomm_connection_complete_get_status(event));
  183. } else {
  184. printf("RFCOMM connection established.\n");
  185. }
  186. break;
  187. case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
  188. if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){
  189. printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event));
  190. } else {
  191. printf("RFCOMM disconnected.\n");
  192. }
  193. break;
  194. case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE:
  195. if (hsp_subevent_audio_connection_complete_get_status(event)){
  196. printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event));
  197. } else {
  198. sco_handle = hsp_subevent_audio_connection_complete_get_handle(event);
  199. printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle);
  200. hci_request_sco_can_send_now_event();
  201. }
  202. break;
  203. case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
  204. printf("Audio connection released.\n\n");
  205. sco_handle = HCI_CON_HANDLE_INVALID;
  206. break;
  207. case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
  208. printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
  209. break;
  210. case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED:
  211. printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
  212. break;
  213. case HSP_SUBEVENT_RING:
  214. printf("HS: RING RING!\n");
  215. break;
  216. case HSP_SUBEVENT_AG_INDICATION: {
  217. memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer));
  218. unsigned int size = hsp_subevent_ag_indication_get_value_length(event);
  219. if (size >= sizeof(hs_cmd_buffer)-1){
  220. size = sizeof(hs_cmd_buffer)-1;
  221. }
  222. memcpy(hs_cmd_buffer, hsp_subevent_ag_indication_get_value(event), size);
  223. printf("Received custom indication: \"%s\". \nExit code or call hsp_hs_send_result.\n", hs_cmd_buffer);
  224. }
  225. break;
  226. default:
  227. printf("event not handled %u\n", event[2]);
  228. break;
  229. }
  230. break;
  231. default:
  232. break;
  233. }
  234. default:
  235. break;
  236. }
  237. }
  238. /* @section Main Application Setup
  239. *
  240. * @text Listing MainConfiguration shows main application code.
  241. * To run a HSP Headset service you need to initialize the SDP, and to create and register HSP HS record with it.
  242. * In this example, the SCO over HCI is used to receive and send an audio signal.
  243. *
  244. * Two packet handlers are registered:
  245. * - The HCI SCO packet handler receives audio data.
  246. * - The HSP HS packet handler is used to trigger sending of audio data and commands to the AG. It also receives the AG's answers.
  247. *
  248. * The stdin_process callback allows for sending commands to the AG.
  249. * At the end the Bluetooth stack is started.
  250. */
  251. /* LISTING_START(MainConfiguration): Setup HSP Headset */
  252. int btstack_main(int argc, const char * argv[]);
  253. int btstack_main(int argc, const char * argv[]){
  254. (void)argc;
  255. (void)argv;
  256. sco_demo_init();
  257. sco_demo_set_codec(HFP_CODEC_CVSD);
  258. l2cap_init();
  259. sdp_init();
  260. memset(hsp_service_buffer, 0, sizeof(hsp_service_buffer));
  261. hsp_hs_create_sdp_record(hsp_service_buffer, 0x10001, rfcomm_channel_nr, hsp_hs_service_name, 0);
  262. sdp_register_service(hsp_service_buffer);
  263. rfcomm_init();
  264. hsp_hs_init(rfcomm_channel_nr);
  265. // register for HCI events and SCO packets
  266. hci_event_callback_registration.callback = &packet_handler;
  267. hci_add_event_handler(&hci_event_callback_registration);
  268. hci_register_sco_packet_handler(&packet_handler);
  269. // register for HSP events
  270. hsp_hs_register_packet_handler(packet_handler);
  271. #ifdef HAVE_BTSTACK_STDIN
  272. btstack_stdin_setup(stdin_process);
  273. #endif
  274. gap_set_local_name("HSP HS Demo 00:00:00:00:00:00");
  275. gap_discoverable_control(1);
  276. gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
  277. gap_set_class_of_device(0x240404);
  278. // Parse human readable Bluetooth address.
  279. sscanf_bd_addr(device_addr_string, device_addr);
  280. // turn on!
  281. hci_power_control(HCI_POWER_ON);
  282. return 0;
  283. }
  284. /* LISTING_END */
  285. /* EXAMPLE_END */