语言

Menu
Sites
Language
Bluetooth audio connect

Hi,

I'm trying to connect my Gear s3 wearable to a bluetooth speaker(like JBL) and play a sound. I assume we must use the "Bluetooth Audio" API for this but after connecting to the bluetooth device speaker and entering the callback function (bt_audio_set_connection_state_changed_cb ()) upon successful connection, I try to play a sound it comes out from the wearable and not from the speaker.

1)What am I missing out here that I should implement to ensure the sound comes out through the speaker ? If you personally explain and enumerate the important steps to be done to achieve my goal and what API must be used,that would be helpful.

2)Also, If I want to reduce the latency between the speaker(sink) and the device(source), how can I do that?

响应

4 回复
K Johnson

Would you please share your full source code here?

Subhodip Mandal
#include "furstproject.h"
#include <bluetooth.h>
#include <player.h>
#include <storage.h>
#include <app.h>
 
typedef struct appdata
{
Evas_Object *win;
Evas_Object *conform;
Evas_Object *label;
bt_adapter_device_discovery_info_s *chosenDevice;
player_h player;
} appdata_s;
 
 
static void
win_delete_request_cb(void *data, Evas_Object *obj, void *event_info)
{
ui_app_exit();
}
 
static void
win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s *ad = data;
/* Let window go to hide state. */
elm_win_lower(ad->win);
}
 
void playAgain(void *data, Evas_Object *obj, void *event_info)  //function to play the sound again
{
appdata_s *ad = (appdata_s*) data;
Evas_Object *buttonstart =obj;
 
evas_object_smart_callback_add(buttonstart, "clicked", playAgain, ad);
int    error_code = player_start(ad->player);
    elm_object_text_set(buttonstart, "play again");
    if (error_code != PLAYER_ERROR_NONE)
    elm_object_text_set(buttonstart, "failed to play ");
 
}
 
void musicstream(int result, bool connected, const char *remote_address, bt_audio_profile_type_e type, void *user_data)
{
appdata_s *ad = (appdata_s*) user_data;
 
 
/* Create a button */
Evas_Object *buttonstart;
buttonstart = elm_button_add(ad->win);
elm_object_style_set(buttonstart, "bottom");
evas_object_move(buttonstart,180,150);
evas_object_show(buttonstart);
elm_object_text_set(buttonstart, "play song");
 
 
int error_code = player_create(&ad->player);   //preparing the media player
    if (error_code != PLAYER_ERROR_NONE)
    elm_object_text_set(buttonstart,  "failed to create");
 
    error_code = player_set_uri(ad->player, "file:///opt/usr/media/Music/button.mp3");//uploading the file to play
    if (error_code != PLAYER_ERROR_NONE)
    elm_object_text_set(buttonstart,"file location error");
 
error_code = player_prepare(ad->player);   //preparing the media player
    if (error_code != PLAYER_ERROR_NONE)
    elm_object_text_set(buttonstart, "failed to prepare ");
 
    evas_object_smart_callback_add(buttonstart, "clicked", playAgain, ad);  //instruction set to play the sound
    error_code = player_start(ad->player);
    elm_object_text_set(buttonstart, "play again");
    if (error_code != PLAYER_ERROR_NONE)
    elm_object_text_set(buttonstart, "failed to play ");
 
}
 
 
void bond_created_cb(int result, bt_device_info_s *device_info, void *user_data)
{
appdata_s *ad = (appdata_s*) user_data;
 
bt_error_e ret;
Evas_Object *buttonstart
 
    /* Create a button */
buttonstart = elm_button_add(ad->win);
elm_object_style_set(buttonstart, "bottom");
evas_object_move(buttonstart,180,150);
evas_object_show(buttonstart);
 
 
ret = bt_audio_initialize();
 
if (ret != BT_ERROR_NONE) {
elm_object_text_set(buttonstart, "[bt_initialize] failed.");
    return;
}
 
bt_audio_set_connection_state_changed_cb (musicstream, ad);
ret = bt_audio_connect(device_info->remote_address, BT_AUDIO_PROFILE_TYPE_A2DP );
if (ret != BT_ERROR_NONE) {
elm_object_text_set(buttonstart, "profile failed");
    return;
}
 
 
}
void chosen(void *data, Evas_Object *obj, void *event_info)//to bond with the device chosen by the user
{
appdata_s *ad = (appdata_s*)data;
 
bt_device_set_bond_created_cb(bond_created_cb, ad);
 
bt_adapter_device_discovery_info_s *device_info = ad->chosenDevice;
bt_error_e ret = bt_device_create_bond( device_info->remote_address);
if (ret != BT_ERROR_NONE )
{
elm_object_text_set(obj, "failed to connect");
return;
}
//elm_object_text_set(obj, "device now connected");
 
 
}
void printOption(int result,  bt_adapter_device_discovery_state_e discovery_state,
             bt_adapter_device_discovery_info_s *discovery_info, void *user_data)
{
appdata_s *ad= user_data;
Evas_Object *buttonstart;
 
 
    /* Create a button */
buttonstart = elm_button_add(ad->win);
elm_object_style_set(buttonstart, "bottom");
evas_object_move(buttonstart,180,150);
evas_object_show(buttonstart);
 
 
 
 
if (result != BT_ERROR_NONE) {
elm_object_text_set(buttonstart, "[adapter_device_discovery_state_changed_cb] failed! result(%d).");
return;
}
 
switch (discovery_state) {
 
case BT_ADAPTER_DEVICE_DISCOVERY_STARTED:
elm_object_text_set(buttonstart,  "STARTED");
        break;
    case BT_ADAPTER_DEVICE_DISCOVERY_FINISHED:
    elm_object_text_set(buttonstart,  "RECYCLE DEVICE LIST");
        break;
    case BT_ADAPTER_DEVICE_DISCOVERY_FOUND:
    if (discovery_info != NULL)
    {
    elm_object_text_set(buttonstart,  discovery_info->remote_name);//print device name 
    ad->chosenDevice = discovery_info; //saving data of the device found,incase this is selected by user when clicking on button
    evas_object_smart_callback_add(buttonstart, "clicked", chosen, ad);
    }
         break;
  }
}
 
void search(void *data, Evas_Object *obj, void *event_info)
{
bt_error_e ret;
 
ret = bt_initialize();
if (ret != BT_ERROR_NONE) {
elm_object_text_set(obj, "[bt_initialize] failed.");
    return;
}
appdata_s *ad = (appdata_s*)data;
 
bt_adapter_device_discovery_state_changed_cb foundDevice = printOption;
 
bt_adapter_set_device_discovery_state_changed_cb(foundDevice,ad);
 
ret = bt_adapter_start_device_discovery();
 
if (ret != BT_ERROR_NONE)
switch(ret)
{
case BT_ERROR_NOT_INITIALIZED : elm_object_text_set(obj,"not intialized");
break;
case BT_ERROR_NOT_ENABLED : elm_object_text_set(obj,"Not enabled");
break;
case BT_ERROR_NOW_IN_PROGRESS : elm_object_text_set(obj,"Operation is now in progress");
break;
case BT_ERROR_OPERATION_FAILED :elm_object_text_set(obj,"Operation failed");
break;
case BT_ERROR_NOT_SUPPORTED : elm_object_text_set(obj,"Not Supported");
break;
case BT_ERROR_PERMISSION_DENIED :elm_object_text_set(obj,"Permission denied");
break;
 
}
 
 
 
}
 
static void
create_base_gui(appdata_s *ad)
{
char name[10] = "Dipster";
/* Window */
/* Create and initialize elm_win.
   elm_win is mandatory to manipulate window. */
ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
elm_win_autodel_set(ad->win, EINA_TRUE);
 
if (elm_win_wm_rotation_supported_get(ad->win)) {
int rots[4] = { 0, 90, 180, 270 };
elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
}
 
evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);
eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);
 
/* Conformant */
/* Create and initialize elm_conformant.
   elm_conformant is mandatory for base gui to have proper size
   when indicator or virtual keypad is visible. */
ad->conform = elm_conformant_add(ad->win);
elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);
evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(ad->win, ad->conform);
evas_object_show(ad->conform);
 
 
 
 
/* Label */
/* Create an actual view of the base gui.
   Modify this part to change the view. */
ad->label = elm_label_add(ad->conform);
elm_object_text_set(ad->label, "<align=center>Hello Tizen</align>");
evas_object_size_hint_weight_set(ad->label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_object_content_set(ad->conform, ad->label);
 
 
 
 
      Evas_Object *buttonstart;
 
 
/* Create a button */
buttonstart = elm_button_add(ad->win);
elm_object_text_set(buttonstart, "Search Bluetooth devices");
elm_object_style_set(buttonstart, "bottom");
evas_object_move(buttonstart,180,250);
evas_object_show(buttonstart);
 
/* Show window after base gui is set up */
evas_object_show(ad->win);
evas_object_smart_callback_add(buttonstart, "clicked", search, ad);
 
}
 
 
 
static bool
app_create(void *data)
{
/* Hook to take necessary actions before main event loop starts
Initialize UI resources and application's data
If this function returns true, the main loop of application starts
If this function returns false, the application is terminated */
appdata_s *ad = data;
 
create_base_gui(ad);
 
return true;
}
 
static void
app_control(app_control_h app_control, void *data)
{
/* Handle the launch request. */
}
 
static void
app_pause(void *data)
{
/* Take necessary actions when application becomes invisible. */
}
 
static void
app_resume(void *data)
{
/* Take necessary actions when application becomes visible. */
}
 
static void
app_terminate(void *data)
{
/* Release all resources. */
}
 
static void
ui_app_lang_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LANGUAGE_CHANGED*/
char *locale = NULL;
system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
elm_language_set(locale);
free(locale);
return;
}
 
static void
ui_app_orient_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_DEVICE_ORIENTATION_CHANGED*/
return;
}
 
static void
ui_app_region_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_REGION_FORMAT_CHANGED*/
}
 
static void
ui_app_low_battery(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LOW_BATTERY*/
}
 
static void
ui_app_low_memory(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LOW_MEMORY*/
}
 
int
main(int argc, char *argv[])
{
appdata_s ad = {0,};
int ret = 0;
 
ui_app_lifecycle_callback_s event_callback = {0,};
app_event_handler_h handlers[5] = {NULL, };
 
event_callback.create = app_create;
event_callback.terminate = app_terminate;
event_callback.pause = app_pause;
event_callback.resume = app_resume;
event_callback.app_control = app_control;
 
ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, ui_app_low_battery, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, ui_app_low_memory, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, ui_app_orient_changed, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, ui_app_region_changed, &ad);
 
ret = ui_app_main(argc, argv, &event_callback, &ad);
if (ret != APP_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "app_main() is failed. err = %d", ret);
}
 
return ret;
}
Subhodip Mandal

If I can brief my approach to makew it easy for you to understand, -

the code that concerns my query is from the search() function onwards.
Any code below that has no role in my application other than setting up the GUI and the app lifecycle.

-So we begin with the search() function inside which,-> first bt_intitialize,then device discovery,then upon device discovery,callback to printOption().

-In printOption() function,print the list of devices , select those devices via a button,upon selection, callback to chosen() function.

-in chosen() fucntion, bond with that device that has been chosen by the user touching the button,callback to bond_created_cb() function,

- in bond_created_cb(), initialize the bt_audio_intialize(), and perform bt_audio_connect(),set the bluetooth profile type and callback to musicStream() function.

- in musicStream() function, create a media player and play a sound. this should automatically play in the bonded bluetooth device.

 

 

Please point out my mistakes and tell me what I should do to correct my code. My objective is get the wearable to produce a sound in the bluetooth device. This is very urgent so I will be very grateful if I can get a viable solution from you.

K Johnson

Hi Subhodip Mandal,

I've tried to test your code. While debugging it, I've found that it can discover devices properly, get remote device name and bluetooth address correctly. According to my findings, the problem can be with playing media files, which is the task of musicstream() function. In this scenario, I would like to suggest you to develop another app which will play an audio file only and after that use the code of that app inside musicstream() function.