2265 lines
57 KiB
C
Raw Permalink Normal View History

2025-05-10 21:58:58 +08:00
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#include <pthread.h>
#include <RkBtBase.h>
#include <RkBtSink.h>
#include <RkBtSource.h>
#include <RkBle.h>
#include <RkBtSpp.h>
#include <RkBtHfp.h>
#include <RkBleClient.h>
#include <RkBtObex.h>
#include <RkBtPan.h>
#include "bt_test.h"
/* Immediate wifi Service UUID */
#define BLE_UUID_SERVICE "00001111-0000-1000-8000-00805F9B34FB"
#define BLE_UUID_WIFI_CHAR "00002222-0000-1000-8000-00805F9B34FB"
#define BLE_UUID_PROXIMITY "7B931104-1810-4CBC-94DA-875C8067F845"
#define BLE_UUID_SEND "dfd4416e-1810-47f7-8248-eb8be3dc47f9"
#define BLE_UUID_RECV "9884d812-1810-4a24-94d3-b2c11a851fac"
#define SERVICE_UUID "00001910-0000-1000-8000-00805f9b34fb"
#define HFP_PCM_CHANNEL_NB 2
#define CVSD_SAMPLE_RATE 8000
#define MSBC_SAMPLE_RATE 16000
#define READ_FRAME_256 256
#define BUFFER_SIZE_1024 1024
#define PERIOD_SIZE_256 READ_FRAME_256
#define READ_FRAME_512 512
#define BUFFER_SIZE_2048 2048
#define PERIOD_SIZE_512 READ_FRAME_512
#define READ_FRAME_1024 1024
#define BUFFER_SIZE_4096 4096
#define PERIOD_SIZE_1024 READ_FRAME_1024
static const char *alsa_playback_device = "default";
static const char *alsa_capture_device = "6mic_loopback"; //"2mic_loopback";
static const char *bt_playback_device = "hw:1,0";
static const char *bt_capture_device = "hw:1,0";
typedef struct {
unsigned int channels;
unsigned int sample_rate;
snd_pcm_uframes_t period_size;
snd_pcm_uframes_t buffer_size;
} alsa_config_t;
typedef struct {
bool alsa_duplex_opened;
bool bt_duplex_opened;
pthread_t alsa_tid;
pthread_t bt_tid;
} duplex_info_t;
static duplex_info_t g_duplex_control = {
false,
false,
0,
0,
};
static RkBtScanedDevice *g_paired_dev_list;
static unsigned int g_mtu = 0;
static void bt_test_ble_recv_data_callback(const char *uuid, char *data, int len);
static void bt_test_ble_request_data_callback(const char *uuid, char *data, int *len);
/* Must be initialized before using Bluetooth ble */
static RkBtContent bt_content;
static RK_BT_SCO_CODEC_TYPE sco_codec = BT_SCO_CODEC_CVSD;
/******************************************/
/* BT base server init */
/******************************************/
static volatile bool gonff = false;
static void bt_test_state_cb(RK_BT_STATE state)
{
switch(state) {
case RK_BT_STATE_TURNING_ON:
printf("++++++++++ RK_BT_STATE_TURNING_ON ++++++++++\n");
break;
case RK_BT_STATE_ON:
printf("++++++++++ RK_BT_STATE_ON ++++++++++\n");
gonff = true;
break;
case RK_BT_STATE_TURNING_OFF:
printf("++++++++++ RK_BT_STATE_TURNING_OFF ++++++++++\n");
break;
case RK_BT_STATE_OFF:
printf("++++++++++ RK_BT_STATE_OFF ++++++++++\n");
gonff = false;
break;
}
}
static void bt_test_bond_state_cb(const char *bd_addr, const char *name, RK_BT_BOND_STATE state)
{
switch(state) {
case RK_BT_BOND_STATE_NONE:
printf("++++++++++ BT BOND NONE: %s, %s ++++++++++\n", name, bd_addr);
break;
case RK_BT_BOND_STATE_BONDING:
printf("++++++++++ BT BOND BONDING: %s, %s ++++++++++\n", name, bd_addr);
break;
case RK_BT_BOND_STATE_BONDED:
printf("++++++++++ BT BONDED: %s, %s ++++++++++\n", name, bd_addr);
break;
}
}
static void bt_test_discovery_status_cb(RK_BT_DISCOVERY_STATE status)
{
switch(status) {
case RK_BT_DISC_STARTED:
printf("++++++++++ RK_BT_DISC_STARTED ++++++++++\n");
break;
case RK_BT_DISC_STOPPED_AUTO:
printf("++++++++++ RK_BT_DISC_STOPPED_AUTO ++++++++++\n");
break;
case RK_BT_DISC_START_FAILED:
printf("++++++++++ RK_BT_DISC_START_FAILED ++++++++++\n");
break;
case RK_BT_DISC_STOPPED_BY_USER:
printf("++++++++++ RK_BT_DISC_STOPPED_BY_USER ++++++++++\n");
break;
}
if(status != RK_BT_DISC_STARTED) {
printf("+++++++++ deregister scan callback +++++++++\n");
rk_bt_register_discovery_callback(NULL);
rk_bt_register_dev_found_callback(NULL);
}
}
static void bt_test_dev_found_cb(const char *address,const char *name, unsigned int bt_class, int rssi)
{
printf("++++++++++++ Device is found ++++++++++++\n");
printf(" address: %s\n", address);
printf(" name: %s\n", name);
printf(" class: 0x%x\n", bt_class);
printf(" rssi: %d\n", rssi);
printf("+++++++++++++++++++++++++++++++++++++++++\n");
}
static void bt_test_name_change_cb(const char *bd_addr, const char *name)
{
if(bd_addr)
printf("+++++ Device Name Change(%s, %s) +++++\n", bd_addr, name);
}
/*
* The Bluetooth basic service is turned on and the function
* must be called before using the Bluetooth function.
*/
#if 0
void *bt_test_bluetooth_init_thread(void *arg)
{
printf("%s: BT BLUETOOTH INIT\n", __func__);
memset(&bt_content, 0, sizeof(RkBtContent));
bt_content.bt_name = "ROCKCHIP_TEST";
//bt_content.bt_addr = "11:22:33:44:55:66";
bt_content.ble_content.ble_name = "ROCKCHIP_AUDIO BLE";
#if 0
//user-defined ble address test, if not set, the default random address
bt_content.ble_content.ble_addr[0] = 0x11;
bt_content.ble_content.ble_addr[1] = 0x22;
bt_content.ble_content.ble_addr[2] = 0x33;
bt_content.ble_content.ble_addr[3] = 0x44;
bt_content.ble_content.ble_addr[4] = 0x55;
bt_content.ble_content.ble_addr[5] = 0x66;
//Clear two most significant bits
bt_content.ble_content.ble_addr[5] &= 0x3f;
//Set second most significant bit, Private resolvable
bt_content.ble_content.ble_addr[5] |= 0x40;
printf("ble_addr: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
bt_content.ble_content.ble_addr[5], bt_content.ble_content.ble_addr[4],
bt_content.ble_content.ble_addr[3], bt_content.ble_content.ble_addr[2],
bt_content.ble_content.ble_addr[1], bt_content.ble_content.ble_addr[0]);
#endif
bt_content.ble_content.server_uuid.uuid = BLE_UUID_SERVICE;
bt_content.ble_content.server_uuid.len = UUID_128;
bt_content.ble_content.chr_uuid[0].uuid = BLE_UUID_WIFI_CHAR;
bt_content.ble_content.chr_uuid[0].len = UUID_128;
bt_content.ble_content.chr_uuid[1].uuid = BLE_UUID_SEND;
bt_content.ble_content.chr_uuid[1].len = UUID_128;
bt_content.ble_content.chr_uuid[2].uuid = BLE_UUID_RECV;
bt_content.ble_content.chr_uuid[2].len = UUID_128;
bt_content.ble_content.chr_cnt = 3;
bt_content.ble_content.advDataType = BLE_ADVDATA_TYPE_SYSTEM;
bt_content.ble_content.cb_ble_recv_fun = bt_test_ble_recv_data_callback;
bt_content.ble_content.cb_ble_request_data = bt_test_ble_request_data_callback;
rk_bt_register_state_callback(bt_test_state_cb);
rk_bt_register_bond_callback(bt_test_bond_state_cb);
rk_bt_register_name_change_callback(bt_test_name_change_cb);
rk_bt_init(&bt_content);
return NULL;
}
#else
//BLE_ADVDATA_TYPE_USER demo
void *bt_test_bluetooth_init_thread(void *arg)
{
printf("%s: BT BLUETOOTH INIT\n", __func__);
int len, ble_name_len, remain_len;
memset(&bt_content, 0, sizeof(RkBtContent));
bt_content.bt_name = "ROCKCHIP_AUDIO";
//bt_content.bt_addr = "11:22:33:44:55:66";
bt_content.ble_content.ble_name = "ROCKCHIP_AUDIO_BLE";
bt_content.ble_content.server_uuid.uuid = SERVICE_UUID;
bt_content.ble_content.server_uuid.len = UUID_128;
bt_content.ble_content.chr_uuid[0].uuid = BLE_UUID_SEND;
bt_content.ble_content.chr_uuid[0].len = UUID_128;
bt_content.ble_content.chr_uuid[1].uuid = BLE_UUID_RECV;
bt_content.ble_content.chr_uuid[1].len = UUID_128;
bt_content.ble_content.chr_cnt = 2;
bt_content.ble_content.advDataType = BLE_ADVDATA_TYPE_USER;
//标识设备 LE 物理连接的功能
bt_content.ble_content.advData[1] = 0x02;
bt_content.ble_content.advData[2] = 0x01;
bt_content.ble_content.advData[3] = 0x02;
//service uuid(SERVICE_UUID)
bt_content.ble_content.advData[4] = 0x03;
bt_content.ble_content.advData[5] = 0x03;
bt_content.ble_content.advData[6] = 0x10;
bt_content.ble_content.advData[7] = 0x19;
//ble name
printf("ble_name_len: %s(%d)\n", bt_content.ble_content.ble_name, strlen(bt_content.ble_content.ble_name));
ble_name_len = strlen(bt_content.ble_content.ble_name);
remain_len = 31 - (bt_content.ble_content.advData[1] + 1)
- (bt_content.ble_content.advData[4] + 1);
len = ble_name_len > remain_len ? remain_len : ble_name_len;
bt_content.ble_content.advData[8] = len + 1;
bt_content.ble_content.advData[9] = 0x09;
memcpy(&bt_content.ble_content.advData[10], bt_content.ble_content.ble_name, len);
bt_content.ble_content.advData[0] = bt_content.ble_content.advData[1] + 1
+ bt_content.ble_content.advData[4] + 1
+ bt_content.ble_content.advData[8] + 1;
bt_content.ble_content.advDataLen = bt_content.ble_content.advData[0] + 1;
//==========================rsp======================
bt_content.ble_content.respData[1] = 0x16; //长度
bt_content.ble_content.respData[2] = 0xFF; //字段类型
/*厂商编码*/
bt_content.ble_content.respData[3] = 0x46;
bt_content.ble_content.respData[4] = 0x00;
bt_content.ble_content.respData[5] = 0x02; //项目代号长度
/*项目代号*/
bt_content.ble_content.respData[6] = 0x1c;
bt_content.ble_content.respData[7] = 0x02;
bt_content.ble_content.respData[8] = 0x04; //版本号长度
bt_content.ble_content.respData[9] = 'T'; //版本号类型
/*版本号*/
bt_content.ble_content.respData[10] = 0x01;
bt_content.ble_content.respData[11] = 0x00;
bt_content.ble_content.respData[12] = 0x00;
bt_content.ble_content.respData[13] = 0x08; // SN长度
/*SN号*/
bt_content.ble_content.respData[14] = 0x54;
bt_content.ble_content.respData[15] = 0x00;
bt_content.ble_content.respData[16] = 0x00;
bt_content.ble_content.respData[17] = 0x00;
bt_content.ble_content.respData[18] = 0x00;
bt_content.ble_content.respData[19] = 0x00;
bt_content.ble_content.respData[20] = 0x00;
bt_content.ble_content.respData[21] = 0x36;
bt_content.ble_content.respData[22] = 0x01; //绑定信息长度
bt_content.ble_content.respData[23] = 0x00; //绑定信息
bt_content.ble_content.respData[0] = bt_content.ble_content.respData[1] + 1; //长度
bt_content.ble_content.respDataLen = bt_content.ble_content.respData[0] + 1;
bt_content.ble_content.cb_ble_recv_fun = bt_test_ble_recv_data_callback;
bt_content.ble_content.cb_ble_request_data = bt_test_ble_request_data_callback;
rk_bt_register_state_callback(bt_test_state_cb);
rk_bt_register_bond_callback(bt_test_bond_state_cb);
rk_bt_init(&bt_content);
return NULL;
}
#endif
static int bt_onff_cnt = 0;
void *bt_test_onff_thread(void *arg)
{
while (1) {
bt_test_bluetooth_init_thread(NULL);
bt_test_source_open(NULL);
while (gonff == false) {
sleep(1);
printf("%s: BT BLUETOOTH TURNING ON ...\n", __func__);
}
printf("%s: BT BLUETOOTH DEINIT\n", __func__);
bt_test_source_close(NULL);
rk_bt_deinit();
while (gonff == true) {
sleep(1);
printf("%s: BT BLUETOOTH TURNING OFF ...\n", __func__);
}
printf("%s: BT BLUETOOTH TURN ONOFF CNT: [%d] \n", __func__, bt_onff_cnt++);
}
}
static pthread_t bt_init_onoff_thread = 0;
void bt_test_bluetooth_onff_init(char *data)
{
printf("%s: ", __func__);
if (bt_init_onoff_thread) {
printf("bt init thread already exist\n");
return;
}
if (pthread_create(&bt_init_onoff_thread, NULL, bt_test_onff_thread, NULL)) {
printf("Create bt init pthread failed\n");
return;
}
}
static pthread_t bt_init_thread = 0;
void bt_test_bluetooth_init(char *data)
{
printf("%s: ", __func__);
bt_test_bluetooth_init_thread(NULL);
return;
if (bt_init_thread) {
printf("bt init thread already exist\n");
return;
}
if (pthread_create(&bt_init_thread, NULL, bt_test_bluetooth_init_thread, NULL)) {
printf("Create bt init pthread failed\n");
return;
}
}
void bt_test_bluetooth_deinit(char *data)
{
int ret;
printf("%s: BT BLUETOOTH DEINIT\n", __func__);
rk_bt_deinit();
if(bt_init_thread) {
ret = pthread_join(bt_init_thread, NULL);
if (ret) {
printf("%s: bt init thread exit failed!\n", __func__);
} else {
printf("%s: bt init thread exit ok\n", __func__);
}
bt_init_thread = 0;
}
}
void bt_test_set_class(char *data)
{
rk_bt_set_class(0x240404);
}
void bt_test_enable_reconnect(char *data)
{
rk_bt_enable_reconnect(1);
}
void bt_test_disable_reconnect(char *data)
{
rk_bt_enable_reconnect(0);
}
void bt_test_get_device_name(char *data)
{
char name[256];
memset(name, 0, 256);
rk_bt_get_device_name(name, 256);
printf("bt device name: %s\n", name);
}
void bt_test_get_device_addr(char *data)
{
char addr[18];
memset(addr, 0, 18);
rk_bt_get_device_addr(addr, 18);
printf("bt device addr: %s\n", addr);
}
void bt_test_set_device_name(char *data)
{
printf("%s: device name: %s\n", __func__, data);
rk_bt_set_device_name(data);
}
void bt_test_pair_by_addr(char *data)
{
rk_bt_pair_by_addr(data);
}
void bt_test_unpair_by_addr(char *data)
{
rk_bt_unpair_by_addr(data);
}
void bt_test_get_paired_devices(char *data)
{
int i, count;
RkBtScanedDevice *dev_tmp = NULL;
if(g_paired_dev_list)
bt_test_free_paired_devices(NULL);
rk_bt_get_paired_devices(&g_paired_dev_list, &count);
printf("%s: current paired devices count: %d\n", __func__, count);
dev_tmp = g_paired_dev_list;
for(i = 0; i < count; i++) {
printf("device %d\n", i);
printf(" remote_address: %s\n", dev_tmp->remote_address);
printf(" remote_name: %s\n", dev_tmp->remote_name);
printf(" is_connected: %d\n", dev_tmp->is_connected);
dev_tmp = dev_tmp->next;
}
}
void bt_test_free_paired_devices(char *data)
{
rk_bt_free_paired_devices(g_paired_dev_list);
g_paired_dev_list = NULL;
}
void bt_test_start_discovery(char *data)
{
int time;
if(data == NULL) {
printf("Please enter the scan time\n");
return;
}
time = atoi(data);
if(time < 10000) {
printf("Scan time is too short(%d), reset to 10000ms\n", time);
time = 10000;
}
rk_bt_register_discovery_callback(bt_test_discovery_status_cb);
rk_bt_register_dev_found_callback(bt_test_dev_found_cb);
rk_bt_start_discovery(time, SCAN_TYPE_AUTO);
}
void bt_test_start_discovery_bredr(char *data)
{
int time;
if(data == NULL) {
printf("Please enter the scan time\n");
return;
}
time = atoi(data);
if(time < 10000) {
printf("Scan time is too short(%d), reset to 10000ms\n", time);
time = 10000;
}
rk_bt_register_discovery_callback(bt_test_discovery_status_cb);
rk_bt_register_dev_found_callback(bt_test_dev_found_cb);
rk_bt_start_discovery(time, SCAN_TYPE_BREDR);
}
void bt_test_start_discovery_le(char *data)
{
int time;
if(data == NULL) {
printf("Please enter the scan time\n");
return;
}
time = atoi(data);
if(time < 10000) {
printf("Scan time is too short(%d), reset to 10000ms\n", time);
time = 10000;
}
rk_bt_register_discovery_callback(bt_test_discovery_status_cb);
rk_bt_register_dev_found_callback(bt_test_dev_found_cb);
rk_bt_start_discovery(time, SCAN_TYPE_LE);
}
void bt_test_start_discovery_pan(char *data)
{
int time;
if(data == NULL) {
printf("Please enter the scan time\n");
return;
}
time = atoi(data);
if(time < 10000) {
printf("Scan time is too short(%d), reset to 10000ms\n", time);
time = 10000;
}
rk_bt_register_discovery_callback(bt_test_discovery_status_cb);
rk_bt_register_dev_found_callback(bt_test_dev_found_cb);
rk_bt_start_discovery(time, SCAN_TYPE_PAN);
}
void bt_test_start_discovery_spp(char *data)
{
int time;
if(data == NULL) {
printf("Please enter the scan time\n");
return;
}
time = atoi(data);
if(time < 10000) {
printf("Scan time is too short(%d), reset to 10000ms\n", time);
time = 10000;
}
rk_bt_register_discovery_callback(bt_test_discovery_status_cb);
rk_bt_register_dev_found_callback(bt_test_dev_found_cb);
rk_bt_start_discovery(time, SCAN_TYPE_SPP);
}
void bt_test_cancel_discovery(char *data)
{
rk_bt_cancel_discovery();
}
void bt_test_is_discovering(char *data)
{
bool ret = rk_bt_is_discovering();
printf("the device discovery procedure is active? %s\n", (ret == true) ? "yes" : "no");
}
void bt_test_get_scaned_devices(char *data)
{
int i, count;
RkBtScanedDevice *dev_tmp = NULL;
RkBtScanedDevice *scaned_dev_list = NULL;
rk_bt_get_scaned_devices(&scaned_dev_list, &count);
printf("%s: current scaned devices count: %d\n", __func__, count);
dev_tmp = scaned_dev_list;
for(i = 0; i < count; i++) {
printf("device %d\n", i);
printf(" remote_address: %s\n", dev_tmp->remote_address);
printf(" remote_name: %s\n", dev_tmp->remote_name);
printf(" is_connected: %d\n", dev_tmp->is_connected);
printf(" class_of_device: 0x%x\n", dev_tmp->cod);
dev_tmp = dev_tmp->next;
}
rk_bt_free_scaned_devices(scaned_dev_list);
}
void bt_test_display_devices(char *data)
{
rk_bt_display_devices();
}
void bt_test_display_paired_devices(char *data)
{
rk_bt_display_paired_devices();
}
void bt_test_get_connected_properties(char *data)
{
bool is_connected = false;
is_connected = rk_bt_get_connected_properties(data);
printf("the device connected properties is %s\n", (is_connected == true) ? "yes" : "no");
}
void bt_test_read_remote_device_name(char *data)
{
rk_bt_read_remote_device_name(data, RK_BT_TRANSPORT_UNKNOWN);
}
/******************************************/
/* A2DP SINK */
/******************************************/
int bt_sink_callback(RK_BT_SINK_STATE state)
{
switch(state) {
case RK_BT_SINK_STATE_IDLE:
printf("++++++++++++ BT SINK EVENT: idle ++++++++++\n");
break;
case RK_BT_SINK_STATE_CONNECT:
printf("++++++++++++ BT SINK EVENT: connect sucess ++++++++++\n");
break;
case RK_BT_SINK_STATE_DISCONNECT:
printf("++++++++++++ BT SINK EVENT: disconnected ++++++++++\n");
//system("amixer set bt 255");
break;
//avrcp
case RK_BT_SINK_STATE_PLAY:
printf("++++++++++++ BT SINK EVENT: playing ++++++++++\n");
break;
case RK_BT_SINK_STATE_PAUSE:
printf("++++++++++++ BT SINK EVENT: paused ++++++++++\n");
break;
case RK_BT_SINK_STATE_STOP:
printf("++++++++++++ BT SINK EVENT: stoped ++++++++++\n");
break;
//avdtp(a2dp)
case RK_BT_A2DP_SINK_STARTED:
printf("++++++++++++ BT A2DP SINK STATE: started ++++++++++\n");
break;
case RK_BT_A2DP_SINK_SUSPENDED:
printf("++++++++++++ BT A2DP SINK STATE: suspended ++++++++++\n");
break;
case RK_BT_A2DP_SINK_STOPPED:
printf("++++++++++++ BT A2DP SINK STATE: stoped ++++++++++\n");
break;
}
return 0;
}
void bt_sink_volume_callback(int volume)
{
printf("++++++++ bt sink volume change, volume: %d ++++++++\n", volume);
/* Change the code below based on which interface audio is going out to. */
#if 0
char buffer[100];
sprintf(buffer, "amixer set bt %d", volume * 255 / 127);
if (-1 == system(buffer))
printf("set volume error: %d, volume: %d\n", errno, volume);
#endif
}
void bt_sink_track_change_callback(const char *bd_addr, BtTrackInfo track_info)
{
#if 0
printf("++++++++ bt sink track change ++++++++\n");
printf(" remote device address: %s\n", bd_addr);
printf(" title: %s\n", track_info.title);
printf(" artist: %s\n", track_info.artist);
printf(" album: %s\n", track_info.album);
printf(" genre: %s\n", track_info.genre);
printf(" num_tracks: %s\n", track_info.num_tracks);
printf(" track_num: %s\n", track_info.track_num);
printf(" playing_time: %s\n", track_info.playing_time);
#endif
}
void bt_sink_position_change_callback(const char *bd_addr, int song_len, int song_pos)
{
#if 0
printf("++++++++ bt sink position change ++++++++\n");
printf(" remote device address: %s\n", bd_addr);
printf(" song_len: %d, song_pos: %d\n", song_len, song_pos);
#endif
}
void bt_test_sink_open(char *data)
{
rk_bt_sink_register_volume_callback(bt_sink_volume_callback);
rk_bt_sink_register_track_callback(bt_sink_track_change_callback);
rk_bt_sink_register_position_callback(bt_sink_position_change_callback);
rk_bt_sink_register_callback(bt_sink_callback);
rk_bt_sink_open();
//rk_bt_sink_set_alsa_device("bt");
}
void bt_test_sink_visibility00(char *data)
{
rk_bt_set_visibility(0, 0);
}
void bt_test_sink_visibility01(char *data)
{
rk_bt_set_visibility(0, 1);
}
void bt_test_sink_visibility10(char *data)
{
rk_bt_set_visibility(1, 0);
}
void bt_test_sink_visibility11(char *data)
{
rk_bt_set_visibility(1, 1);
}
void bt_test_ble_visibility00(char *data)
{
rk_bt_set_visibility(0, 0);
}
void bt_test_ble_visibility11(char *data)
{
rk_bt_set_visibility(1, 1);
}
void bt_test_sink_status(char *data)
{
RK_BT_SINK_STATE pState;
rk_bt_sink_get_state(&pState);
switch(pState) {
case RK_BT_SINK_STATE_IDLE:
printf("++++++++++++ BT SINK STATUS: idle ++++++++++\n");
break;
case RK_BT_SINK_STATE_CONNECT:
printf("++++++++++++ BT SINK STATUS: connect sucess ++++++++++\n");
break;
case RK_BT_SINK_STATE_PLAY:
case RK_BT_A2DP_SINK_STARTED:
printf("++++++++++++ BT SINK STATUS: playing ++++++++++\n");
break;
case RK_BT_SINK_STATE_PAUSE:
case RK_BT_A2DP_SINK_SUSPENDED:
printf("++++++++++++ BT SINK STATUS: paused ++++++++++\n");
break;
case RK_BT_SINK_STATE_STOP:
case RK_BT_A2DP_SINK_STOPPED:
printf("++++++++++++ BT SINK STATUS: stoped ++++++++++\n");
break;
case RK_BT_SINK_STATE_DISCONNECT:
printf("++++++++++++ BT SINK STATUS: disconnected ++++++++++\n");
break;
}
}
void bt_test_sink_music_play(char *data)
{
rk_bt_sink_play();
}
void bt_test_sink_music_pause(char *data)
{
rk_bt_sink_pause();
}
void bt_test_sink_music_next(char *data)
{
rk_bt_sink_next();
}
void bt_test_sink_music_previous(char *data)
{
rk_bt_sink_prev();
}
void bt_test_sink_music_stop(char *data)
{
rk_bt_sink_stop();
}
void bt_test_sink_disconnect(char *data)
{
rk_bt_sink_disconnect();
}
void bt_test_sink_close(char *data)
{
rk_bt_sink_close();
}
void bt_test_sink_set_volume(char *data)
{
int i = 0;
printf("===== A2DP SINK Set Volume:100 =====\n");
rk_bt_sink_set_volume(127);
sleep(2);
printf("===== A2DP SINK Set Volume:64 =====\n");
rk_bt_sink_set_volume(64);
sleep(2);
printf("===== A2DP SINK Set Volume:0 =====\n");
rk_bt_sink_set_volume(0);
sleep(2);
for (; i < 17; i++) {
printf("===== A2DP SINK Set Volume UP =====\n");
rk_bt_sink_volume_up();
sleep(2);
}
for (i = 0; i < 17; i++) {
printf("===== A2DP SINK Set Volume DOWN =====\n");
rk_bt_sink_volume_down();
sleep(2);
}
}
void bt_test_sink_connect_by_addr(char *data)
{
rk_bt_sink_connect_by_addr(data);
}
void bt_test_sink_disconnect_by_addr(char *data)
{
rk_bt_sink_disconnect_by_addr(data);
}
void bt_test_sink_get_play_status(char *data)
{
rk_bt_sink_get_play_status();
}
void bt_test_sink_get_poschange(char *data)
{
bool pos_change = rk_bt_sink_get_poschange();
printf("support position change: %s\n", pos_change ? "yes" : "no");
}
/******************************************/
/* A2DP SOURCE */
/******************************************/
void bt_test_source_status_callback(void *userdata, const char *bd_addr,
const char *name, const RK_BT_SOURCE_EVENT enEvent)
{
switch(enEvent)
{
case BT_SOURCE_EVENT_CONNECT_FAILED:
printf("+++++ BT_SOURCE_EVENT_CONNECT_FAILED: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_CONNECTED:
printf("+++++ BT_SOURCE_EVENT_CONNECTED: %s, %s +++++\n", name, bd_addr);
printf("+++++ device playrole: %d\n", rk_bt_get_playrole_by_addr(bd_addr));
break;
case BT_SOURCE_EVENT_AUTO_RECONNECTING:
printf("+++++ BT_SOURCE_EVENT_AUTO_RECONNECTING: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_DISCONNECT_FAILED:
printf("+++++ BT_SOURCE_EVENT_DISCONNECT_FAILED: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_DISCONNECTED:
printf("+++++ BT_SOURCE_EVENT_DISCONNECTED: %s, %s +++++\n", name, bd_addr);
break;
#if 0
case BT_SOURCE_EVENT_REMOVE_FAILED:
printf("+++++ BT_SOURCE_EVENT_REMOVE_FAILED +++++\n");
break;
case BT_SOURCE_EVENT_REMOVED:
printf("+++++ BT_SOURCE_EVENT_REMOVED +++++\n");
break;
#endif
case BT_SOURCE_EVENT_RC_PLAY:
printf("+++++ BT_SOURCE_EVENT_RC_PLAY: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_RC_STOP:
printf("+++++ BT_SOURCE_EVENT_RC_STOP: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_RC_PAUSE:
printf("+++++ BT_SOURCE_EVENT_RC_PAUSE: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_RC_FORWARD:
printf("+++++ BT_SOURCE_EVENT_RC_FORWARD: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_RC_BACKWARD:
printf("+++++ BT_SOURCE_EVENT_RC_BACKWARD: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_RC_VOL_UP:
printf("+++++ BT_SOURCE_EVENT_RC_VOL_UP: %s, %s +++++\n", name, bd_addr);
break;
case BT_SOURCE_EVENT_RC_VOL_DOWN:
printf("+++++ BT_SOURCE_EVENT_RC_VOL_DOWN: %s, %s +++++\n", name, bd_addr);
break;
}
}
void bt_test_source_auto_start(char *data)
{
rk_bt_source_auto_connect_start(NULL, bt_test_source_status_callback);
}
void bt_test_source_auto_stop(char *data)
{
rk_bt_source_auto_connect_stop();
}
void bt_test_source_connect_status(char *data)
{
RK_BT_SOURCE_STATUS status;
char name[256], address[256];
rk_bt_source_get_status(&status, name, 256, address, 256);
if (status == BT_SOURCE_STATUS_CONNECTED) {
printf("++++++++++++ BT SOURCE STATUS: connected ++++++++++++\n");
printf("\t name:%s, address:%s\n", name, address);
} else
printf("++++++++++++ BT SOURCE STATUS: disconnected ++++++++++++\n");
}
void bt_test_source_open(char *data)
{
rk_bt_source_register_status_cb(NULL, bt_test_source_status_callback);
rk_bt_source_open();
}
void bt_test_source_close(char *data)
{
rk_bt_source_close();
}
void bt_test_source_connect_by_addr(char *data)
{
rk_bt_source_connect_by_addr(data);
}
void bt_test_source_disconnect_by_addr(char *data)
{
rk_bt_source_disconnect_by_addr(data);
}
void bt_test_source_remove_by_addr(char *data)
{
rk_bt_source_remove(data);
}
void bt_test_source_disconnect(char *data)
{
rk_bt_source_disconnect();
}
void bt_test_source_set_vol(char *data)
{
int vol;
vol = atoi(data);
printf("+++++ bt_test_source_set_vol: %s, %d +++++\n", data, vol);
rk_bt_source_set_vol(vol);
}
/******************************************/
/* BLE */
/******************************************/
static void ble_status_callback_test(const char *bd_addr, const char *name, RK_BLE_STATE state)
{
printf("%s: status: %d.\n", __func__, state);
switch (state) {
case RK_BLE_STATE_IDLE:
printf("+++++ RK_BLE_STATE_IDLE +++++\n");
break;
case RK_BLE_STATE_CONNECT:
printf("+++++ RK_BLE_STATE_CONNECT: %s, %s +++++\n", name, bd_addr);
break;
case RK_BLE_STATE_DISCONNECT:
printf("+++++ RK_BLE_STATE_DISCONNECT: %s, %s +++++\n", name, bd_addr);
g_mtu = 0;
break;
}
}
static void bt_test_ble_recv_data_callback(const char *uuid, char *data, int len)
{
char data_t[512];
char reply_buf[512] = {"My name is rockchip"};
printf("=== %s uuid: %s===\n", __func__, uuid);
memcpy(data_t, data, len);
for (int i = 0 ; i < len; i++) {
printf("%02x ", data_t[i]);
}
printf("\n");
if (strstr(data_t, "Hello RockChip") || strstr(data_t, "HelloRockChip") ||
strstr(data_t, "HELLO ROCKCHIP") || strstr(data_t, "HELLOROCKCHIP") ||
strstr(data_t, "hello rockchip") || strstr(data_t, "hellorockchip")) {
printf("=== %s Reply:%s ===\n", __func__, reply_buf);
rk_ble_write(uuid, reply_buf, 17);
}
}
void *_send_data(void *data)
{
char *uuid = (char *)data;
rk_ble_write(uuid, "abcd", 4);
usleep(100000);
rk_ble_write(uuid, "wwww", 4);
usleep(100000);
rk_ble_write(uuid, "zzzz", 4);
return ((void *)0);
}
void send_data(char *uuid)
{
pthread_t tid = 0;
if (pthread_create(&tid, NULL, _send_data, (void *)uuid)) {
printf("Create _send_data pthread failed\n");
return;
}
}
static void bt_test_ble_request_data_callback(const char *uuid, char *data, int *len)
{
printf("=== %s uuid: %s===\n", __func__, uuid);
//len <= mtu(g_mtu)
*len = strlen("hello rockchip");
memcpy(data, "hello rockchip", strlen("hello rockchip"));
printf("=== %s uuid: %s data: %s[%d]===\n", __func__, uuid, data, *len);
return;
}
static void bt_test_mtu_callback(const char *bd_addr, unsigned int mtu)
{
printf("=== %s: bd_addr: %s, mtu: %d ===\n", __func__, bd_addr, mtu);
g_mtu = mtu;
}
void bt_test_ble_start(char *data)
{
rk_ble_register_status_callback(ble_status_callback_test);
rk_ble_register_mtu_callback(bt_test_mtu_callback);
rk_ble_start(&bt_content.ble_content);
}
void bt_test_ble_set_address(char *data)
{
//user-defined ble address test, if not set, the default random address
char ble_addr[DEVICE_ADDR_LEN];
if(!data || strlen(data) < 17)
return;
printf("ble address: %s\n", data);
if (sscanf(data, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&ble_addr[5], &ble_addr[4], &ble_addr[3],
&ble_addr[2], &ble_addr[1], &ble_addr[0]) != 6) {
return;
}
//Clear two most significant bits
ble_addr[5] &= 0x3f;
//Set second most significant bit, Private resolvable
ble_addr[5] |= 0x40;
printf("ble_addr: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
ble_addr[5], ble_addr[4], ble_addr[3],
ble_addr[2], ble_addr[1], ble_addr[0]);
rk_ble_set_address(ble_addr);
}
void bt_test_ble_set_adv_interval(char *data)
{
//default 100ms, test: 20ms(32 * 0.625) ~ 100ms(160 * 0.625)
rk_ble_set_adv_interval(32, 160);
}
void bt_test_ble_write(char *data)
{
int i = 0, write_len = BT_ATT_DEFAULT_LE_MTU;
char *write_buf;
if(g_mtu > BT_ATT_HEADER_LEN)
write_len = g_mtu;
write_len -= BT_ATT_HEADER_LEN;
if(write_len > BT_ATT_MAX_VALUE_LEN)
write_len = BT_ATT_MAX_VALUE_LEN;
write_buf = (char *)malloc(write_len);
for (i = 0; i < (write_len - 1); i++)
write_buf[i] = '0' + i % 10;
write_buf[write_len - 1] = '\0';
rk_ble_write(BLE_UUID_SEND, data, strlen(data));
//rk_ble_write(BLE_UUID_WIFI_CHAR, write_buf, write_len);
free(write_buf);
}
void bt_test_ble_get_status(char *data)
{
RK_BLE_STATE state;
printf("RK_ble_status_test: ");
rk_ble_get_state(&state);
switch (state) {
case RK_BLE_STATE_IDLE:
printf("RK_BLE_STATE_IDLE.\n");
break;
case RK_BLE_STATE_CONNECT:
printf("RK_BLE_STATE_CONNECT.\n");
break;
case RK_BLE_STATE_DISCONNECT:
printf("RK_BLE_STATE_DISCONNECT.\n");
break;
}
}
void bt_test_ble_stop(char *data) {
g_mtu = 0;
rk_ble_stop();
}
void bt_test_ble_disconnect(char *data) {
rk_ble_disconnect();
}
/******************************************/
/* BLE CLIENT */
/******************************************/
void ble_client_test_state_callback(const char *bd_addr, const char *name, RK_BLE_CLIENT_STATE state)
{
switch(state)
{
case RK_BLE_CLIENT_STATE_IDLE:
printf("+++++ RK_BLE_CLIENT_STATE_IDLE +++++\n");
break;
case RK_BLE_CLIENT_STATE_CONNECT:
printf("+++++ RK_BLE_CLIENT_STATE_CONNECT(%s, %s) +++++\n", bd_addr, name);
break;
case RK_BLE_CLIENT_STATE_DISCONNECT:
printf("+++++ RK_BLE_CLIENT_STATE_DISCONNECT(%s, %s) +++++\n", bd_addr, name);
g_mtu = 0;
break;
case RK_BLE_CLIENT_WRITE_SUCCESS:
printf("+++++ RK_BLE_CLIENT_WRITE_SUCCESS(%s, %s) +++++\n", bd_addr, name);
break;
case RK_BLE_CLIENT_WRITE_ERROR:
printf("+++++ RK_BLE_CLIENT_WRITE_ERROR(%s, %s) +++++\n", bd_addr, name);
break;
}
}
static void bt_test_ble_client_recv_data_callback(const char *uuid, char *data, int len)
{
printf("+++++ recv data +++++\n");
printf(" uuid: %s\n", uuid);
printf(" data len: %d\n ", len);
for (int i = 0 ; i < len; i++) {
printf("%02x ", data[i]);
}
printf("\n");
}
void bt_test_ble_client_open(char *data)
{
rk_ble_client_register_state_callback(ble_client_test_state_callback);
rk_ble_client_register_recv_callback(bt_test_ble_client_recv_data_callback);
rk_ble_client_register_mtu_callback(bt_test_mtu_callback);
rk_ble_client_open(true);
}
void bt_test_ble_client_close(char *data)
{
g_mtu = 0;
rk_ble_client_close();
}
void bt_test_ble_client_get_status(char *data)
{
RK_BLE_CLIENT_STATE state;
state = rk_ble_client_get_state();
switch (state) {
case RK_BLE_CLIENT_STATE_IDLE:
printf("RK_BLE_CLIENT_STATE_IDLE\n");
break;
case RK_BLE_CLIENT_STATE_CONNECT:
printf("RK_BLE_CLIENT_STATE_CONNECT\n");
break;
case RK_BLE_CLIENT_STATE_DISCONNECT:
printf("RK_BLE_CLIENT_STATE_DISCONNECT\n");
break;
}
}
void bt_test_ble_client_connect(char *data)
{
rk_ble_client_connect(data);
}
void bt_test_ble_client_disconnect(char *data)
{
rk_ble_client_disconnect(data);
}
void bt_test_ble_client_get_service_info(char *data)
{
int i, j, k;
RK_BLE_CLIENT_SERVICE_INFO info;
if(!rk_ble_client_get_service_info(data, &info)) {
printf("+++++ get device(%s) service info +++++\n", data);
for(i = 0; i < info.service_cnt; i++) {
printf("service[%d]:\n", i);
printf(" describe: %s\n", info.service[i].describe);
printf(" path: %s\n", info.service[i].path);
printf(" uuid: %s\n", info.service[i].uuid);
for(j = 0; j < info.service[i].chrc_cnt; j++) {
printf(" characteristic[%d]:\n", j);
printf(" describe: %s\n", info.service[i].chrc[j].describe);
printf(" path: %s\n", info.service[i].chrc[j].path);
printf(" uuid: %s\n", info.service[i].chrc[j].uuid);
printf(" props: 0x%x\n", info.service[i].chrc[j].props);
printf(" ext_props: 0x%x\n", info.service[i].chrc[j].ext_props);
printf(" perm: 0x%x\n", info.service[i].chrc[j].perm);
printf(" notifying: %d\n", info.service[i].chrc[j].notifying);
for(k = 0; k < info.service[i].chrc[j].desc_cnt; k++) {
printf(" descriptor[%d]:\n", k);
printf(" describe: %s\n", info.service[i].chrc[j].desc[k].describe);
printf(" path: %s\n", info.service[i].chrc[j].desc[k].path);
printf(" uuid: %s\n", info.service[i].chrc[j].desc[k].uuid);
}
}
}
}
}
void bt_test_ble_client_read(char *data)
{
rk_ble_client_read(data);
}
void bt_test_ble_client_write(char *data)
{
#if 0
//write data len no more than (g_mtu - BT_ATT_HEADER_LEN)
rk_ble_client_write(data, "rockchip ble client write test", strlen("rockchip ble client write test"));
#else
int i = 0, write_len = BT_ATT_DEFAULT_LE_MTU;
char *write_buf;
if(g_mtu > BT_ATT_HEADER_LEN)
write_len = g_mtu;
write_len -= BT_ATT_HEADER_LEN;
if(write_len > BT_ATT_MAX_VALUE_LEN)
write_len = BT_ATT_MAX_VALUE_LEN;
write_buf = (char *)malloc(write_len);
for (i = 0; i < (write_len - 1); i++)
write_buf[i] = '0' + i % 10;
write_buf[write_len - 1] = '\0';
rk_ble_client_write(data, write_buf, strlen(write_buf));
free(write_buf);
#endif
}
void bt_test_ble_client_is_notify(char *data)
{
bool notifying;
notifying = rk_ble_client_is_notifying(data);
printf("%s notifying %s\n", data, notifying ? "yes" : "no");
}
void bt_test_ble_client_notify_on(char *data)
{
rk_ble_client_notify(data, false, true);
}
void bt_test_ble_client_notify_off(char *data)
{
rk_ble_client_notify(data, false, false);
}
void bt_test_ble_client_indicate_on(char *data)
{
rk_ble_client_notify(data, true, true);
}
void bt_test_ble_client_indicate_off(char *data)
{
rk_ble_client_notify(data, true, false);
}
void bt_test_ble_client_get_eir_data(char *data)
{
char eir_data[300];
rk_ble_client_get_eir_data(data, eir_data, 300);
#if 1
int i;
for(i = 0; i < 300; i++) {
printf("%02x ", eir_data[i]);
if((i != 0) && (i % 20 == 0))
printf("\n");
}
printf("\n");
#endif
}
void bt_test_get_eir_data(char *data)
{
char eir_data[300];
int len;
len = rk_bt_get_eir_data(data, eir_data, 300);
#if 1
int i;
printf("\n");
for (i = 0; i < len; i++) {
if((i != 0) && (i % 16 == 0))
printf("\n");
printf("%02x ", eir_data[i]);
}
printf("\n");
#endif
}
/******************************************/
/* SPP */
/******************************************/
void _btspp_status_callback(RK_BT_SPP_STATE type)
{
switch(type) {
case RK_BT_SPP_STATE_IDLE:
printf("+++++++ RK_BT_SPP_STATE_IDLE +++++\n");
break;
case RK_BT_SPP_STATE_CONNECT:
printf("+++++++ RK_BT_SPP_EVENT_CONNECT +++++\n");
break;
case RK_BT_SPP_STATE_DISCONNECT:
printf("+++++++ RK_BT_SPP_EVENT_DISCONNECT +++++\n");
break;
default:
printf("+++++++ BT SPP NOT SUPPORT TYPE! +++++\n");
break;
}
}
void _btspp_recv_callback(char *data, int len)
{
if (len) {
printf("+++++++ RK BT SPP RECV DATA: +++++\n");
printf("\tRECVED(%d):%s\n", len, data);
}
}
void bt_test_spp_open(char *data)
{
rk_bt_spp_open(data);
rk_bt_spp_register_status_cb(_btspp_status_callback);
rk_bt_spp_register_recv_cb(_btspp_recv_callback);
}
void bt_test_spp_write(char *data)
{
unsigned int ret = 0;
char buff[100] = {"This is a message from rockchip board!"};
ret = rk_bt_spp_write(data, strlen(data));
if (ret < 0) {
printf("%s failed\n", __func__);
}
}
void bt_test_spp_connect(char *data)
{
rk_bt_spp_connect(data);
}
void bt_test_spp_disconnect(char *data)
{
rk_bt_spp_disconnect(data);
}
void bt_test_spp_listen(char *data)
{
rk_bt_spp_listen();
}
void bt_test_spp_close(char *data)
{
rk_bt_spp_close();
}
void bt_test_spp_status(char *data)
{
RK_BT_SPP_STATE status;
rk_bt_spp_get_state(&status);
switch(status) {
case RK_BT_SPP_STATE_IDLE:
printf("+++++++ RK_BT_SPP_STATE_IDLE +++++\n");
break;
case RK_BT_SPP_STATE_CONNECT:
printf("+++++++ RK_BT_SPP_STATE_CONNECT +++++\n");
break;
case RK_BT_SPP_STATE_DISCONNECT:
printf("+++++++ RK_BT_SPP_STATE_DISCONNECT +++++\n");
break;
default:
printf("+++++++ BTSPP NO STATUS SUPPORT! +++++\n");
break;
}
}
/******************************************/
/* HFP */
/******************************************/
static int hfp_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t buffer_size,
snd_pcm_uframes_t period_size, char **msg)
{
int err;
snd_pcm_sw_params_t *params;
snd_pcm_sw_params_malloc(&params);
if ((err = snd_pcm_sw_params_current(pcm, params)) != 0) {
printf("Get current params: %s\n", snd_strerror(err));
return -1;
}
/* start the transfer when the buffer is full (or almost full) */
snd_pcm_uframes_t threshold = (buffer_size / period_size) * period_size;
if ((err = snd_pcm_sw_params_set_start_threshold(pcm, params, threshold)) != 0) {
printf("Set start threshold: %s: %lu\n", snd_strerror(err), threshold);
return -1;
}
/* allow the transfer when at least period_size samples can be processed */
if ((err = snd_pcm_sw_params_set_avail_min(pcm, params, period_size)) != 0) {
printf("Set avail min: %s: %lu\n", snd_strerror(err), period_size);
return -1;
}
if ((err = snd_pcm_sw_params(pcm, params)) != 0) {
printf("snd_pcm_sw_params: %s\n", snd_strerror(err));
return -1;
}
if(params)
snd_pcm_sw_params_free(params);
return 0;
}
static int hfp_playback_device_open(snd_pcm_t** playback_handle,
const char* device_name, alsa_config_t alsa_config)
{
int err;
snd_pcm_hw_params_t *hw_params;
unsigned int rate = alsa_config.sample_rate;
snd_pcm_uframes_t period_size = alsa_config.period_size;
snd_pcm_uframes_t buffer_size = alsa_config.buffer_size;
err = snd_pcm_open(playback_handle, device_name, SND_PCM_STREAM_PLAYBACK, 0);
if (err) {
printf( "Unable to open playback PCM device: %s\n", device_name);
return -1;
}
printf("Open playback PCM device: %s\n", device_name);
err = snd_pcm_hw_params_malloc(&hw_params);
if (err) {
printf("cannot malloc hardware parameter structure (%s)\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_any(*playback_handle, hw_params);
if (err) {
printf("cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_access(*playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err) {
printf("Error setting interleaved mode: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_format(*playback_handle, hw_params, SND_PCM_FORMAT_S16_LE);
if (err) {
printf("Error setting format: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_channels(*playback_handle, hw_params, alsa_config.channels);
if (err) {
printf( "Error setting channels: %s\n", snd_strerror(err));
return -1;
}
printf("setting channels (%d)\n", alsa_config.channels);
printf("WANT-RATE = %d\n", rate);
err = snd_pcm_hw_params_set_rate_near(*playback_handle, hw_params, &rate, 0);
if (err) {
printf("Error setting sampling rate (%d): %s\n", rate, snd_strerror(err));
return -1;
}
printf("set sampling rate (%d)\n", rate);
err = snd_pcm_hw_params_set_period_size_near(*playback_handle, hw_params, &period_size, 0);
if (err) {
printf("Error setting period size (%ld): %s\n", period_size, snd_strerror(err));
return -1;
}
printf("period_size = %d\n", (int)period_size);
err = snd_pcm_hw_params_set_buffer_size_near(*playback_handle, hw_params, &buffer_size);
if (err) {
printf("Error setting buffer size (%ld): %s\n", buffer_size, snd_strerror(err));
return -1;
}
printf("buffer_size = %d\n", (int)buffer_size);
/* Write the parameters to the driver */
err = snd_pcm_hw_params(*playback_handle, hw_params);
if (err < 0) {
printf( "Unable to set HW parameters: %s\n", snd_strerror(err));
return -1;
}
printf("Open playback device is successful: %s\n", device_name);
hfp_set_sw_params(*playback_handle, buffer_size, period_size, NULL);
if (hw_params)
snd_pcm_hw_params_free(hw_params);
return 0;
}
static int hfp_capture_device_open(snd_pcm_t** capture_handle,
const char* device_name, alsa_config_t alsa_config)
{
int err;
snd_pcm_hw_params_t *hw_params;
unsigned int rate = alsa_config.sample_rate;
snd_pcm_uframes_t period_size = alsa_config.period_size;
snd_pcm_uframes_t buffer_size = alsa_config.buffer_size;
err = snd_pcm_open(capture_handle, device_name, SND_PCM_STREAM_CAPTURE, 0);
if (err) {
printf( "Unable to open capture PCM device: %s\n", device_name);
return -1;
}
printf("Open capture PCM device: %s\n", device_name);
err = snd_pcm_hw_params_malloc(&hw_params);
if (err) {
printf("cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_any(*capture_handle, hw_params);
if (err) {
printf("cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_access(*capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err) {
printf("Error setting interleaved mode: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_format(*capture_handle, hw_params, SND_PCM_FORMAT_S16_LE);
if (err) {
printf("Error setting format: %s\n", snd_strerror(err));
return -1;
}
err = snd_pcm_hw_params_set_channels(*capture_handle, hw_params, alsa_config.channels);
if (err) {
printf( "Error setting channels: %s, channels = %d\n", snd_strerror(err), alsa_config.channels);
return -1;
}
printf("setting channels (%d)\n", alsa_config.channels);
printf("WANT-RATE = %d\n", rate);
err = snd_pcm_hw_params_set_rate_near(*capture_handle, hw_params, &rate, 0);
if (err) {
printf("Error setting sampling rate (%d): %s\n", rate, snd_strerror(err));
return -1;
}
printf("set sampling rate (%d)\n", rate);
err = snd_pcm_hw_params_set_period_size_near(*capture_handle, hw_params, &period_size, 0);
if (err) {
printf("Error setting period size (%d): %s\n", (int)period_size, snd_strerror(err));
return -1;
}
printf("period_size = %d\n", (int)period_size);
err = snd_pcm_hw_params_set_buffer_size_near(*capture_handle, hw_params, &buffer_size);
if (err) {
printf("Error setting buffer size (%d): %s\n", (int)buffer_size, snd_strerror(err));
return -1;
}
printf("buffer_size = %d\n", (int)buffer_size);
/* Write the parameters to the driver */
err = snd_pcm_hw_params(*capture_handle, hw_params);
if (err < 0) {
printf( "Unable to set HW parameters: %s\n", snd_strerror(err));
return -1;
}
printf("Open capture device is successful: %s\n", device_name);
if (hw_params)
snd_pcm_hw_params_free(hw_params);
return 0;
}
static void hfp_pcm_close(snd_pcm_t *handle)
{
if(handle)
snd_pcm_close(handle);
}
static void hfp_tinymix_set(int group, int volume)
{
char cmd[50] = {0};
sprintf(cmd, "tinymix set 'ADC MIC Group %d Left Volume' %d", group, volume);
if (-1 == system(cmd))
printf("tinymix set ADC MIC Group %d Left Volume failed\n", group);
memset(cmd, 0, 50);
sprintf(cmd, "tinymix set 'ADC MIC Group %d Right Volume' %d", group, volume);
if (-1 == system(cmd))
printf("tinymix set ADC MIC Group %d Right Volume failed\n", group);
}
static void *hfp_alsa_playback(void *arg)
{
int err, ret = -1;
snd_pcm_t *capture_handle = NULL;
snd_pcm_t *playbcak_handle = NULL;
short *buffer;
int read_frame, buffer_size;
alsa_config_t alsa_config;
switch(sco_codec) {
case BT_SCO_CODEC_CVSD:
read_frame = READ_FRAME_512;
alsa_config.sample_rate = CVSD_SAMPLE_RATE;
alsa_config.period_size = PERIOD_SIZE_512;
alsa_config.buffer_size = BUFFER_SIZE_2048;
break;
case BT_SCO_CODEC_MSBC:
read_frame = READ_FRAME_1024;
alsa_config.sample_rate = MSBC_SAMPLE_RATE;
alsa_config.period_size = PERIOD_SIZE_1024;
alsa_config.buffer_size = BUFFER_SIZE_4096;
break;
default:
printf("%s: invalid sco codec type: %d\n", __func__, sco_codec);
return NULL;
}
alsa_config.channels = HFP_PCM_CHANNEL_NB;
buffer_size = read_frame * HFP_PCM_CHANNEL_NB * sizeof(short);
buffer = (short *)malloc(buffer_size);
memset((char *)buffer, 0, buffer_size);
device_open:
printf("==========bt capture, alsa playback============\n");
ret = hfp_capture_device_open(&capture_handle, bt_capture_device, alsa_config);
if (ret == -1) {
printf("capture device open failed: %s\n", bt_capture_device);
goto exit;
}
ret = hfp_playback_device_open(&playbcak_handle, alsa_playback_device, alsa_config);
if (ret == -1) {
printf("playback device open failed: %s\n", alsa_playback_device);
goto exit;
}
g_duplex_control.alsa_duplex_opened = true;
while (g_duplex_control.alsa_duplex_opened) {
err = snd_pcm_readi(capture_handle, buffer , read_frame);
if (!g_duplex_control.alsa_duplex_opened)
goto exit;
if (err != read_frame)
printf("=====read frame error = %d=====\n", err);
if (err == -EPIPE)
printf("Overrun occurred: %d\n", err);
if (err < 0) {
err = snd_pcm_recover(capture_handle, err, 0);
// Still an error, need to exit.
if (err < 0) {
printf( "Error occured while recording: %s\n", snd_strerror(err));
usleep(100 * 1000);
hfp_pcm_close(capture_handle);
hfp_pcm_close(playbcak_handle);
goto device_open;
}
}
err = snd_pcm_writei(playbcak_handle, buffer, read_frame);
if (!g_duplex_control.alsa_duplex_opened)
goto exit;
if (err != read_frame)
printf("=====write frame error = %d=====\n", err);
if (err == -EPIPE)
printf("Underrun occurred from write: %d\n", err);
if (err < 0) {
err = snd_pcm_recover(playbcak_handle, err, 0);
// Still an error, need to exit.
if (err < 0) {
printf( "Error occured while writing: %s\n", snd_strerror(err));
usleep(100 * 1000);
hfp_pcm_close(capture_handle);
hfp_pcm_close(playbcak_handle);
goto device_open;
}
}
}
exit:
hfp_pcm_close(capture_handle);
hfp_pcm_close(playbcak_handle);
free(buffer);
printf("Exit app hs alsa playback thread\n");
pthread_exit(0);
}
static void *hfp_bt_playback(void *arg)
{
int err, ret = -1;
snd_pcm_t *capture_handle = NULL;
snd_pcm_t *playbcak_handle = NULL;
short buffer[READ_FRAME_256 * HFP_PCM_CHANNEL_NB] = {0};
alsa_config_t alsa_config;
alsa_config.channels = HFP_PCM_CHANNEL_NB;
alsa_config.period_size = PERIOD_SIZE_256;
alsa_config.buffer_size = BUFFER_SIZE_1024;
switch(sco_codec) {
case BT_SCO_CODEC_CVSD:
alsa_config.sample_rate = CVSD_SAMPLE_RATE;
break;
case BT_SCO_CODEC_MSBC:
alsa_config.sample_rate = MSBC_SAMPLE_RATE;
break;
default:
printf("%s: invalid sco codec type: %d\n", __func__, sco_codec);
return NULL;
}
device_open:
printf("==========mic capture, bt playback============\n");
ret = hfp_capture_device_open(&capture_handle, alsa_capture_device, alsa_config);
if (ret == -1) {
printf("capture device open failed: %s\n", alsa_capture_device);
goto exit;
}
hfp_tinymix_set(1, 3);
ret = hfp_playback_device_open(&playbcak_handle, bt_playback_device, alsa_config);
if (ret == -1) {
printf("playback device open failed: %s\n", bt_playback_device);
goto exit;
}
g_duplex_control.bt_duplex_opened = true;
while (g_duplex_control.bt_duplex_opened) {
err = snd_pcm_readi(capture_handle, buffer , READ_FRAME_256);
if (!g_duplex_control.bt_duplex_opened)
goto exit;
if (err != READ_FRAME_256)
printf("=====read frame error = %d=====\n", err);
if (err == -EPIPE)
printf("Overrun occurred: %d\n", err);
if (err < 0) {
err = snd_pcm_recover(capture_handle, err, 0);
// Still an error, need to exit.
if (err < 0) {
printf( "Error occured while recording: %s\n", snd_strerror(err));
usleep(100 * 1000);
hfp_pcm_close(capture_handle);
hfp_pcm_close(playbcak_handle);
goto device_open;
}
}
err = snd_pcm_writei(playbcak_handle, buffer, READ_FRAME_256);
if (!g_duplex_control.bt_duplex_opened)
goto exit;
if (err != READ_FRAME_256)
printf("====write frame error = %d===\n",err);
if (err == -EPIPE)
printf("Underrun occurred from write: %d\n", err);
if (err < 0) {
err = snd_pcm_recover(playbcak_handle, err, 0);
// Still an error, need to exit.
if (err < 0) {
printf( "Error occured while writing: %s\n", snd_strerror(err));
usleep(100 * 1000);
hfp_pcm_close(capture_handle);
hfp_pcm_close(playbcak_handle);
goto device_open;
}
}
}
exit:
hfp_pcm_close(capture_handle);
hfp_pcm_close(playbcak_handle);
printf("Exit app hs bt pcm playback thread\n");
pthread_exit(0);
}
static int hfp_open_alsa_duplex()
{
if (!g_duplex_control.alsa_duplex_opened) {
if (pthread_create(&g_duplex_control.alsa_tid, NULL, hfp_alsa_playback, NULL)) {
printf("Create alsa duplex thread failed\n");
return -1;
}
} else {
printf("hfp_open_alsa_duplex: alsa duplex already open\n");
}
return 0;
}
static void hfp_close_alsa_duplex(void)
{
printf("app_hs_close_alsa_duplex start\n");
g_duplex_control.alsa_duplex_opened = false;
if (g_duplex_control.alsa_tid) {
pthread_join(g_duplex_control.alsa_tid, NULL);
g_duplex_control.alsa_tid = 0;
}
printf("app_hs_close_alsa_duplex end\n");
}
static int hfp_open_bt_duplex()
{
if (!g_duplex_control.bt_duplex_opened) {
if (pthread_create(&g_duplex_control.bt_tid, NULL, hfp_bt_playback, NULL)) {
printf("Create bt pcm duplex thread failed\n");
return -1;
}
} else {
printf("hfp_open_bt_duplex: bt duplex already open\n");
}
return 0;
}
static void hfp_close_bt_duplex(void)
{
printf("app_hs_close_bt_duplex start\n");
g_duplex_control.bt_duplex_opened = false;
if (g_duplex_control.bt_tid) {
pthread_join(g_duplex_control.bt_tid, NULL);
g_duplex_control.bt_tid = 0;
}
printf("app_hs_close_bt_duplex end\n");
}
static int hfp_open_audio_duplex()
{
if(sco_codec != BT_SCO_CODEC_CVSD && sco_codec != BT_SCO_CODEC_MSBC) {
printf("%s: invalid sco codec type: %d\n", __func__, sco_codec);
return -1;
}
if(hfp_open_alsa_duplex() < 0)
return -1;
if(hfp_open_bt_duplex() < 0)
return -1;
return 0;
}
static void hfp_close_audio_duplex()
{
hfp_close_alsa_duplex();
hfp_close_bt_duplex();
}
static void get_call_info(char *str)
{
char number[20];
char name[256];
int i = 0;
char *p0=str;
char *p1=number;
char *p2=name;
if(!str)
return;
while(*p0!='\0')
{
if(*p0=='\"')
i++;
if(i==1)
{
if(*p0!='\"')
{*p1=*p0;p1++;}
}
if(i==3)
{
if(*p0!='\"')
{*p2=*p0;p2++;}
}
p0++;
}
printf("Call info: %s\n", str);
if(i>0)
printf("Call number: %s\n", number);
if(i>2)
printf("Call name: %s\n", name);
}
int bt_test_hfp_hp_cb(const char *bd_addr, RK_BT_HFP_EVENT event, void *data)
{
switch(event) {
case RK_BT_HFP_CONNECT_EVT:
printf("+++++ BT HFP HP CONNECT(%s) +++++\n", bd_addr);
printf("device platform is %s\n", rk_bt_get_dev_platform((char *)bd_addr) == RK_BT_DEV_PLATFORM_UNKNOWN ?
"Unknown Platform" : "Apple IOS");
break;
case RK_BT_HFP_DISCONNECT_EVT:
printf("+++++ BT HFP HP DISCONNECT(%s) +++++\n", bd_addr);
break;
case RK_BT_HFP_RING_EVT:
printf("+++++ BT HFP HP RING(%s) +++++\n", bd_addr);
break;
case RK_BT_HFP_AUDIO_OPEN_EVT:
printf("+++++ BT HFP AUDIO OPEN(%s) +++++\n", bd_addr);
hfp_open_audio_duplex();
break;
case RK_BT_HFP_AUDIO_CLOSE_EVT:
printf("+++++ BT HFP AUDIO CLOSE(%s) +++++\n", bd_addr);
hfp_close_audio_duplex();
break;
case RK_BT_HFP_PICKUP_EVT:
printf("+++++ BT HFP PICKUP(%s) +++++\n", bd_addr);
break;
case RK_BT_HFP_HANGUP_EVT:
printf("+++++ BT HFP HANGUP(%s) +++++\n", bd_addr);
break;
case RK_BT_HFP_VOLUME_EVT:
{
unsigned short volume = *(unsigned short*)data;
printf("+++++ BT HFP VOLUME CHANGE, volume: %d +++++\n", volume);
break;
}
case RK_BT_HFP_BCS_EVT:
{
unsigned short codec_type = *(unsigned short*)data;
printf("+++++ BT HFP BCS EVENT: %d(%s) +++++\n", codec_type,
(codec_type == BT_SCO_CODEC_MSBC) ? "mSBC":"CVSD");
sco_codec = (RK_BT_SCO_CODEC_TYPE)codec_type;
break;
}
case RK_BT_HFP_CLIP_EVT:
{
printf("+++++ BT HFP CLIP EVENT(%s) +++++\n", bd_addr);
get_call_info((char *)data);
break;
}
case RK_BT_HFP_OUTGOING_CALL_DIAL_EVT:
printf("+++++ BT HFP OUTGOING CALL DIAL EVT(%s) +++++\n", bd_addr);
break;
case RK_BT_HFP_OUTGOING_CALL_RING_EVT:
printf("+++++ BT HFP OUTGOING CALL RING EVT(%s) +++++\n", bd_addr);
break;
case RK_BT_HFP_CLCC_EVT:
{
printf("+++++ BT HFP CLCC EVENT(%s) +++++\n", bd_addr);
get_call_info((char *)data);
}
default:
break;
}
return 0;
}
void bt_test_hfp_hp_open(char *data)
{
int ret = 0;
/* must be placed before rk_bt_hfp_open */
rk_bt_hfp_register_callback(bt_test_hfp_hp_cb);
/* only bsa: if enable cvsd, sco_codec must be set to BT_SCO_CODEC_CVSD */
rk_bt_hfp_enable_cvsd();
ret = rk_bt_hfp_open();
if (ret < 0)
printf("%s hfp open failed!\n", __func__);
}
void bt_test_hfp_hp_accept(char *data)
{
int ret = 0;
ret = rk_bt_hfp_pickup();
if (ret < 0)
printf("%s hfp accept failed!\n", __func__);
}
void bt_test_hfp_hp_hungup(char *data)
{
int ret = 0;
ret = rk_bt_hfp_hangup();
if (ret < 0)
printf("%s hfp hungup failed!\n", __func__);
}
void bt_test_hfp_hp_redial(char *data)
{
int ret = 0;
ret = rk_bt_hfp_redial();
if (ret < 0)
printf("%s hfp redial failed!\n", __func__);
}
void bt_test_hfp_hp_dial_number(char *data)
{
rk_bt_hfp_dial_number(data);
}
void bt_test_hfp_hp_report_battery(char *data)
{
int ret = 0;
int i = 0;
for (i = 0; i < 10; i++) {
ret = rk_bt_hfp_report_battery(i);
if (ret < 0) {
printf("%s hfp report battery(%d) failed!\n", __func__, i);
break;
}
sleep(1);
}
}
void bt_test_hfp_hp_set_volume(char *data)
{
int i;
for(i = 0; i <= 15; i++) {
if (rk_bt_hfp_set_volume(i) < 0) {
printf("%s hfp set volume(%d) failed!\n", __func__, i);
break;
}
sleep(2);
}
}
void bt_test_hfp_hp_close(char *data)
{
rk_bt_hfp_close();
}
void bt_test_hfp_hp_disconnect(char *data)
{
rk_bt_hfp_disconnect();
}
void bt_test_hfp_sink_open(char *data)
{
rk_bt_sink_register_volume_callback(bt_sink_volume_callback);
rk_bt_sink_register_track_callback(bt_sink_track_change_callback);
rk_bt_sink_register_position_callback(bt_sink_position_change_callback);
rk_bt_sink_register_callback(bt_sink_callback);
rk_bt_hfp_register_callback(bt_test_hfp_hp_cb);
rk_bt_hfp_sink_open();
}
/******************************************/
/* OBEX */
/******************************************/
static void obex_pbap_event_cb(const char *bd_addr, RK_BT_OBEX_STATE state)
{
switch(state) {
case RK_BT_OBEX_CONNECT_FAILED:
printf("----- RK_BT_OBEX_CONNECT_FAILED(%s) -----\n", bd_addr);
break;
case RK_BT_OBEX_CONNECTED:
printf("----- RK_BT_OBEX_CONNECTED(%s) -----\n", bd_addr);
break;
case RK_BT_OBEX_DISCONNECT_FAILED:
printf("----- RK_BT_OBEX_DISCONNECT_FAILED(%s) -----\n", bd_addr);
break;
case RK_BT_OBEX_DISCONNECTED:
printf("----- RK_BT_OBEX_DISCONNECTED(%s) -----\n", bd_addr);
break;
case RK_BT_OBEX_TRANSFER_ACTIVE:
printf("----- RK_BT_OBEX_TRANSFER_ACTIVE(%s) -----\n", bd_addr);
break;
case RK_BT_OBEX_TRANSFER_COMPLETE:
printf("----- RK_BT_OBEX_TRANSFER_COMPLETE(%s) -----\n", bd_addr);
break;
}
}
void bt_test_obex_init(char *data)
{
rk_bt_obex_init(data);
}
void bt_test_obex_pbap_init(char *data)
{
rk_bt_obex_register_status_cb(obex_pbap_event_cb);
rk_bt_obex_pbap_init();
}
void bt_test_obex_pbap_connect(char *data)
{
rk_bt_obex_pbap_connect(data);
}
void bt_test_obex_pbap_get_pb_vcf(char *data)
{
rk_bt_obex_pbap_get_vcf("pb", "/data/pb.vcf");
}
void bt_test_obex_pbap_get_ich_vcf(char *data)
{
rk_bt_obex_pbap_get_vcf("ich", "/data/ich.vcf");
}
void bt_test_obex_pbap_get_och_vcf(char *data)
{
rk_bt_obex_pbap_get_vcf("och", "/data/och.vcf");
}
void bt_test_obex_pbap_get_mch_vcf(char *data)
{
rk_bt_obex_pbap_get_vcf("mch", "/data/mch.vcf");
}
void bt_test_obex_pbap_get_spd_vcf(char *data)
{
rk_bt_obex_pbap_get_vcf("spd", "/data/spd.vcf");
}
void bt_test_obex_pbap_get_fav_vcf(char *data)
{
rk_bt_obex_pbap_get_vcf("fav", "/data/fav.vcf");
}
void bt_test_obex_pbap_disconnect(char *data)
{
rk_bt_obex_pbap_disconnect(data);
}
void bt_test_obex_pbap_deinit(char *data)
{
rk_bt_obex_pbap_deinit();
}
void bt_test_obex_deinit(char *data)
{
rk_bt_obex_deinit();
}
/******************************************/
/* PAN */
/******************************************/
static void pan_event_cb(RK_BT_PAN_EVENT event, char *bd_addr)
{
switch(event) {
case RK_BT_PAN_CONNECT_FAILED:
printf("----- RK_BT_PAN_CONNECT_FAILED(%s) -----\n", bd_addr);
break;
case RK_BT_PAN_CONNECT:
printf("----- RK_BT_PAN_CONNECT(%s) -----\n", bd_addr);
break;
case RK_BT_PAN_DISCONNECT:
printf("----- RK_BT_PAN_DISCONNECT(%s) -----\n", bd_addr);
break;
}
}
void bt_test_pan_init(char *data)
{
rk_bt_pan_register_event_cb(pan_event_cb);
rk_bt_pan_open();
}
void bt_test_pan_deinit(char *data)
{
rk_bt_pan_close();
}
void bt_test_pan_connect(char *data)
{
rk_bt_pan_connect(data);
}
void bt_test_pan_disconnect(char *data)
{
rk_bt_pan_disconnect(data);
}