4 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Dohyun Pyun <dh79.pyun@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 #include <vconf-internal-keys.h>
25 #include <oal-event.h>
26 #include <oal-hardware.h>
27 #include <oal-audio-src.h>
29 #include "bt-service-common.h"
30 #include "bt-service-audio-common.h"
31 #include "bt-service-event.h"
32 #include "bt-service-avrcp-tg.h"
34 /* Avoid the build error related to vconf.h's dependency */
35 #ifndef VCONFKEY_BT_AVC_MODE
36 #define VCONFKEY_BT_AVC_MODE "db/bluetooth/avc_mode"
39 #ifndef VCONFKEY_BT_AVC_OFF
40 #define VCONFKEY_BT_AVC_OFF false
43 #define ABSOLUTE_VOLUME_MAX 150
44 #define BT_VOLUME_MAX 127
46 static unsigned int absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
47 static unsigned int bt_volume = BT_VOLUME_MAX + 1;
48 static unsigned int avc_mode = BT_AVC_OFF;
50 static void __bt_audio_covert_system_to_bt_volume(unsigned int sys_vol, unsigned int *bt_vol)
52 /* Convert system gain to BT
53 BT volume range : 0 ~ 127
54 system volume range : 0 ~ 150 */
56 *bt_vol = 127 * ((float)sys_vol / 150);
59 system volume : 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
60 avrcp volume : 0 9 17 26 34 43 51 60 68 77 85 94 102 111 119 127 */
62 if (*bt_vol > 0 && *bt_vol < 127)
63 *bt_vol = *bt_vol + 1;
65 BT_DBG("System volume [%d], BT volume [%d]", sys_vol, *bt_vol);
68 static void __bt_audio_covert_bt_to_system_volume(unsigned int bt_vol, unsigned int *sys_vol)
70 /* Convert BT gain to system
71 BT volume range : 0 ~ 127
72 system volume range : 0 ~ 150 */
74 *sys_vol = 150 * ((float)bt_vol / 127);
77 system volume : 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
78 avrcp volume : 0 9 17 26 34 43 51 60 68 77 85 94 102 111 119 127 */
80 if (*sys_vol > 0 && *sys_vol < 150)
81 *sys_vol = *sys_vol + 1;
83 BT_DBG("System volume [%d], BT volume [%d]", *sys_vol, bt_vol);
86 static int __bt_audio_get_active_headset_volume(void)
88 int result = BLUETOOTH_ERROR_NONE;
89 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
90 bluetooth_device_address_t device_address;
91 gboolean connected = FALSE;
92 unsigned int volume = BT_VOLUME_MAX + 1;
94 /* 1. Get active A2DP headset path */
96 /* We should modify this function to get the active headset in later */
97 connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
99 if (connected == FALSE) {
100 BT_DBG("There is no active A2DP headset");
104 _bt_convert_addr_string_to_type(device_address.addr, connected_address);
106 /* 2. Get volume info for active transport for the path */
107 result = _bt_avrcp_target_get_volume(&device_address, &volume);
108 if (result != BLUETOOTH_ERROR_NONE) {
109 BT_ERR("Fail to notify BT volume to headset");
113 if (volume > BT_VOLUME_MAX) {
114 BT_DBG("Absolute Volume is not set in transport");
121 static void __bt_audio_notify_avc_mode_changed(unsigned int avc_mode)
123 GVariant *param = g_variant_new("(u)", avc_mode);
125 _bt_send_event(BT_AUDIO_AVC_EVENT,
126 BLUETOOTH_EVENT_AUDIO_AVC_MODE_CHANGED,
130 static void __bt_audio_set_avc_mode(unsigned int mode)
132 unsigned int prev_mode = avc_mode;
134 if (prev_mode == mode) {
135 BT_DBG("No avc mode change");
139 BT_ERR("Previous mode [%d], New mode [%d]", prev_mode, mode);
141 __bt_audio_notify_avc_mode_changed(mode);
146 static void __bt_audio_sync_absolute_volume(unsigned int bt_vol)
148 if (absolute_volume > ABSOLUTE_VOLUME_MAX || bt_volume > BT_VOLUME_MAX) {
149 unsigned int sys_vol = 0;
151 BT_DBG("synchronize the system and bt volume");
153 __bt_audio_covert_bt_to_system_volume(bt_vol, &sys_vol);
156 absolute_volume = sys_vol;
160 static void __bt_audio_set_user_avc_value(bool mode)
165 __bt_audio_set_avc_mode(BT_AVC_OFF);
169 volume = __bt_audio_get_active_headset_volume();
172 __bt_audio_set_avc_mode(BT_AVC_OFF);
176 BT_INFO("The current transport supports AVC : volume [%d]", volume);
179 __bt_audio_set_avc_mode(BT_AVC_NULL);
181 BT_DBG("BT volume: %d", volume);
182 __bt_audio_set_avc_mode(BT_AVC_MAX);
185 __bt_audio_sync_absolute_volume(volume);
188 static void __bt_audio_user_avc_mode_cb(keynode_t *node, void *data)
191 bool mode = VCONFKEY_BT_AVC_OFF;
193 DBG_SECURE("key=%s", vconf_keynode_get_name(node));
194 type = vconf_keynode_get_type(node);
196 if (type == VCONF_TYPE_BOOL) {
197 mode = vconf_keynode_get_bool(node);
198 __bt_audio_set_user_avc_value(mode);
200 BT_ERR("Invaild vconf key type : %d", type);
204 int _bt_audio_init_absolute_volume_control(void)
206 absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
207 bt_volume = BT_VOLUME_MAX + 1;
208 avc_mode = BT_AVC_OFF;
210 if (vconf_notify_key_changed(VCONFKEY_BT_AVC_MODE,
211 (vconf_callback_fn)__bt_audio_user_avc_mode_cb, NULL) < 0) {
212 BT_ERR("Unable to register key handler");
213 return BLUETOOTH_ERROR_INTERNAL;
216 return BLUETOOTH_ERROR_NONE;
219 void _bt_audio_deinit_absolute_volume_control(void)
221 absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
222 bt_volume = BT_VOLUME_MAX + 1;
223 avc_mode = BT_AVC_OFF;
225 vconf_ignore_key_changed(VCONFKEY_BT_AVC_MODE,
226 (vconf_callback_fn)__bt_audio_user_avc_mode_cb);
229 int _bt_audio_set_absolute_volume(unsigned int volume)
231 int result = BLUETOOTH_ERROR_NONE;
232 unsigned int bt_vol = 0;
233 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
234 bluetooth_device_address_t device_address;
235 gboolean connected = FALSE;
238 BT_ERR("The volume exceeded 150");
239 return BLUETOOTH_ERROR_INVALID_PARAM;
242 if (avc_mode == BT_AVC_OFF) {
243 BT_ERR("AVC mode is off");
244 return BLUETOOTH_ERROR_INTERNAL;
247 /* We should modify this function to get the active headset in later */
248 connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
250 if (connected == FALSE) {
251 BT_DBG("There is no active A2DP headset");
252 return BLUETOOTH_ERROR_NOT_CONNECTED;
255 _bt_convert_addr_string_to_type(device_address.addr, connected_address);
257 /* 1. Translate the absolute volume to bt volume */
258 __bt_audio_covert_system_to_bt_volume(volume, &bt_vol);
261 absolute_volume = volume;
263 /* 2. Notify the bt_volume to transport (BT Headset) */
264 result = _bt_avrcp_target_notify_volume(&device_address, bt_volume);
265 if (result != BLUETOOTH_ERROR_NONE)
266 BT_ERR("Fail to notify BT volume to headset");
268 /* 3. Notify the avc mode to the pulseaudio if it is needed */
270 __bt_audio_set_avc_mode(BT_AVC_NULL);
272 BT_DBG("System volume: %d", volume);
273 __bt_audio_set_avc_mode(BT_AVC_MAX);
279 /* Just return the absolute_volume value */
280 int _bt_audio_get_absolute_volume(unsigned int *volume)
282 int result = BLUETOOTH_ERROR_NONE;
284 if (avc_mode == BT_AVC_OFF) {
285 BT_ERR("AVC mode is off");
286 return BLUETOOTH_ERROR_INTERNAL;
289 *volume = absolute_volume;
294 int _bt_audio_is_avc_activated(bool *activated)
296 unsigned int mode = BT_AVC_OFF;
298 if (_bt_audio_get_avc_mode(&mode) != BLUETOOTH_ERROR_NONE)
299 BT_ERR("Fail to get the avc mode");
301 *activated = (mode == BT_AVC_OFF) ? false : true;
303 return BLUETOOTH_ERROR_NONE;
306 int _bt_audio_get_avc_mode(unsigned int *mode)
311 /* 1. Get AVC mode in the vconf value */
312 if (vconf_get_bool(VCONFKEY_BT_AVC_MODE, &state) != 0) {
313 BT_ERR("vconf_get_bool failed");
315 return BLUETOOTH_ERROR_INTERNAL;
318 if (state == VCONFKEY_BT_AVC_OFF) {
320 return BLUETOOTH_ERROR_NONE;
323 volume = __bt_audio_get_active_headset_volume();
327 return BLUETOOTH_ERROR_NONE;
330 BT_INFO("The current transport supports AVC : volume [%d]", volume);
335 BT_DBG("BT volume: %d", volume);
339 __bt_audio_sync_absolute_volume(volume);
341 return BLUETOOTH_ERROR_NONE;
344 /* 1. When a2dp headset is connected, we should set 'AVC' mode internaly */
345 /* 2. If the avc mode is changed, we should inform 'AVC' mode to pulseaudio */
346 /* 3. If BT is off, we should send 'AVC' off mode event for application */
347 /* 4. If BT A2DP is disconnected, we should send 'AVC' off mode event for application */
348 /* 5. When we recieve the volume changed, we shuld sync up the volume */