/***************************************************************************** ** ** Name: wm_audio_sink.c ** ** Description: This file contains the sample functions for bluetooth audio sink application ** *****************************************************************************/ #include #include #include #include #include "wm_bt_config.h" #if (WM_BTA_AV_SINK_INCLUDED == CFG_ON) #include "wm_bt_av.h" #include "wm_audio_sink.h" #include "wm_bt_util.h" #if (WM_AUDIO_BOARD_INCLUDED == CFG_ON) #include "audio.h" #endif static uint16_t g_sample_rate = 44100; static uint8_t g_bit_width = 16; static uint8_t g_chan_count = 2; static uint8_t g_playing_state = 0; /**This function is the pcm output function, type is 0(PCM)*/ #if (WM_AUDIO_BOARD_INCLUDED == CFG_ON) static uint32_t Stereo2Mono(void *audio_buf, uint32_t len, int LR) { if (!audio_buf || !len || len % 4) { printf( "%s arg err\n", __func__); return 0; } int16_t *buf = audio_buf; uint32_t i = 0; LR = LR ? 1 : 0; for (i = 0; i < len / 4; i++) { buf[i] = buf[i * 2 + LR]; } return len / 2; } int btif_co_avk_data_incoming(uint8_t type, uint8_t *p_data,uint16_t length) { uint16_t fif0_len = 0; Stereo2Mono(p_data, length, 1); fif0_len = FifoSpaceLen(); if(fif0_len < length/2) { printf("overwritten, fifo_space(%d), write to len(%d)\r\n", fif0_len, length/2); } FifoWrite(p_data, length/2); if(g_playing_state) { if(FifoDataLen()>4*1024) { PlayStart(g_sample_rate, g_bit_width, g_chan_count); g_playing_state = 0; } } } #else int btif_co_avk_data_incoming(uint8_t type, uint8_t *p_data,uint16_t length) { } #endif static void bta2dp_connection_state_callback(tls_btav_connection_state_t state, tls_bt_addr_t *bd_addr) { switch(state) { case WM_BTAV_CONNECTION_STATE_DISCONNECTED: TLS_BT_APPL_TRACE_DEBUG("BTAV_CONNECTION_STATE_DISCONNECTED\r\n"); //sbc_ABV_buffer_reset(); break; case WM_BTAV_CONNECTION_STATE_CONNECTING: TLS_BT_APPL_TRACE_DEBUG("BTAV_CONNECTION_STATE_CONNECTING\r\n"); break; case WM_BTAV_CONNECTION_STATE_CONNECTED: TLS_BT_APPL_TRACE_DEBUG("BTAV_CONNECTION_STATE_CONNECTED\r\n"); break; case WM_BTAV_CONNECTION_STATE_DISCONNECTING: TLS_BT_APPL_TRACE_DEBUG("BTAV_CONNECTION_STATE_DISCONNECTING\r\n"); break; default: TLS_BT_APPL_TRACE_DEBUG("UNKNOWN BTAV_AUDIO_STATE...\r\n"); } } static void bta2dp_audio_state_callback(tls_btav_audio_state_t state, tls_bt_addr_t *bd_addr) { switch(state) { case WM_BTAV_AUDIO_STATE_STARTED: TLS_BT_APPL_TRACE_DEBUG("BTAV_AUDIO_STATE_STARTED\r\n"); //sbc_ABV_buffer_reset(); //VolumeControl(16); //PlayStart(g_sample_rate, g_bit_width); g_playing_state = 1; break; case WM_BTAV_AUDIO_STATE_STOPPED: TLS_BT_APPL_TRACE_DEBUG("BTAV_AUDIO_STATE_STOPPED\r\n"); #if (WM_AUDIO_BOARD_INCLUDED == CFG_ON) PlayStop(); #endif break; case WM_BTAV_AUDIO_STATE_REMOTE_SUSPEND: TLS_BT_APPL_TRACE_DEBUG("BTAV_AUDIO_STATE_REMOTE_SUSPEND\r\n"); #if (WM_AUDIO_BOARD_INCLUDED == CFG_ON) PlayStop(); #endif break; default: TLS_BT_APPL_TRACE_DEBUG("UNKNOWN BTAV_AUDIO_STATE...\r\n"); } } static void bta2dp_audio_config_callback(tls_bt_addr_t *bd_addr, uint32_t sample_rate, uint8_t channel_count) { TLS_BT_APPL_TRACE_DEBUG("CBACK:%02x:%02x:%02x:%02x:%02x:%02x::sample_rate=%d, channel_count=%d\r\n", bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3], bd_addr->address[4], bd_addr->address[5], sample_rate, channel_count); g_sample_rate = sample_rate; } static void bta2dp_audio_payload_callback(tls_bt_addr_t *bd_addr, uint8_t format, uint8_t *p_data, uint16_t length) { //TLS_BT_APPL_TRACE_DEBUG("CBACK(%s): length=%d\r\n", __FUNCTION__, length); } static void btavrcp_remote_features_callback(tls_bt_addr_t *bd_addr, tls_btrc_remote_features_t features) { TLS_BT_APPL_TRACE_DEBUG("CBACK(%s): features:%d\r\n", __FUNCTION__, features); } static void btavrcp_get_play_status_callback() { TLS_BT_APPL_TRACE_DEBUG("CBACK(%s): \r\n", __FUNCTION__); } static void btavrcp_get_element_attr_callback(uint8_t num_attr, tls_btrc_media_attr_t *p_attrs) { TLS_BT_APPL_TRACE_DEBUG("CBACK(%s): num_attr:%d, param:%d\r\n", __FUNCTION__, num_attr); } static void btavrcp_register_notification_callback(tls_btrc_event_id_t event_id, uint32_t param) { TLS_BT_APPL_TRACE_DEBUG("CBACK(%s): event_id:%d, param:%d\r\n", __FUNCTION__, event_id, param); } static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype) { TLS_BT_APPL_TRACE_DEBUG("CBACK: volume:%d, type:%d\r\n", volume, ctype); } static void btavrcp_passthrough_command_callback(int id, int pressed) { TLS_BT_APPL_TRACE_DEBUG("CBACK(%s): id:%d, pressed:%d\r\n", __FUNCTION__, id, pressed); } static void btavrcp_passthrough_response_callback(int id, int pressed) { } static void btavrcp_connection_state_callback(bool state, tls_bt_addr_t *bd_addr) { TLS_BT_APPL_TRACE_DEBUG("CBACK:%02x:%02x:%02x:%02x:%02x:%02x::state:%d\r\n", bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3], bd_addr->address[4], bd_addr->address[5], state); } static void wm_a2dp_sink_callback(tls_bt_av_evt_t evt, tls_bt_av_msg_t *msg) { switch(evt) { case WMBT_A2DP_CONNECTION_STATE_EVT: bta2dp_connection_state_callback(msg->av_connection_state.stat, msg->av_connection_state.bd_addr); break; case WMBT_A2DP_AUDIO_STATE_EVT: bta2dp_audio_state_callback(msg->av_audio_state.stat, msg->av_audio_state.bd_addr); break; case WMBT_A2DP_AUDIO_CONFIG_EVT: bta2dp_audio_config_callback(msg->av_audio_config.bd_addr, msg->av_audio_config.sample_rate, msg->av_audio_config.channel_count); break; case WMBT_A2DP_AUDIO_PAYLOAD_EVT: bta2dp_audio_payload_callback(msg->av_audio_payload.bd_addr,msg->av_audio_payload.audio_format,msg->av_audio_payload.payload, msg->av_audio_payload.payload_length); break; } } static void wm_btrc_callback(tls_btrc_evt_t evt, tls_btrc_msg_t *msg) { switch(evt) { case WM_BTRC_REMOTE_FEATURE_EVT: btavrcp_remote_features_callback(msg->remote_features.bd_addr, msg->remote_features.features); break; case WM_BTRC_GET_PLAY_STATUS_EVT: btavrcp_get_play_status_callback(); break; case WM_BTRC_GET_ELEMENT_ATTR_EVT: btavrcp_get_element_attr_callback(msg->get_element_attr.num_attr, msg->get_element_attr.p_attrs); break; case WM_BTRC_REGISTER_NOTIFICATION_EVT: btavrcp_register_notification_callback(msg->register_notification.event_id, msg->register_notification.param); break; case WM_BTRC_VOLUME_CHANGED_EVT: btavrcp_volume_change_callback(msg->volume_change.ctype, msg->volume_change.volume); break; case WM_BTRC_PASSTHROUGH_CMD_EVT: btavrcp_passthrough_command_callback(msg->passthrough_cmd.id, msg->passthrough_cmd.key_state); break; default: TLS_BT_APPL_TRACE_VERBOSE("unhandled wm_btrc_callback, evt=%d\r\n", evt); break; } } static void wm_btrc_ctrl_callback(tls_btrc_ctrl_evt_t evt, tls_btrc_ctrl_msg_t *msg) { switch(evt) { case WM_BTRC_PASSTHROUGH_CMD_EVT: btavrcp_passthrough_response_callback(msg->passthrough_rsp.id, msg->passthrough_rsp.key_state); break; default: TLS_BT_APPL_TRACE_VERBOSE("unhandled wm_btrc_ctrl_callback, evt=%d\r\n", evt); break; } } tls_bt_status_t tls_bt_enable_a2dp_sink() { tls_bt_status_t status; status = tls_bt_av_sink_init(wm_a2dp_sink_callback); if(status != TLS_BT_STATUS_SUCCESS) { TLS_BT_APPL_TRACE_ERROR("tls_bt_av_sink_init failed, status=%d\r\n", status); return status; } status = tls_btrc_init(wm_btrc_callback); if(status != TLS_BT_STATUS_SUCCESS) { TLS_BT_APPL_TRACE_ERROR("tls_btrc_init failed, status=%d\r\n", status); tls_bt_av_sink_deinit(); return status; } status = tls_btrc_ctrl_init(wm_btrc_ctrl_callback); if(status != TLS_BT_STATUS_SUCCESS) { TLS_BT_APPL_TRACE_ERROR("tls_btrc_init failed, status=%d\r\n", status); tls_bt_av_sink_deinit(); tls_btrc_deinit(); return status; } #if (WM_AUDIO_BOARD_INCLUDED == CFG_ON) AudioInit(12*1024); #endif return status; } tls_bt_status_t tls_bt_disable_a2dp_sink() { tls_bt_av_sink_deinit(); tls_btrc_deinit(); tls_btrc_ctrl_deinit(); return TLS_BT_STATUS_SUCCESS; } #endif