%endif
%build
-export CFLAGS="%{optflags} -fno-strict-aliasing -DBLUETOOTH_APTX_SUPPORT -D__TIZEN__ -DTIZEN_BT_A2DP_MULTISTREAM -D__TIZEN_BT__ -D__TIZEN_LOG__ %{?asan:-ldl -fPIC }"
+export CFLAGS="%{optflags} -fno-strict-aliasing -DBLUETOOTH_APTX_SUPPORT -DTIZEN_BT_AVC_TARGET -D__TIZEN__ -DTIZEN_BT_A2DP_MULTISTREAM -D__TIZEN_BT__ -D__TIZEN_LOG__ %{?asan:-ldl -fPIC }"
%if 0%{?sec_build_binary_debug_enable}
export CFLAGS+=" -DTIZEN_DEBUG_ENABLE"
export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
#endif
+#ifdef TIZEN_BT_AVC_TARGET
+ } else if (dbus_message_is_signal(m, "org.projectx.bt_event", "AvcModeChanged")) {
+ pa_bluetooth_transport *t;
+ dbus_uint32_t mode = PA_BLUETOOTH_AVC_OFF;
+
+ if (!dbus_message_get_args(m, &err,
+ DBUS_TYPE_UINT32, &mode,
+ DBUS_TYPE_INVALID)) {
+ pa_log_error("Failed to parse org.projectx.bt_event.AvcModeChanged: %s", err.message);
+ goto fail;
+ }
+
+ if (!(t = pa_hashmap_first(y->transports)))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ pa_log_debug("Previous mode [%d], New mode [%d]", t->avc_mode, mode);
+
+ t->avc_mode = mode;
+
+ pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_AVC_MODE_CHANGED], t);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+#endif
}
fail:
pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to clear configuration"));
return r;
}
+
+#ifdef TIZEN_BT_AVC_TARGET
+int pa_bluetooth_transport_get_avc_mode(pa_bluetooth_transport *t, unsigned int *avc_mode)
+{
+ DBusMessage *m, *r;
+ DBusError err;
+ int ret = 0;
+ uint32_t mode = 0;
+
+ pa_assert(t);
+ pa_assert(t->device);
+ pa_assert(t->device->discovery);
+
+ pa_assert_se(m = dbus_message_new_method_call("org.projectx.bt", "/org/projectx/bt_service", "org.projectx.bt", "get_avc_mode"));
+
+ dbus_error_init(&err);
+
+ r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
+ dbus_message_unref(m);
+
+ m = NULL;
+ if (!r) {
+ dbus_error_free(&err);
+ return -1;
+ }
+
+ if (!dbus_message_get_args(r, &err, DBUS_TYPE_UINT32, &mode, DBUS_TYPE_INVALID)) {
+ pa_log_error("Failed to parse reply: %s", err.message);
+ dbus_error_free(&err);
+ ret = -1;
+ goto finish;
+ }
+
+ *avc_mode = mode;
+
+finish:
+ dbus_message_unref(r);
+ return ret;
+}
+#endif
#endif
static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
",arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'",
#ifdef __TIZEN_BT__
"type='signal',interface='org.bluez.ag_agent',member='SuspendMedia'",
+#ifdef TIZEN_BT_AVC_TARGET
+ "type='signal',interface='org.projectx.bt_event',member='AvcModeChanged',path='/org/projectx/bt/avc_mode'",
+#endif
#endif
NULL) < 0) {
pa_log_error("Failed to add D-Bus matches: %s", err.message);
"member='PropertiesChanged',arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'",
#ifdef __TIZEN_BT__
"type='signal',interface='org.bluez.ag_agent',member='SuspendMedia'",
+#ifdef TIZEN_BT_AVC_TARGET
+ "type='signal',interface='org.projectx.bt_event',member='AvcModeChanged',path='/org/projectx/bt/avc_mode'",
+#endif
#endif
NULL);
PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluetooth_transport */
#ifdef __TIZEN_BT__
PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED, /* Call data: pa_bluetooth_transport */
+ PA_BLUETOOTH_HOOK_AVC_MODE_CHANGED, /* Call data: pa_bluetooth_transport */
#endif
PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */
PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */
PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
} pa_bluetooth_transport_state_t;
+#ifdef TIZEN_BT_AVC_TARGET
+typedef enum pa_bluetooth_avc_mode {
+ PA_BLUETOOTH_AVC_OFF, /* Absolute Volume Control (AVC) : No */
+ PA_BLUETOOTH_AVC_NULL, /* Absolute Volume Control (AVC) : Volume 0 */
+ PA_BLUETOOTH_AVC_MAX /* Absolute Volume Control (AVC) : MAX Volume */
+} pa_bluetooth_avc_mode_t;
+#endif
+
typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu);
typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
typedef void (*pa_bluetooth_transport_destroy_cb)(pa_bluetooth_transport *t);
uint16_t microphone_gain;
uint16_t speaker_gain;
+#ifdef TIZEN_BT_AVC_TARGET
+ uint32_t avc_mode;
+#endif
+
pa_bluetooth_transport_state_t state;
pa_bluetooth_transport_acquire_cb acquire;
#ifdef __TIZEN_BT__
bool pa_bluetooth_device_sink_transport_connected(const pa_bluetooth_device *d);
bool pa_bluetooth_device_source_transport_connected(const pa_bluetooth_device *d);
+#ifdef TIZEN_BT_AVC_TARGET
+int pa_bluetooth_transport_get_avc_mode(pa_bluetooth_transport *t, unsigned int *mode);
+#endif
#endif
pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_discovery *y, const char *path);
pa_hook_slot *transport_state_changed_slot;
#ifdef __TIZEN_BT__
pa_hook_slot *sco_state_changed_slot;
+#ifdef TIZEN_BT_AVC_TARGET
+ pa_hook_slot *avc_mode_changed_slot;
+#endif
#endif
pa_hook_slot *transport_speaker_gain_changed_slot;
pa_hook_slot *transport_microphone_gain_changed_slot;
return -1;
}
+#ifdef TIZEN_BT_AVC_TARGET
+ if (u->transport) {
+ unsigned int avc_mode = PA_BLUETOOTH_AVC_OFF;
+
+ if (pa_bluetooth_transport_get_avc_mode(u->transport, &avc_mode) != 0)
+ pa_log_info("Fail to get the initial AVC mode");
+
+ u->transport->avc_mode = avc_mode;
+
+ pa_sink_set_avc_mode(u->sink, u->transport->avc_mode);
+ }
+#endif
+
u->sink->userdata = u;
u->sink->parent.process_msg = sink_process_msg;
return PA_HOOK_OK;
}
+
+#ifdef TIZEN_BT_AVC_TARGET
+static pa_hook_result_t avc_mode_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
+ pa_assert(t);
+ pa_assert(u);
+
+ if (t == u->transport && t->state <= PA_BLUETOOTH_TRANSPORT_STATE_IDLE)
+ return PA_HOOK_OK;
+
+ if (t->device == u->device)
+ pa_sink_set_avc_mode(u->sink, t->avc_mode);
+
+ return PA_HOOK_OK;
+}
+#endif
#endif
u->sco_state_changed_slot =
pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED),
PA_HOOK_NORMAL, (pa_hook_cb_t) sco_state_changed_cb, u);
+
+#ifdef TIZEN_BT_AVC_TARGET
+ u->avc_mode_changed_slot =
+ pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_AVC_MODE_CHANGED),
+ PA_HOOK_NORMAL, (pa_hook_cb_t) avc_mode_changed_cb, u);
+#endif
#endif
if (add_card(u) < 0)
#ifdef __TIZEN_BT__
if (u->sco_state_changed_slot)
pa_hook_slot_free(u->sco_state_changed_slot);
+ if (u->avc_mode_changed_slot)
+ pa_hook_slot_free(u->avc_mode_changed_slot);
#endif
if (u->transport_microphone_gain_changed_slot)
size_t ilength;
size_t ilength_full;
+#ifdef __TIZEN__
+ pa_sink_avc_mode_t avc_mode = PA_SINK_AVC_OFF;
+#endif
+
pa_sink_input_assert_ref(i);
pa_sink_input_assert_io_context(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.muted;
need_volume_factor_sink = !pa_cvolume_is_norm(&i->volume_factor_sink);
+#ifdef __TIZEN__
+ avc_mode = pa_sink_get_avc_mode(i->sink);
+#ifdef SINK_INPUT_DEBUG
+ pa_log("idx(%u), avc mode(%d), do(%d), norm(%d), nvfs(%d), muted(%d), resampler(%p)",
+ i->index, avc_mode,
+ do_volume_adj_here, volume_is_norm, need_volume_factor_sink,
+ i->thread_info.muted, i->thread_info.resampler);
+#endif
+#endif
+
while (!pa_memblockq_is_readable(i->thread_info.render_memblockq)) {
pa_memchunk tchunk;
wchunk.length = block_size_max_sink_input;
/* It might be necessary to adjust the volume here */
+#ifdef __TIZEN__
+ if (do_volume_adj_here && !volume_is_norm && avc_mode != PA_SINK_AVC_NORM) {
+#else
if (do_volume_adj_here && !volume_is_norm) {
+#endif
pa_memchunk_make_writable(&wchunk, 0);
+#ifdef __TIZEN__
+ if (i->thread_info.muted || avc_mode == PA_SINK_AVC_SILENT) {
+#else
if (i->thread_info.muted) {
+#endif
pa_silence_memchunk(&wchunk, &i->thread_info.sample_spec);
nvfs = false;
#ifdef TIZEN_VOLUME_RAMP
check_and_apply_silence(i);
-
prev_ramp_finished = i->thread_info.ramp.finished;
#endif
if (!i->thread_info.resampler) {
/* Let's see if we had to apply the volume adjustment ourselves,
* or if this can be done by the sink for us */
+#ifdef __TIZEN__
+ if (do_volume_adj_here || avc_mode == PA_SINK_AVC_NORM)
+#else
if (do_volume_adj_here)
+#endif
/* We had different channel maps, so we already did the adjustment */
pa_cvolume_reset(volume, i->sink->sample_spec.channels);
+#ifdef __TIZEN__
+ else if (i->thread_info.muted || avc_mode == PA_SINK_AVC_SILENT)
+#else
else if (i->thread_info.muted)
+#endif
/* We've both the same channel map, so let's have the sink do the adjustment for us*/
pa_cvolume_mute(volume, i->sink->sample_spec.channels);
else
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s);
}
+
+#ifdef __TIZEN__
+/* Called from the main thread. */
+void pa_sink_set_avc_mode(pa_sink *s, pa_sink_avc_mode_t mode) {
+ pa_proplist *pl = NULL;
+
+ pa_assert(s);
+
+ pl = pa_proplist_new();
+ pa_proplist_setf(pl, "device.avc_mode", "%d", mode);
+ pa_sink_update_proplist(s, PA_UPDATE_REPLACE, pl);
+ pa_proplist_free(pl);
+
+ pa_log_info("setting avc mode = %d", mode);
+
+ s->avc_mode = mode;
+}
+
+pa_sink_avc_mode_t pa_sink_get_avc_mode(pa_sink *s) {
+ pa_assert(s);
+
+ return s->avc_mode;
+}
+#endif
\ No newline at end of file
#define PA_MAX_INPUTS_PER_SINK 256
+#ifdef __TIZEN__
+typedef enum pa_sink_avc_mode {
+ PA_SINK_AVC_OFF,
+ PA_SINK_AVC_SILENT,
+ PA_SINK_AVC_NORM,
+} pa_sink_avc_mode_t;
+#endif
+
/* Returns true if sink is linked: registered and accessible from client side. */
static inline bool PA_SINK_IS_LINKED(pa_sink_state_t x) {
return x == PA_SINK_RUNNING || x == PA_SINK_IDLE || x == PA_SINK_SUSPENDED;
char *dump_path;
void *device_item;
bool use_internal_codec;
+ pa_sink_avc_mode_t avc_mode;
#endif
void *userdata;
};
* s->reference_volume and fires change notifications. */
void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume);
+
+#ifdef __TIZEN__
+void pa_sink_set_avc_mode(pa_sink *s, pa_sink_avc_mode_t mode);
+pa_sink_avc_mode_t pa_sink_get_avc_mode(pa_sink *s);
+#endif
+
/* Verify that we called in IO context (aka 'thread context), or that
* the sink is not yet set up, i.e. the thread not set up yet. See
* pa_assert_io_context() in thread-mq.h for more information. */