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"
33 /* Avoid the build error related to vconf.h's dependency */
34 #ifndef VCONFKEY_BT_AVC_MODE
35 #define VCONFKEY_BT_AVC_MODE "db/bluetooth/avc_mode"
38 #ifndef VCONFKEY_BT_AVC_OFF
39 #define VCONFKEY_BT_AVC_OFF false
42 #define ABSOLUTE_VOLUME_MAX 150
43 #define BT_VOLUME_MAX 127
45 static unsigned int absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
46 static unsigned int bt_volume = BT_VOLUME_MAX + 1;
47 static unsigned int avc_mode = BT_AVC_OFF;
49 static int __bt_audio_get_active_headset_volume(void)
51 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
52 gboolean connected = FALSE;
55 /* 1. Get active A2DP headset path */
57 /* We should modify this function to get the active headset in later */
58 connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
60 if (connected == FALSE) {
61 BT_DBG("There is no active A2DP headset");
65 /* 2. Get volume info for active transport for the path */
68 _bt_avrcp_transport_get_property(VOLUME, &volume)
74 static void __bt_audio_notify_avc_mode_changed(unsigned int avc_mode)
76 GVariant *param = g_variant_new("(u)", avc_mode);
78 _bt_send_event(BT_AUDIO_AVC_EVENT,
79 BLUETOOTH_EVENT_AUDIO_AVC_MODE_CHANGED,
83 static void __bt_audio_set_avc_mode(unsigned int mode)
85 unsigned int prev_mode = avc_mode;
87 if (prev_mode == mode) {
88 BT_DBG("No avc mode change");
92 BT_ERR("Previous mode [%d], New mode [%d]", prev_mode, mode);
94 __bt_audio_notify_avc_mode_changed(mode);
99 static void __bt_audio_set_user_avc_value(bool mode)
104 __bt_audio_set_avc_mode(BT_AVC_OFF);
108 volume = __bt_audio_get_active_headset_volume();
111 __bt_audio_set_avc_mode(BT_AVC_OFF);
115 BT_INFO("The current transport supports AVC : volume [%d]", volume);
118 __bt_audio_set_avc_mode(BT_AVC_NULL);
120 BT_DBG("BT volume: %d", volume);
121 __bt_audio_set_avc_mode(BT_AVC_MAX);
124 if (absolute_volume > ABSOLUTE_VOLUME_MAX || bt_volume > BT_VOLUME_MAX) {
125 BT_DBG("synchronize the system and bt volume");
127 /* Add Sync volumes */
131 static void __bt_audio_user_avc_mode_cb(keynode_t *node, void *data)
134 bool mode = VCONFKEY_BT_AVC_OFF;
136 DBG_SECURE("key=%s", vconf_keynode_get_name(node));
137 type = vconf_keynode_get_type(node);
139 if (type == VCONF_TYPE_BOOL) {
140 mode = vconf_keynode_get_bool(node);
141 __bt_audio_set_user_avc_value(mode);
143 BT_ERR("Invaild vconf key type : %d", type);
147 int _bt_audio_init_absolute_volume_control(void)
149 absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
150 bt_volume = BT_VOLUME_MAX + 1;
151 avc_mode = BT_AVC_OFF;
153 if (vconf_notify_key_changed(VCONFKEY_BT_AVC_MODE,
154 (vconf_callback_fn)__bt_audio_user_avc_mode_cb, NULL) < 0) {
155 BT_ERR("Unable to register key handler");
156 return BLUETOOTH_ERROR_INTERNAL;
159 return BLUETOOTH_ERROR_NONE;
162 void _bt_audio_deinit_absolute_volume_control(void)
164 absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
165 bt_volume = BT_VOLUME_MAX + 1;
166 avc_mode = BT_AVC_OFF;
168 vconf_ignore_key_changed(VCONFKEY_BT_AVC_MODE,
169 (vconf_callback_fn)__bt_audio_user_avc_mode_cb);
172 int _bt_audio_set_absolute_volume(unsigned int volume)
174 int result = BLUETOOTH_ERROR_NONE;
176 if (avc_mode == BT_AVC_OFF) {
177 BT_ERR("AVC mode is off");
178 return BLUETOOTH_ERROR_INTERNAL;
181 /* 1. Translate the absolute volume to bt volume */
183 /* Convert system gain to BT
184 BT volume range : 0 ~ 127
185 system volume range : 0 ~ 150 */
187 bt_volume = 127 * volume / 150;
190 system volume : 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
191 avrcp_ volume : 0 9 17 26 34 43 51 60 68 77 85 94 102 111 119 127 */
193 if (bt_volume > 0 && bt_volume < 127)
196 /* 2. Notify the bt_volume to transport (BT Headset) */
199 _bt_avrcp_transport_set_property(VOLUME, bt_volume)
202 /* 3. Notify the avc mode to the pulseaudio if it is needed */
204 __bt_audio_set_avc_mode(BT_AVC_NULL);
206 BT_DBG("BT volume: %d", volume);
207 __bt_audio_set_avc_mode(BT_AVC_MAX);
213 /* Just return the absolute_volume value */
214 int _bt_audio_get_absolute_volume(unsigned int *volume)
216 int result = BLUETOOTH_ERROR_NONE;
218 if (avc_mode == BT_AVC_OFF) {
219 BT_ERR("AVC mode is off");
220 return BLUETOOTH_ERROR_INTERNAL;
223 *volume = absolute_volume;
228 int _bt_audio_is_avc_activated(bool *activated)
230 unsigned int mode = BT_AVC_OFF;
232 if (_bt_audio_get_avc_mode(&mode) != BLUETOOTH_ERROR_NONE)
233 BT_ERR("Fail to get the avc mode");
235 *activated = (mode == BT_AVC_OFF) ? false : true;
237 return BLUETOOTH_ERROR_NONE;
240 int _bt_audio_get_avc_mode(unsigned int *mode)
245 /* 1. Get AVC mode in the vconf value */
246 if (vconf_get_bool(VCONFKEY_BT_AVC_MODE, &state) != 0) {
247 BT_ERR("vconf_get_bool failed");
249 return BLUETOOTH_ERROR_INTERNAL;
252 if (state == VCONFKEY_BT_AVC_OFF) {
254 return BLUETOOTH_ERROR_NONE;
257 volume = __bt_audio_get_active_headset_volume();
261 return BLUETOOTH_ERROR_NONE;
264 BT_INFO("The current transport supports AVC : volume [%d]", volume);
269 BT_DBG("BT volume: %d", volume);
273 if (absolute_volume > ABSOLUTE_VOLUME_MAX || bt_volume > BT_VOLUME_MAX) {
274 BT_DBG("synchronize the system and bt volume");
276 /* Add Sync volumes */
279 return BLUETOOTH_ERROR_NONE;
282 /* 1. When a2dp headset is connected, we should set 'AVC' mode internaly */
283 /* 2. If the avc mode is changed, we should inform 'AVC' mode to pulseaudio */
284 /* 3. If BT is off, we should send 'AVC' off mode event for application */
285 /* 4. If BT A2DP is disconnected, we should send 'AVC' off mode event for application */