summaryrefslogtreecommitdiff
path: root/cras/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'cras/src/server')
-rw-r--r--cras/src/server/audio_thread.c11
-rw-r--r--cras/src/server/config/cras_board_config.c10
-rw-r--r--cras/src/server/config/cras_board_config.h1
-rw-r--r--cras/src/server/cras_a2dp_iodev.c4
-rw-r--r--cras/src/server/cras_alsa_helpers.c45
-rw-r--r--cras/src/server/cras_alsa_helpers.h5
-rw-r--r--cras/src/server/cras_alsa_io.c20
-rw-r--r--cras/src/server/cras_alsa_jack.c23
-rw-r--r--cras/src/server/cras_alsa_plugin_io.c17
-rw-r--r--cras/src/server/cras_alsa_ucm.c13
-rw-r--r--cras/src/server/cras_alsa_ucm.h8
-rw-r--r--cras/src/server/cras_apm_list.h2
-rw-r--r--cras/src/server/cras_bt_device.c98
-rw-r--r--cras/src/server/cras_bt_device.h7
-rw-r--r--cras/src/server/cras_bt_io.c2
-rw-r--r--cras/src/server/cras_control_rclient.c12
-rw-r--r--cras/src/server/cras_dbus_control.c115
-rw-r--r--cras/src/server/cras_dsp.c14
-rw-r--r--cras/src/server/cras_dsp.h6
-rw-r--r--cras/src/server/cras_dsp_ini.c23
-rw-r--r--cras/src/server/cras_dsp_ini.h4
-rw-r--r--cras/src/server/cras_empty_iodev.c2
-rw-r--r--cras/src/server/cras_fmt_conv.c100
-rw-r--r--cras/src/server/cras_fmt_conv_ops.c69
-rw-r--r--cras/src/server/cras_fmt_conv_ops.h5
-rw-r--r--cras/src/server/cras_hfp_ag_profile.c8
-rw-r--r--cras/src/server/cras_hfp_ag_profile.h3
-rw-r--r--cras/src/server/cras_hfp_alsa_iodev.c4
-rw-r--r--cras/src/server/cras_hfp_info.c28
-rw-r--r--cras/src/server/cras_hfp_info.h4
-rw-r--r--cras/src/server/cras_hfp_iodev.c2
-rw-r--r--cras/src/server/cras_hfp_slc.c19
-rw-r--r--cras/src/server/cras_iodev.c16
-rw-r--r--cras/src/server/cras_iodev.h4
-rw-r--r--cras/src/server/cras_iodev_list.c3
-rw-r--r--cras/src/server/cras_loopback_iodev.c2
-rw-r--r--cras/src/server/cras_observer.c38
-rw-r--r--cras/src/server/cras_observer.h4
-rw-r--r--cras/src/server/cras_rclient.c15
-rw-r--r--cras/src/server/cras_rclient.h4
-rw-r--r--cras/src/server/cras_rclient_util.c14
-rw-r--r--cras/src/server/cras_rclient_util.h29
-rw-r--r--cras/src/server/cras_rstream.c13
-rw-r--r--cras/src/server/cras_rstream.h3
-rw-r--r--cras/src/server/cras_server_metrics.c2
-rw-r--r--cras/src/server/cras_system_state.c32
-rw-r--r--cras/src/server/cras_system_state.h24
-rw-r--r--cras/src/server/dev_io.c24
-rw-r--r--cras/src/server/dev_stream.c10
-rw-r--r--cras/src/server/ewma_power.c81
-rw-r--r--cras/src/server/ewma_power.h65
-rw-r--r--cras/src/server/server_stream.c17
-rw-r--r--cras/src/server/server_stream.h4
-rw-r--r--cras/src/server/test_iodev.c2
54 files changed, 810 insertions, 280 deletions
diff --git a/cras/src/server/audio_thread.c b/cras/src/server/audio_thread.c
index df713ca5..cd155e82 100644
--- a/cras/src/server/audio_thread.c
+++ b/cras/src/server/audio_thread.c
@@ -555,8 +555,11 @@ static void append_stream_dump_info(struct audio_debug_info *info,
si->runtime_nsec = time_since.tv_nsec;
}
-/* Handle a message sent to the playback thread */
-static int handle_playback_thread_message(struct audio_thread *thread)
+/* Handle a message sent from main thread to the audio thread.
+ * Returns:
+ * Error code when reading or sending message fails.
+ */
+static int handle_audio_thread_message(struct audio_thread *thread)
{
uint8_t buf[256];
struct audio_thread_msg *msg = (struct audio_thread_msg *)buf;
@@ -711,7 +714,7 @@ static int handle_playback_thread_message(struct audio_thread *thread)
err = audio_thread_send_response(thread, ret);
if (err < 0)
return err;
- return ret;
+ return 0;
}
/* Returns the number of active streams plus the number of active devices. */
@@ -912,7 +915,7 @@ static void *audio_io_thread(void *arg)
continue;
if (thread->pollfds[0].revents & POLLIN) {
- rc = handle_playback_thread_message(thread);
+ rc = handle_audio_thread_message(thread);
if (rc < 0)
syslog(LOG_ERR, "handle message %d", rc);
}
diff --git a/cras/src/server/config/cras_board_config.c b/cras/src/server/config/cras_board_config.c
index d04d626b..14d3fa0c 100644
--- a/cras/src/server/config/cras_board_config.c
+++ b/cras/src/server/config/cras_board_config.c
@@ -13,12 +13,14 @@ static const int32_t DEFAULT_OUTPUT_BUFFER_SIZE = 512;
static const int32_t AEC_SUPPORTED_DEFAULT = 0;
static const int32_t AEC_GROUP_ID_DEFAULT = -1;
static const int32_t BLUETOOTH_WBS_ENABLED_INI_DEFAULT = 1;
+static const int32_t BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_DEFAULT = 0;
#define CONFIG_NAME "board.ini"
#define DEFAULT_OUTPUT_BUF_SIZE_INI_KEY "output:default_output_buffer_size"
#define AEC_SUPPORTED_INI_KEY "processing:aec_supported"
#define AEC_GROUP_ID_INI_KEY "processing:group_id"
#define BLUETOOTH_WBS_ENABLED_INI_KEY "bluetooth:wbs_enabled"
+#define BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_KEY "bluetooth:deprioritize_wbs_mic"
#define UCM_IGNORE_SUFFIX_KEY "ucm:ignore_suffix"
void cras_board_config_get(const char *config_path,
@@ -34,6 +36,8 @@ void cras_board_config_get(const char *config_path,
board_config->aec_group_id = AEC_GROUP_ID_DEFAULT;
board_config->ucm_ignore_suffix = NULL;
board_config->bt_wbs_enabled = BLUETOOTH_WBS_ENABLED_INI_DEFAULT;
+ board_config->deprioritize_bt_wbs_mic =
+ BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_DEFAULT;
if (config_path == NULL)
return;
@@ -66,6 +70,12 @@ void cras_board_config_get(const char *config_path,
board_config->bt_wbs_enabled = iniparser_getint(
ini, ini_key, BLUETOOTH_WBS_ENABLED_INI_DEFAULT);
+ snprintf(ini_key, MAX_INI_KEY_LENGTH,
+ BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_KEY);
+ ini_key[MAX_INI_KEY_LENGTH] = 0;
+ board_config->deprioritize_bt_wbs_mic = iniparser_getint(
+ ini, ini_key, BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_DEFAULT);
+
snprintf(ini_key, MAX_INI_KEY_LENGTH, UCM_IGNORE_SUFFIX_KEY);
ini_key[MAX_INI_KEY_LENGTH] = 0;
ptr = iniparser_getstring(ini, ini_key, "");
diff --git a/cras/src/server/config/cras_board_config.h b/cras/src/server/config/cras_board_config.h
index ed80bec5..2ecde265 100644
--- a/cras/src/server/config/cras_board_config.h
+++ b/cras/src/server/config/cras_board_config.h
@@ -13,6 +13,7 @@ struct cras_board_config {
int32_t aec_supported;
int32_t aec_group_id;
int32_t bt_wbs_enabled;
+ int32_t deprioritize_bt_wbs_mic;
char *ucm_ignore_suffix;
};
diff --git a/cras/src/server/cras_a2dp_iodev.c b/cras/src/server/cras_a2dp_iodev.c
index 683fa31f..6c434758 100644
--- a/cras/src/server/cras_a2dp_iodev.c
+++ b/cras/src/server/cras_a2dp_iodev.c
@@ -664,7 +664,7 @@ struct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
iodev->start = start;
iodev->frames_to_play_in_sleep = frames_to_play_in_sleep;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
strcpy(node->name, iodev->info.name);
@@ -684,6 +684,8 @@ struct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
iodev->info.max_supported_channels =
(a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2;
+ ewma_power_disable(&iodev->ewma);
+
return iodev;
error:
if (a2dpio) {
diff --git a/cras/src/server/cras_alsa_helpers.c b/cras/src/server/cras_alsa_helpers.c
index 4f402498..6cdc165a 100644
--- a/cras/src/server/cras_alsa_helpers.c
+++ b/cras/src/server/cras_alsa_helpers.c
@@ -556,7 +556,7 @@ int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format,
return 0;
}
-int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp)
+int cras_alsa_set_swparams(snd_pcm_t *handle)
{
int err;
snd_pcm_sw_params_t *swparams;
@@ -593,50 +593,7 @@ int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp)
return err;
}
- if (*enable_htimestamp) {
- /* Use MONOTONIC_RAW time-stamps. */
- err = snd_pcm_sw_params_set_tstamp_type(
- handle, swparams, SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_type: %s\n",
- snd_strerror(err));
- return err;
- }
- err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams,
- SND_PCM_TSTAMP_ENABLE);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_mode: %s\n",
- snd_strerror(err));
- return err;
- }
- }
-
- /* This hack is required because ALSA-LIB does not provide any way to
- * detect whether MONOTONIC_RAW timestamps are supported by the kernel.
- * In ALSA-LIB, the code checks the hardware protocol version. */
err = snd_pcm_sw_params(handle, swparams);
- if (err == -EINVAL && *enable_htimestamp) {
- *enable_htimestamp = 0;
- syslog(LOG_WARNING,
- "MONOTONIC_RAW timestamps are not supported.");
-
- err = snd_pcm_sw_params_set_tstamp_type(
- handle, swparams, SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_type: %s\n",
- snd_strerror(err));
- return err;
- }
- err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams,
- SND_PCM_TSTAMP_NONE);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_mode: %s\n",
- snd_strerror(err));
- return err;
- }
-
- err = snd_pcm_sw_params(handle, swparams);
- }
if (err < 0) {
syslog(LOG_ERR, "sw_params: %s\n", snd_strerror(err));
diff --git a/cras/src/server/cras_alsa_helpers.h b/cras/src/server/cras_alsa_helpers.h
index 38976749..01a42aea 100644
--- a/cras/src/server/cras_alsa_helpers.h
+++ b/cras/src/server/cras_alsa_helpers.h
@@ -135,13 +135,10 @@ int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format,
/* Sets up the swparams to alsa.
* Args:
* handle - The open PCM to configure.
- * enable_htimestamp - If non-zero, enable and configure hardware timestamps,
- * updated to reflect whether MONOTONIC RAW htimestamps
- * are supported by the kernel implementation.
* Returns:
* 0 on success, negative error on failure.
*/
-int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp);
+int cras_alsa_set_swparams(snd_pcm_t *handle);
/* Get the number of used frames in the alsa buffer.
*
diff --git a/cras/src/server/cras_alsa_io.c b/cras/src/server/cras_alsa_io.c
index 792305bb..da4ef630 100644
--- a/cras/src/server/cras_alsa_io.c
+++ b/cras/src/server/cras_alsa_io.c
@@ -113,7 +113,6 @@ struct alsa_input_node {
* is_first - true if this is the first iodev on the card.
* fully_specified - true if this device and it's nodes were fully specified.
* That is, don't automatically create nodes for it.
- * enable_htimestamp - True when the device's htimestamp is used.
* handle - Handle to the opened ALSA device.
* num_severe_underruns - Number of times we have run out of data badly.
Unlike num_underruns which records for the duration
@@ -148,7 +147,6 @@ struct alsa_io {
enum CRAS_ALSA_CARD_TYPE card_type;
int is_first;
int fully_specified;
- int enable_htimestamp;
snd_pcm_t *handle;
unsigned int num_severe_underruns;
snd_pcm_stream_t alsa_stream;
@@ -331,8 +329,7 @@ static int frames_queued(const struct cras_iodev *iodev,
aio->num_severe_underruns++;
return rc;
}
- if (!aio->enable_htimestamp)
- clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
+ clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
if (iodev->direction == CRAS_STREAM_INPUT)
return (int)frames;
@@ -374,7 +371,7 @@ static int close_dev(struct cras_iodev *iodev)
return 0;
}
-static int dummy_hotword_cb(void *arg, int revents)
+static int empty_hotword_cb(void *arg, int revents)
{
/* Only need this once. */
struct alsa_io *aio = (struct alsa_io *)arg;
@@ -449,7 +446,7 @@ static int configure_dev(struct cras_iodev *iodev)
return rc;
/* Configure software params. */
- rc = cras_alsa_set_swparams(aio->handle, &aio->enable_htimestamp);
+ rc = cras_alsa_set_swparams(aio->handle);
if (rc < 0)
return rc;
@@ -490,7 +487,7 @@ static int configure_dev(struct cras_iodev *iodev)
if (aio->poll_fd >= 0)
audio_thread_add_events_callback(
- aio->poll_fd, dummy_hotword_cb, aio, POLLIN);
+ aio->poll_fd, empty_hotword_cb, aio, POLLIN);
}
/* Capture starts right away, playback will wait for samples. */
@@ -1549,7 +1546,7 @@ static void jack_output_plug_event(const struct cras_alsa_jack *jack,
* For HDMI plug event cases, update max supported channels according
* to the current active node.
*/
- if (node->base.type == CRAS_NODE_TYPE_HDMI)
+ if (node->base.type == CRAS_NODE_TYPE_HDMI && plugged)
update_max_supported_channels(&aio->base);
}
@@ -2134,8 +2131,6 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index,
rc = ucm_get_min_buffer_level(ucm, &level);
if (!rc && direction == CRAS_STREAM_OUTPUT)
iodev->min_buffer_level = level;
-
- aio->enable_htimestamp = ucm_get_enable_htimestamp_flag(ucm);
}
set_iodev_name(iodev, card_name, dev_name, card_index, device_index,
@@ -2355,8 +2350,11 @@ void alsa_iodev_ucm_complete_init(struct cras_iodev *iodev)
set_default_hotword_model(iodev);
+ node = iodev->active_node;
+
/* Record max supported channels into cras_iodev_info. */
- update_max_supported_channels(iodev);
+ if (node && node->plugged)
+ update_max_supported_channels(iodev);
}
void alsa_iodev_destroy(struct cras_iodev *iodev)
diff --git a/cras/src/server/cras_alsa_jack.c b/cras/src/server/cras_alsa_jack.c
index 52a227e7..6d4d7bf5 100644
--- a/cras/src/server/cras_alsa_jack.c
+++ b/cras/src/server/cras_alsa_jack.c
@@ -734,6 +734,16 @@ static snd_hctl_elem_t *find_eld_control_by_dev_index(snd_hctl_t *hctl,
return snd_hctl_find_elem(hctl, elem_id);
}
+/* For non-gpio jack, check if it's of type hdmi/dp by
+ * matching jack name. */
+static int is_jack_hdmi_dp(const char *jack_name)
+{
+ // TODO(hychao): Use the information provided in UCM instead of
+ // name matching.
+ static const char *hdmi_dp = "HDMI";
+ return !!strstr(jack_name, hdmi_dp);
+}
+
/* Find GPIO jacks for this jack_list.
* Args:
* jack_list - Jack list to add to.
@@ -772,8 +782,9 @@ static int find_gpio_jacks(struct cras_alsa_jack_list *jack_list,
if (result_jack) {
*result_jack = data.result_jack;
- /* Find ELD control for HDMI/DP gpio jack. */
- if (*result_jack)
+ /* Find ELD control only for HDMI/DP gpio jack. */
+ if (*result_jack &&
+ is_jack_hdmi_dp((*result_jack)->gpio.device_name))
(*result_jack)->eld_control =
find_eld_control_by_dev_index(
jack_list->hctl,
@@ -833,14 +844,6 @@ static unsigned int hctl_jack_device_index(const char *name)
return (unsigned int)device_index;
}
-/* For non-gpio jack, check if it's of type hdmi/dp by
- * matching jack name. */
-static int is_jack_hdmi_dp(const char *jack_name)
-{
- static const char *hdmi_dp = "HDMI/DP";
- return strncmp(jack_name, hdmi_dp, strlen(hdmi_dp)) == 0;
-}
-
/* Checks if the given control name is in the supplied list of possible jack
* control base names. */
static int is_jack_control_in_list(const char *const *list,
diff --git a/cras/src/server/cras_alsa_plugin_io.c b/cras/src/server/cras_alsa_plugin_io.c
index 9c557a40..32c1ae11 100644
--- a/cras/src/server/cras_alsa_plugin_io.c
+++ b/cras/src/server/cras_alsa_plugin_io.c
@@ -24,9 +24,9 @@
#define PLUGIN_KEY_PCM "pcm"
#define PLUGIN_KEY_CARD "card"
-#define DUMMY_USB_VID 0x00
-#define DUMMY_USB_PID 0x00
-#define DUMMY_USB_SERIAL_NUMBER "serial-number-not-used"
+#define NULL_USB_VID 0x00
+#define NULL_USB_PID 0x00
+#define NULL_USB_SERIAL_NUMBER "serial-number-not-used"
struct hctl_poll_fd {
int fd;
@@ -159,12 +159,11 @@ void alsa_plugin_io_create(enum CRAS_STREAM_DIRECTION direction,
"section %s mixer_name %s",
section->name, section->mixer_name);
}
- plugin->iodev =
- alsa_iodev_create(0, card_name, 0, pcm_name, "", "",
- ALSA_CARD_TYPE_USB, 1, /* is first */
- plugin->mixer, NULL, plugin->ucm,
- plugin->hctl, direction, DUMMY_USB_VID,
- DUMMY_USB_PID, DUMMY_USB_SERIAL_NUMBER);
+ plugin->iodev = alsa_iodev_create(0, card_name, 0, pcm_name, "", "",
+ ALSA_CARD_TYPE_USB, 1, /* is first */
+ plugin->mixer, NULL, plugin->ucm,
+ plugin->hctl, direction, NULL_USB_VID,
+ NULL_USB_PID, NULL_USB_SERIAL_NUMBER);
DL_FOREACH (ucm_sections, section) {
if (section->dir != plugin->iodev->direction)
diff --git a/cras/src/server/cras_alsa_ucm.c b/cras/src/server/cras_alsa_ucm.c
index 3782cb24..9759a50f 100644
--- a/cras/src/server/cras_alsa_ucm.c
+++ b/cras/src/server/cras_alsa_ucm.c
@@ -57,7 +57,6 @@ static const char default_node_gain[] = "DefaultNodeGain";
static const char hotword_model_prefix[] = "Hotword Model";
static const char fully_specified_ucm_var[] = "FullySpecifiedUCM";
static const char main_volume_names[] = "MainVolumeNames";
-static const char enable_htimestamp_var[] = "EnableHtimestamp";
/* Use case verbs corresponding to CRAS_STREAM_TYPE. */
static const char *use_case_verbs[] = {
@@ -1121,15 +1120,3 @@ unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr *mgr,
return 0;
return value;
}
-
-unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr *mgr)
-{
- char *flag;
- int ret = 0;
- flag = ucm_get_flag(mgr, enable_htimestamp_var);
- if (!flag)
- return 0;
- ret = !strcmp(flag, "1");
- free(flag);
- return ret;
-}
diff --git a/cras/src/server/cras_alsa_ucm.h b/cras/src/server/cras_alsa_ucm.h
index 48dc6550..99a8b440 100644
--- a/cras/src/server/cras_alsa_ucm.h
+++ b/cras/src/server/cras_alsa_ucm.h
@@ -472,12 +472,4 @@ unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr *mgr,
*/
unsigned int ucm_get_optimize_no_stream_flag(struct cras_use_case_mgr *mgr);
-/* Retrieve the flag that enables use of htimestamp.
- * Args:
- * mgr - The cras_use_case_mgr pointer returned from alsa_ucm_create.
- * Returns:
- * 1 if the flag is enabled. 0 otherwise.
- */
-unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr *mgr);
-
#endif /* _CRAS_ALSA_UCM_H */
diff --git a/cras/src/server/cras_apm_list.h b/cras/src/server/cras_apm_list.h
index b9a7fe2f..7a36ceae 100644
--- a/cras/src/server/cras_apm_list.h
+++ b/cras/src/server/cras_apm_list.h
@@ -162,7 +162,7 @@ void cras_apm_list_set_aec_dump(struct cras_apm_list *list, void *dev_ptr,
/*
* If webrtc audio processing library is not available then define all
- * cras_apm_list functions as dummy. As long as cras_apm_list_add returns
+ * cras_apm_list functions as empty. As long as cras_apm_list_add returns
* NULL, non of the other functions should be called.
*/
static inline int cras_apm_list_init(const char *device_config_dir)
diff --git a/cras/src/server/cras_bt_device.c b/cras/src/server/cras_bt_device.c
index 0607ac8e..70c87479 100644
--- a/cras/src/server/cras_bt_device.c
+++ b/cras/src/server/cras_bt_device.c
@@ -61,9 +61,7 @@ static const unsigned int CONN_WATCH_MAX_RETRIES = 30;
static const unsigned int SCO_SUSPEND_DELAY_MS = 5000;
static const unsigned int CRAS_SUPPORTED_PROFILES =
- CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
- CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE |
- CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY;
+ CRAS_BT_DEVICE_PROFILE_A2DP_SINK | CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE;
/* Object to represent a general bluetooth device, and used to
* associate with some CRAS modules if it supports audio.
@@ -79,6 +77,8 @@ static const unsigned int CRAS_SUPPORTED_PROFILES =
* connected - If this devices is connected.
* connected_profiles - OR'ed all connected audio profiles.
* profiles - OR'ed by all audio profiles this device supports.
+ * hidden_profiles - OR'ed by all audio profiles this device actually
+ * supports but is not scanned by BlueZ.
* bt_iodevs - The pointer to the cras_iodevs of this device.
* active_profile - The flag to indicate the active audio profile this
* device is currently using.
@@ -102,8 +102,9 @@ struct cras_bt_device {
int paired;
int trusted;
int connected;
- enum cras_bt_device_profile connected_profiles;
- enum cras_bt_device_profile profiles;
+ unsigned int connected_profiles;
+ unsigned int profiles;
+ unsigned int hidden_profiles;
struct cras_iodev *bt_iodevs[CRAS_NUM_DIRECTIONS];
unsigned int active_profile;
int use_hardware_volume;
@@ -512,14 +513,18 @@ int cras_bt_device_audio_gateway_initialized(struct cras_bt_device *device)
* behavior on qualification test software. */
if (!cras_bt_device_supports_profile(
device, CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE)) {
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ unsigned int profiles =
+ device->profiles | CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE;
+ cras_bt_device_set_supported_profiles(device, profiles);
+ device->hidden_profiles |= CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE;
bt_device_conn_watch_cb(NULL, (void *)device);
}
return 0;
}
-int cras_bt_device_get_active_profile(const struct cras_bt_device *device)
+unsigned int
+cras_bt_device_get_active_profile(const struct cras_bt_device *device)
{
return device->active_profile;
}
@@ -569,6 +574,19 @@ static void cras_bt_device_log_profile(const struct cras_bt_device *device,
}
}
+static void cras_bt_device_log_profiles(const struct cras_bt_device *device,
+ unsigned int profiles)
+{
+ unsigned int profile;
+
+ while (profiles) {
+ /* Get the LSB of profiles */
+ profile = profiles & -profiles;
+ cras_bt_device_log_profile(device, profile);
+ profiles ^= profile;
+ }
+}
+
static int
cras_bt_device_is_profile_connected(const struct cras_bt_device *device,
enum cras_bt_device_profile profile)
@@ -708,7 +726,7 @@ void cras_bt_device_set_connected(struct cras_bt_device *device, int value)
void cras_bt_device_notify_profile_dropped(struct cras_bt_device *device,
enum cras_bt_device_profile profile)
{
- device->connected_profiles &= !profile;
+ device->connected_profiles &= ~profile;
/* Do nothing if device already disconnected. */
if (!device->connected)
@@ -723,37 +741,33 @@ void cras_bt_device_notify_profile_dropped(struct cras_bt_device *device,
UNEXPECTED_PROFILE_DROP);
}
-/*
- * Check if the uuid is of a new audio profile that isn't listed
- * as supported by device.
+/* Refresh the list of known supported profiles.
* Args:
- * device - The BT device holding supported profiles bitmap.
- * uuid - UUID string from the device properties notified by BlueZ.
+ * device - The BT device holding scanned profiles bitmap.
+ * profiles - The OR'ed profiles the device claims to support as is notified
+ * by BlueZ.
* Returns:
- * True if uuid is a new audio profiles not already supported by device.
+ * The OR'ed profiles that are both supported by Cras and isn't previously
+ * supported by the device.
*/
-int cras_bt_device_add_supported_profiles(struct cras_bt_device *device,
- const char *uuid)
+int cras_bt_device_set_supported_profiles(struct cras_bt_device *device,
+ unsigned int profiles)
{
- enum cras_bt_device_profile profile =
- cras_bt_device_profile_from_uuid(uuid);
-
- if (profile == 0)
+ /* Do nothing if no new profiles. */
+ if ((device->profiles & profiles) == profiles)
return 0;
- /* Do nothing if this profile is not new. */
- if (device->profiles & profile)
- return 0;
+ unsigned int new_profiles = profiles & ~device->profiles;
/* Log this event as we might need to re-intialize the BT audio nodes
* if new audio profile is reported for already connected device. */
- if (device->connected && (profile & CRAS_SUPPORTED_PROFILES))
+ if (device->connected && (new_profiles & CRAS_SUPPORTED_PROFILES))
BTLOG(btlog, BT_NEW_AUDIO_PROFILE_AFTER_CONNECT,
- device->profiles, profile);
- device->profiles |= profile;
- cras_bt_device_log_profile(device, profile);
+ device->profiles, new_profiles);
+ cras_bt_device_log_profiles(device, new_profiles);
+ device->profiles = profiles | device->hidden_profiles;
- return (profile & CRAS_SUPPORTED_PROFILES);
+ return (new_profiles & CRAS_SUPPORTED_PROFILES);
}
void cras_bt_device_update_properties(struct cras_bt_device *device,
@@ -821,6 +835,7 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
"as") == 0 &&
strcmp(key, "UUIDs") == 0) {
DBusMessageIter uuid_array_iter;
+ unsigned int profiles = 0;
dbus_message_iter_recurse(&variant_iter,
&uuid_array_iter);
@@ -830,22 +845,21 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
dbus_message_iter_get_basic(&uuid_array_iter,
&uuid);
-
- /*
- * If updated properties includes new audio
- * profile, and device is connected, we need
- * to start connection watcher. This is needed
- * because on some bluetooth device, supported
- * profiles do not present when device
- * interface is added and they are updated
- * later.
- */
- if (cras_bt_device_add_supported_profiles(
- device, uuid))
- watch_needed = device->connected;
+ profiles |=
+ cras_bt_device_profile_from_uuid(uuid);
dbus_message_iter_next(&uuid_array_iter);
}
+
+ /* If updated properties includes new audio profile and
+ * device is connected, we need to start connection
+ * watcher. This is needed because on some bluetooth
+ * devices, supported profiles do not present when
+ * device interface is added and they are updated later.
+ */
+ if (cras_bt_device_set_supported_profiles(device,
+ profiles))
+ watch_needed = device->connected;
}
dbus_message_iter_next(properties_array_iter);
@@ -876,7 +890,7 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
} else if (strcmp(key, "Connected") == 0) {
device->connected = 0;
} else if (strcmp(key, "UUIDs") == 0) {
- device->profiles = 0;
+ device->profiles = device->hidden_profiles;
}
dbus_message_iter_next(invalidated_array_iter);
diff --git a/cras/src/server/cras_bt_device.h b/cras/src/server/cras_bt_device.h
index 3800927e..4202bc93 100644
--- a/cras/src/server/cras_bt_device.h
+++ b/cras/src/server/cras_bt_device.h
@@ -63,8 +63,8 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
DBusMessageIter *invalidated_array_iter);
/* Updates the supported profiles on dev. Expose for unit test. */
-int cras_bt_device_add_supported_profiles(struct cras_bt_device *device,
- const char *uuid);
+int cras_bt_device_set_supported_profiles(struct cras_bt_device *device,
+ unsigned int profiles);
/* Checks if profile is claimed supported by the device. */
int cras_bt_device_supports_profile(const struct cras_bt_device *device,
@@ -133,7 +133,8 @@ void cras_bt_device_rm_iodev(struct cras_bt_device *device,
struct cras_iodev *iodev);
/* Gets the active profile of the bt device. */
-int cras_bt_device_get_active_profile(const struct cras_bt_device *device);
+unsigned int
+cras_bt_device_get_active_profile(const struct cras_bt_device *device);
/* Sets the active profile of the bt device. */
void cras_bt_device_set_active_profile(struct cras_bt_device *device,
diff --git a/cras/src/server/cras_bt_io.c b/cras/src/server/cras_bt_io.c
index 3cffe148..9f5c2f79 100644
--- a/cras/src/server/cras_bt_io.c
+++ b/cras/src/server/cras_bt_io.c
@@ -518,7 +518,7 @@ struct cras_iodev *cras_bt_io_create(struct cras_bt_device *device,
iodev->set_volume = set_bt_volume;
}
- /* Create the dummy node so it's the only node exposed to UI, and
+ /* Create the fake node so it's the only node exposed to UI, and
* point it to the first profile dev. */
active = (struct bt_node *)calloc(1, sizeof(*active));
if (!active)
diff --git a/cras/src/server/cras_control_rclient.c b/cras/src/server/cras_control_rclient.c
index 3906a23b..cd0c4d3b 100644
--- a/cras/src/server/cras_control_rclient.c
+++ b/cras/src/server/cras_control_rclient.c
@@ -15,6 +15,7 @@
#include "cras_dsp.h"
#include "cras_iodev.h"
#include "cras_iodev_list.h"
+#include "cras_hfp_ag_profile.h"
#include "cras_main_thread_log.h"
#include "cras_messages.h"
#include "cras_observer.h"
@@ -298,15 +299,11 @@ static int ccr_handle_message_from_client(struct cras_rclient *client,
switch (msg->id) {
case CRAS_SERVER_CONNECT_STREAM: {
int client_shm_fd = num_fds > 1 ? fds[1] : -1;
- struct cras_connect_message cmsg;
if (MSG_LEN_VALID(msg, struct cras_connect_message)) {
rclient_handle_client_stream_connect(
client,
(const struct cras_connect_message *)msg, fd,
client_shm_fd);
- } else if (!convert_connect_message_old(msg, &cmsg)) {
- rclient_handle_client_stream_connect(client, &cmsg, fd,
- client_shm_fd);
} else {
return -EINVAL;
}
@@ -422,10 +419,15 @@ static int ccr_handle_message_from_client(struct cras_rclient *client,
state = cras_system_state_get_no_lock();
#ifdef CRAS_DBUS
memcpy(&state->bt_debug_info.bt_log, btlog,
- sizeof(struct cras_bt_debug_info));
+ sizeof(struct cras_bt_event_log));
+ memcpy(&state->bt_debug_info.wbs_logger,
+ cras_hfp_ag_get_wbs_logger(),
+ sizeof(struct packet_status_logger));
#else
memset(&state->bt_debug_info.bt_log, 0,
sizeof(struct cras_bt_debug_info));
+ memset(&state->bt_debug_info.wbs_logger, 0,
+ sizeof(struct packet_status_logger));
#endif
cras_fill_client_audio_debug_info_ready(&msg);
diff --git a/cras/src/server/cras_dbus_control.c b/cras/src/server/cras_dbus_control.c
index 628ec221..3479c3c6 100644
--- a/cras/src/server/cras_dbus_control.c
+++ b/cras/src/server/cras_dbus_control.c
@@ -75,6 +75,9 @@
" <method name=\"GetSystemAecGroupId\">\n" \
" <arg name=\"group_id\" type=\"i\" direction=\"out\"/>\n" \
" </method>\n" \
+ " <method name=\"GetDeprioritizeBtWbsMic\">\n" \
+ " <arg name=\"deprioritized\" type=\"b\" direction=\"out\"/>\n" \
+ " </method>\n" \
" <method name=\"SetActiveOutputNode\">\n" \
" <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n" \
" </method>\n" \
@@ -105,6 +108,9 @@
" <method name=\"GetNumberOfActiveInputStreams\">\n" \
" <arg name=\"num\" type=\"i\" direction=\"out\"/>\n" \
" </method>\n" \
+ " <method name=\"GetNumberOfInputStreamsWithPermission\">\n" \
+ " <arg name=\"num\" type=\"a{sv}\" direction=\"out\"/>\n" \
+ " </method>\n" \
" <method name=\"SetGlobalOutputChannelRemix\">\n" \
" <arg name=\"num_channels\" type=\"i\" direction=\"in\"/>\n" \
" <arg name=\"coefficient\" type=\"ad\" direction=\"in\"/>\n" \
@@ -671,6 +677,27 @@ static DBusHandlerResult handle_get_system_aec_group_id(DBusConnection *conn,
}
static DBusHandlerResult
+handle_get_deprioritize_bt_wbs_mic(DBusConnection *conn, DBusMessage *message,
+ void *arg)
+{
+ DBusMessage *reply;
+ dbus_uint32_t serial = 0;
+ dbus_bool_t deprioritized;
+
+ reply = dbus_message_new_method_return(message);
+
+ deprioritized = cras_system_get_deprioritize_bt_wbs_mic();
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &deprioritized,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(conn, reply, &serial);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
handle_set_active_node(DBusConnection *conn, DBusMessage *message, void *arg,
enum CRAS_STREAM_DIRECTION direction)
{
@@ -784,6 +811,65 @@ handle_get_num_active_streams_use_output_hw(DBusConnection *conn,
return DBUS_HANDLER_RESULT_HANDLED;
}
+static bool append_num_input_streams_with_permission(
+ DBusMessage *message, uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ unsigned type;
+
+ dbus_message_iter_init_append(message, &array);
+ for (type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type) {
+ const char *client_type_str = cras_client_type_str(type);
+ if (!is_utf8_string(client_type_str)) {
+ syslog(LOG_ERR,
+ "Non-utf8 clinet_type_str '%s' cannot be sent "
+ "via dbus",
+ client_type_str);
+ client_type_str = "";
+ }
+
+ if (!dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
+ "{sv}", &dict))
+ return false;
+ if (!append_key_value(&dict, "ClientType", DBUS_TYPE_STRING,
+ DBUS_TYPE_STRING_AS_STRING,
+ &client_type_str))
+ return false;
+ if (!append_key_value(&dict, "NumStreamsWithPermission",
+ DBUS_TYPE_UINT32,
+ DBUS_TYPE_UINT32_AS_STRING,
+ &num_input_streams[type]))
+ return false;
+ if (!dbus_message_iter_close_container(&array, &dict))
+ return false;
+ }
+ return true;
+}
+
+static DBusHandlerResult
+handle_get_num_input_streams_with_permission(DBusConnection *conn,
+ DBusMessage *message, void *arg)
+{
+ DBusMessage *reply;
+ dbus_uint32_t serial = 0;
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE] = {};
+
+ reply = dbus_message_new_method_return(message);
+
+ cras_system_state_get_input_streams_with_permission(num_input_streams);
+ if (!append_num_input_streams_with_permission(reply, num_input_streams))
+ goto error;
+
+ dbus_connection_send(conn, reply, &serial);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+error:
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
static DBusHandlerResult
handle_set_global_output_channel_remix(DBusConnection *conn,
DBusMessage *message, void *arg)
@@ -1052,6 +1138,9 @@ static DBusHandlerResult handle_control_message(DBusConnection *conn,
"GetSystemAecGroupId")) {
return handle_get_system_aec_group_id(conn, message, arg);
} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
+ "GetDeprioritizeBtWbsMic")) {
+ return handle_get_deprioritize_bt_wbs_mic(conn, message, arg);
+ } else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
"SetActiveOutputNode")) {
return handle_set_active_node(conn, message, arg,
CRAS_STREAM_OUTPUT);
@@ -1088,6 +1177,11 @@ static DBusHandlerResult handle_control_message(DBusConnection *conn,
arg);
} else if (dbus_message_is_method_call(
message, CRAS_CONTROL_INTERFACE,
+ "GetNumberOfInputStreamsWithPermission")) {
+ return handle_get_num_input_streams_with_permission(
+ conn, message, arg);
+ } else if (dbus_message_is_method_call(
+ message, CRAS_CONTROL_INTERFACE,
"GetNumberOfActiveOutputStreams")) {
return handle_get_num_active_streams_use_output_hw(
conn, message, arg);
@@ -1315,6 +1409,25 @@ static void signal_num_active_streams_changed(void *context,
dbus_message_unref(msg);
}
+static void signal_num_input_streams_with_permission_changed(
+ void *context, uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ struct cras_dbus_control *control = (struct cras_dbus_control *)context;
+ dbus_uint32_t serial = 0;
+ DBusMessage *msg;
+
+ msg = create_dbus_message("NumberOfInputStreamsWithPermissionChanged");
+ if (!msg)
+ return;
+
+ if (!append_num_input_streams_with_permission(msg, num_input_streams))
+ goto error;
+
+ dbus_connection_send(control->conn, msg, &serial);
+error:
+ dbus_message_unref(msg);
+}
+
static void signal_hotword_triggered(void *context, int64_t tv_sec,
int64_t tv_nsec)
{
@@ -1399,6 +1512,8 @@ void cras_dbus_control_start(DBusConnection *conn)
observer_ops.capture_mute_changed = signal_capture_mute;
observer_ops.num_active_streams_changed =
signal_num_active_streams_changed;
+ observer_ops.num_input_streams_with_permission_changed =
+ signal_num_input_streams_with_permission_changed;
observer_ops.nodes_changed = signal_nodes_changed;
observer_ops.active_node_changed = signal_active_node_changed;
observer_ops.input_node_gain_changed = signal_node_capture_gain_changed;
diff --git a/cras/src/server/cras_dsp.c b/cras/src/server/cras_dsp.c
index d0b26264..9c4cc7b5 100644
--- a/cras/src/server/cras_dsp.c
+++ b/cras/src/server/cras_dsp.c
@@ -208,15 +208,15 @@ void cras_dsp_load_pipeline(struct cras_dsp_context *ctx)
cmd_load_pipeline(ctx, global_ini);
}
-void cras_dsp_load_dummy_pipeline(struct cras_dsp_context *ctx,
- unsigned int num_channels)
+void cras_dsp_load_mock_pipeline(struct cras_dsp_context *ctx,
+ unsigned int num_channels)
{
- struct ini *dummy_ini;
- dummy_ini = create_dummy_ini(ctx->purpose, num_channels);
- if (dummy_ini == NULL)
- syslog(LOG_ERR, "Failed to create dummy ini");
+ struct ini *mock_ini;
+ mock_ini = create_mock_ini(ctx->purpose, num_channels);
+ if (mock_ini == NULL)
+ syslog(LOG_ERR, "Failed to create mock ini");
else
- cmd_load_pipeline(ctx, dummy_ini);
+ cmd_load_pipeline(ctx, mock_ini);
}
struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx)
diff --git a/cras/src/server/cras_dsp.h b/cras/src/server/cras_dsp.h
index 9a72f42b..366e2e67 100644
--- a/cras/src/server/cras_dsp.h
+++ b/cras/src/server/cras_dsp.h
@@ -54,11 +54,11 @@ void cras_dsp_set_variable_boolean(struct cras_dsp_context *ctx,
* blocking the audio thread. */
void cras_dsp_load_pipeline(struct cras_dsp_context *ctx);
-/* Loads a dummy pipeline of source directly connects to sink, of given
+/* Loads a mock pipeline of source directly connects to sink, of given
* number of channels.
*/
-void cras_dsp_load_dummy_pipeline(struct cras_dsp_context *ctx,
- unsigned int num_channels);
+void cras_dsp_load_mock_pipeline(struct cras_dsp_context *ctx,
+ unsigned int num_channels);
/* Locks the pipeline in the context for access. Returns NULL if the
* pipeline is still being loaded or cannot be loaded. */
diff --git a/cras/src/server/cras_dsp_ini.c b/cras/src/server/cras_dsp_ini.c
index 0b844d16..a331acf8 100644
--- a/cras/src/server/cras_dsp_ini.c
+++ b/cras/src/server/cras_dsp_ini.c
@@ -11,7 +11,7 @@
#define MAX_NR_PORT 128 /* the max number of ports for a plugin */
#define MAX_PORT_NAME_LENGTH 20 /* names like "output_32" */
-#define MAX_DUMMY_INI_CH 20 /* Max number of channels to create dummy ini */
+#define MAX_MOCK_INI_CH 20 /* Max number of channels to create mock ini */
/* Format of the ini file (See dsp.ini.sample for an example).
@@ -305,22 +305,21 @@ static int insert_swap_lr_plugin(struct ini *ini)
return 0;
}
-struct ini *create_dummy_ini(const char *purpose, unsigned int num_channels)
+struct ini *create_mock_ini(const char *purpose, unsigned int num_channels)
{
- static char dummy_flow_names[MAX_DUMMY_INI_CH][9] = {
- "{tmp:0}", "{tmp:1}", "{tmp:2}", "{tmp:3}",
- "{tmp:4}", "{tmp:5}", "{tmp:6}", "{tmp:7}",
- "{tmp:8}", "{tmp:9}", "{tmp:10}", "{tmp:11}",
- "{tmp:12}", "{tmp:13}", "{tmp:14}", "{tmp:15}",
- "{tmp:16}", "{tmp:17}", "{tmp:18}", "{tmp:19}",
+ static char mock_flow_names[MAX_MOCK_INI_CH][9] = {
+ "{tmp:0}", "{tmp:1}", "{tmp:2}", "{tmp:3}", "{tmp:4}",
+ "{tmp:5}", "{tmp:6}", "{tmp:7}", "{tmp:8}", "{tmp:9}",
+ "{tmp:10}", "{tmp:11}", "{tmp:12}", "{tmp:13}", "{tmp:14}",
+ "{tmp:15}", "{tmp:16}", "{tmp:17}", "{tmp:18}", "{tmp:19}",
};
struct ini *ini;
struct plugin *source, *sink;
- int tmp_flow_ids[MAX_DUMMY_INI_CH];
+ int tmp_flow_ids[MAX_MOCK_INI_CH];
int i;
- if (num_channels > MAX_DUMMY_INI_CH) {
- syslog(LOG_ERR, "Unable to create %u channels of dummy ini",
+ if (num_channels > MAX_MOCK_INI_CH) {
+ syslog(LOG_ERR, "Unable to create %u channels of mock ini",
num_channels);
return NULL;
}
@@ -332,7 +331,7 @@ struct ini *create_dummy_ini(const char *purpose, unsigned int num_channels)
}
for (i = 0; i < num_channels; i++)
- tmp_flow_ids[i] = add_new_flow(ini, dummy_flow_names[i]);
+ tmp_flow_ids[i] = add_new_flow(ini, mock_flow_names[i]);
source = ARRAY_APPEND_ZERO(&ini->plugins);
source->title = "source";
diff --git a/cras/src/server/cras_dsp_ini.h b/cras/src/server/cras_dsp_ini.h
index 51deefd6..c839d4b0 100644
--- a/cras/src/server/cras_dsp_ini.h
+++ b/cras/src/server/cras_dsp_ini.h
@@ -71,7 +71,7 @@ struct ini {
};
/*
- * Creates a dummy ini structure equivalent to:
+ * Creates a mock ini structure equivalent to:
*
* [src]
* out0={tmp:0}
@@ -86,7 +86,7 @@ struct ini {
* The caller of this function is responsible to free the returned
* ini by calling cras_dsp_ini_free().
*/
-struct ini *create_dummy_ini(const char *purpose, unsigned int num_channels);
+struct ini *create_mock_ini(const char *purpose, unsigned int num_channels);
/* Reads the ini file into the ini structure */
struct ini *cras_dsp_ini_create(const char *ini_filename);
diff --git a/cras/src/server/cras_empty_iodev.c b/cras/src/server/cras_empty_iodev.c
index 76eab6c1..3471c756 100644
--- a/cras/src/server/cras_empty_iodev.c
+++ b/cras/src/server/cras_empty_iodev.c
@@ -199,7 +199,7 @@ struct cras_iodev *empty_iodev_create(enum CRAS_STREAM_DIRECTION direction,
iodev->update_active_node = update_active_node;
iodev->no_stream = cras_iodev_default_no_stream_playback;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
node->type = node_type;
diff --git a/cras/src/server/cras_fmt_conv.c b/cras/src/server/cras_fmt_conv.c
index 478452d4..509db1eb 100644
--- a/cras/src/server/cras_fmt_conv.c
+++ b/cras/src/server/cras_fmt_conv.c
@@ -9,6 +9,7 @@
#include <syslog.h>
#include <endian.h>
#include <limits.h>
+#include <math.h>
#include "cras_fmt_conv.h"
#include "cras_fmt_conv_ops.h"
@@ -58,21 +59,35 @@ static int is_channel_layout_equal(const struct cras_audio_format *a,
return 1;
}
-static void normalize_buf(float *buf, size_t size)
+/*
+ * Calculates the normalize_factor abs_sum(ci) from given coefficients.
+ * Since sum(ci / abs_sum(ci)) <= 1, this could prevent sample overflow while
+ * upmixing or downmixing.
+ */
+static float normalize_factor(float *buf, size_t n)
{
int i;
- float squre_sum = 0.0;
- for (i = 0; i < size; i++)
- squre_sum += buf[i] * buf[i];
+ float abs_sum = 0.0;
+ for (i = 0; i < n; i++)
+ abs_sum += fabs(buf[i]);
- if (squre_sum == 0.0)
- return;
+ return 1.0 / abs_sum;
+}
- for (i = 0; i < size; i++)
- buf[i] /= squre_sum;
+/*
+ * Normalize all channels with the same factor to maintain
+ * the energy ratio between original channels.
+ */
+static void normalize(float **mtx, size_t m, size_t n, float factor)
+{
+ int i, j;
+ for (i = 0; i < m; i++)
+ for (j = 0; j < n; j++)
+ mtx[i][j] *= factor;
}
-/* Populates the down mix matrix by rules:
+/*
+ * Populates the down mix matrix by rules:
* 1. Front/side left(right) channel will mix to left(right) of
* full scale.
* 2. Center and LFE will be split equally to left and right.
@@ -106,9 +121,46 @@ static void surround51_to_stereo_downmix_mtx(float **mtx,
mtx[STEREO_L][layout[CRAS_CH_LFE]] = 0.707;
mtx[STEREO_R][layout[CRAS_CH_LFE]] = 0.707;
}
+ normalize(mtx, 2, 6, normalize_factor(mtx[STEREO_L], 6));
+}
+
+/* Populates the down mix matrix by rules:
+ * 1. Front left(right) channel will mix to the front left(right) of
+ * full scale.
+ * 2. Rear and side left(right) channel will mix to the rear left(right) of
+ * full scale.
+ * 3. Center will be split equally to the front left and right.
+ * 4. LFE will be split equally to the other channels.
+ */
+static void surround51_to_quad_downmix_mtx(float **mtx,
+ int8_t layout[CRAS_CH_MAX])
+{
+ if (layout[CRAS_CH_FL] != -1 && layout[CRAS_CH_FR] != -1) {
+ mtx[CRAS_CH_FL][layout[CRAS_CH_FL]] = 1.0;
+ mtx[CRAS_CH_FR][layout[CRAS_CH_FR]] = 1.0;
+ }
+ if (layout[CRAS_CH_RL] != -1 && layout[CRAS_CH_RR] != -1) {
+ mtx[CRAS_CH_RL][layout[CRAS_CH_RL]] = 1.0;
+ mtx[CRAS_CH_RR][layout[CRAS_CH_RR]] = 1.0;
+ }
+ if (layout[CRAS_CH_SL] != -1 && layout[CRAS_CH_SR] != -1) {
+ mtx[CRAS_CH_RL][layout[CRAS_CH_SL]] = 1.0;
+ mtx[CRAS_CH_RR][layout[CRAS_CH_SR]] = 1.0;
+ }
+ if (layout[CRAS_CH_FC] != -1) {
+ /* Split 1/2 power to the front L/R */
+ mtx[CRAS_CH_FL][layout[CRAS_CH_FC]] = 0.707;
+ mtx[CRAS_CH_FR][layout[CRAS_CH_FC]] = 0.707;
+ }
+ if (layout[CRAS_CH_LFE] != -1) {
+ /* Split 1/4 power to the other channel */
+ mtx[CRAS_CH_FL][layout[CRAS_CH_LFE]] = 0.5;
+ mtx[CRAS_CH_FR][layout[CRAS_CH_LFE]] = 0.5;
+ mtx[CRAS_CH_RL][layout[CRAS_CH_LFE]] = 0.5;
+ mtx[CRAS_CH_RR][layout[CRAS_CH_LFE]] = 0.5;
+ }
- normalize_buf(mtx[STEREO_L], 6);
- normalize_buf(mtx[STEREO_R], 6);
+ normalize(mtx, 4, 6, normalize_factor(mtx[CRAS_CH_FL], 6));
}
static int is_supported_format(const struct cras_audio_format *fmt)
@@ -170,6 +222,12 @@ static size_t _51_to_stereo(struct cras_fmt_conv *conv, const uint8_t *in,
return s16_51_to_stereo(in, in_frames, out);
}
+static size_t _51_to_quad(struct cras_fmt_conv *conv, const uint8_t *in,
+ size_t in_frames, uint8_t *out)
+{
+ return s16_51_to_quad(in, in_frames, out);
+}
+
static size_t stereo_to_quad(struct cras_fmt_conv *conv, const uint8_t *in,
size_t in_frames, uint8_t *out)
{
@@ -340,7 +398,8 @@ struct cras_fmt_conv *cras_fmt_conv_create(const struct cras_audio_format *in,
conv->channel_converter = quad_to_stereo;
} else if (in->num_channels == 2 && out->num_channels == 6) {
conv->channel_converter = stereo_to_51;
- } else if (in->num_channels == 6 && out->num_channels == 2) {
+ } else if (in->num_channels == 6 &&
+ (out->num_channels == 2 || out->num_channels == 4)) {
int in_channel_layout_set = 0;
/* Checks if channel_layout is set in the incoming format */
@@ -361,11 +420,20 @@ struct cras_fmt_conv *cras_fmt_conv_create(const struct cras_audio_format *in,
return NULL;
}
conv->channel_converter = convert_channels;
- surround51_to_stereo_downmix_mtx(
- conv->ch_conv_mtx,
- conv->in_fmt.channel_layout);
+ if (out->num_channels == 4) {
+ surround51_to_quad_downmix_mtx(
+ conv->ch_conv_mtx,
+ conv->in_fmt.channel_layout);
+ } else {
+ surround51_to_stereo_downmix_mtx(
+ conv->ch_conv_mtx,
+ conv->in_fmt.channel_layout);
+ }
} else {
- conv->channel_converter = _51_to_stereo;
+ if (out->num_channels == 4)
+ conv->channel_converter = _51_to_quad;
+ else
+ conv->channel_converter = _51_to_stereo;
}
} else if (in->num_channels <= 8 && out->num_channels <= 8) {
// For average channel counts mix from all to all.
diff --git a/cras/src/server/cras_fmt_conv_ops.c b/cras/src/server/cras_fmt_conv_ops.c
index 87358af2..a306d216 100644
--- a/cras/src/server/cras_fmt_conv_ops.c
+++ b/cras/src/server/cras_fmt_conv_ops.c
@@ -235,20 +235,69 @@ size_t s16_51_to_stereo(const uint8_t *_in, size_t in_frames, uint8_t *_out)
int16_t *out = (int16_t *)_out;
static const unsigned int left_idx = 0;
static const unsigned int right_idx = 1;
- /* static const unsigned int left_surround_idx = 2; */
- /* static const unsigned int right_surround_idx = 3; */
- static const unsigned int center_idx = 4;
- /* static const unsigned int lfe_idx = 5; */
- size_t i;
+ static const unsigned int center_idx = 2;
+ /* static const unsigned int lfe_idx = 3; */
+ /* static const unsigned int left_surround_idx = 4; */
+ /* static const unsigned int right_surround_idx = 5; */
+ size_t i;
+ int16_t half_center;
+ /* Use the normalized_factor from the left channel = 1 / (|1| + |0.707|)
+ * to prevent mixing overflow.
+ */
+ const float normalized_factor = 0.585;
for (i = 0; i < in_frames; i++) {
- unsigned int half_center;
-
- half_center = in[6 * i + center_idx] / 2;
+ half_center =
+ in[6 * i + center_idx] * 0.707 * normalized_factor;
out[2 * i + left_idx] =
- s16_add_and_clip(in[6 * i + left_idx], half_center);
+ in[6 * i + left_idx] * normalized_factor + half_center;
out[2 * i + right_idx] =
- s16_add_and_clip(in[6 * i + right_idx], half_center);
+ in[6 * i + right_idx] * normalized_factor + half_center;
+ }
+ return in_frames;
+}
+
+/*
+ * Channel converter: 5.1 surround to quad (front L/R, rear L/R).
+ *
+ * The out buffer can have room for just quad samples. This convert function
+ * is used as the default behavior when channel layout is not set from the
+ * client side.
+ */
+size_t s16_51_to_quad(const uint8_t *_in, size_t in_frames, uint8_t *_out)
+{
+ const int16_t *in = (const int16_t *)_in;
+ int16_t *out = (int16_t *)_out;
+ static const unsigned int l_quad = 0;
+ static const unsigned int r_quad = 1;
+ static const unsigned int rl_quad = 2;
+ static const unsigned int rr_quad = 3;
+
+ static const unsigned int l_51 = 0;
+ static const unsigned int r_51 = 1;
+ static const unsigned int center_51 = 2;
+ static const unsigned int lfe_51 = 3;
+ static const unsigned int rl_51 = 4;
+ static const unsigned int rr_51 = 5;
+
+ /* Use normalized_factor from the left channel = 1 / (|1| + |0.707| + |0.5|)
+ * to prevent overflow. */
+ const float normalized_factor = 0.453;
+ size_t i;
+ for (i = 0; i < in_frames; i++) {
+ int16_t half_center;
+ int16_t lfe;
+
+ half_center = in[6 * i + center_51] * 0.707 * normalized_factor;
+ lfe = in[6 * i + lfe_51] * 0.5 * normalized_factor;
+ out[4 * i + l_quad] = normalized_factor * in[6 * i + l_51] +
+ half_center + lfe;
+ out[4 * i + r_quad] = normalized_factor * in[6 * i + r_51] +
+ half_center + lfe;
+ out[4 * i + rl_quad] =
+ normalized_factor * in[6 * i + rl_51] + lfe;
+ out[4 * i + rr_quad] =
+ normalized_factor * in[6 * i + rr_51] + lfe;
}
return in_frames;
}
diff --git a/cras/src/server/cras_fmt_conv_ops.h b/cras/src/server/cras_fmt_conv_ops.h
index 8042ad59..a1a57487 100644
--- a/cras/src/server/cras_fmt_conv_ops.h
+++ b/cras/src/server/cras_fmt_conv_ops.h
@@ -51,6 +51,11 @@ size_t s16_stereo_to_51(size_t left, size_t right, size_t center,
size_t s16_51_to_stereo(const uint8_t *in, size_t in_frames, uint8_t *out);
/*
+ * Channel converter: 5.1 surround to quad.
+ */
+size_t s16_51_to_quad(const uint8_t *in, size_t in_frames, uint8_t *out);
+
+/*
* Channel converter: stereo to quad (front L/R, rear L/R).
*/
size_t s16_stereo_to_quad(size_t front_left, size_t front_right,
diff --git a/cras/src/server/cras_hfp_ag_profile.c b/cras/src/server/cras_hfp_ag_profile.c
index 8cf4a431..9d59d40e 100644
--- a/cras/src/server/cras_hfp_ag_profile.c
+++ b/cras/src/server/cras_hfp_ag_profile.c
@@ -22,6 +22,7 @@
#include "cras_iodev_list.h"
#include "cras_observer.h"
#include "utlist.h"
+#include "packet_status_logger.h"
#define HFP_AG_PROFILE_NAME "Hands-Free Voice gateway"
#define HFP_AG_PROFILE_PATH "/org/chromium/Cras/Bluetooth/HFPAG"
@@ -103,6 +104,7 @@ struct audio_gateway {
};
static struct audio_gateway *connected_ags;
+static struct packet_status_logger wbs_logger;
static int need_go_sco_pcm(struct cras_bt_device *device)
{
@@ -411,6 +413,7 @@ int cras_hfp_ag_start(struct cras_bt_device *device)
ag->slc_handle, ag->profile);
} else {
ag->info = hfp_info_create();
+ hfp_info_set_wbs_logger(ag->info, &wbs_logger);
ag->idev =
hfp_iodev_create(CRAS_STREAM_INPUT, ag->device,
ag->slc_handle, ag->profile, ag->info);
@@ -453,6 +456,11 @@ struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device)
return NULL;
}
+struct packet_status_logger *cras_hfp_ag_get_wbs_logger()
+{
+ return &wbs_logger;
+}
+
void cras_hfp_ag_resend_device_battery_level()
{
struct audio_gateway *ag;
diff --git a/cras/src/server/cras_hfp_ag_profile.h b/cras/src/server/cras_hfp_ag_profile.h
index fb58efb6..50d27e05 100644
--- a/cras/src/server/cras_hfp_ag_profile.h
+++ b/cras/src/server/cras_hfp_ag_profile.h
@@ -53,6 +53,9 @@ struct hfp_slc_handle *cras_hfp_ag_get_active_handle();
/* Gets the SLC handle for given cras_bt_device. */
struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device);
+/* Gets the logger for WBS packet status. */
+struct packet_status_logger *cras_hfp_ag_get_wbs_logger();
+
/* Iterate all possible AGs (theoratically only one) and signal its battery
* level */
void cras_hfp_ag_resend_device_battery_level();
diff --git a/cras/src/server/cras_hfp_alsa_iodev.c b/cras/src/server/cras_hfp_alsa_iodev.c
index 532b6c40..b80a88c7 100644
--- a/cras/src/server/cras_hfp_alsa_iodev.c
+++ b/cras/src/server/cras_hfp_alsa_iodev.c
@@ -309,6 +309,10 @@ struct cras_iodev *hfp_alsa_iodev_create(struct cras_iodev *aio,
/* Record max supported channels into cras_iodev_info. */
iodev->info.max_supported_channels = 1;
+ /* Specifically disable EWMA calculation on this and the child iodev. */
+ ewma_power_disable(&iodev->ewma);
+ ewma_power_disable(&aio->ewma);
+
return iodev;
}
diff --git a/cras/src/server/cras_hfp_info.c b/cras/src/server/cras_hfp_info.c
index 550de586..fc407b29 100644
--- a/cras/src/server/cras_hfp_info.c
+++ b/cras/src/server/cras_hfp_info.c
@@ -19,6 +19,7 @@
#include "cras_sbc_codec.h"
#include "cras_server_metrics.h"
#include "utlist.h"
+#include "packet_status_logger.h"
/* The max buffer size. Note that the actual used size must set to multiple
* of SCO packet size, and the packet size does not necessarily be equal to
@@ -93,6 +94,7 @@ static const uint8_t h2_header_frames_count[] = { 0x08, 0x38, 0xc8, 0xf8 };
* read_align_cb - Callback used to align mSBC frame reading with read buf.
* msbc_read_current_corrupted - Flag to mark if the current mSBC frame
* read is corrupted.
+ * wbs_logger - The logger for packet status in WBS.
*/
struct hfp_info {
int fd;
@@ -119,6 +121,7 @@ struct hfp_info {
size_t read_rp;
int (*read_align_cb)(uint8_t *buf);
bool msbc_read_current_corrupted;
+ struct packet_status_logger *wbs_logger;
};
int hfp_info_add_iodev(struct hfp_info *info,
@@ -403,6 +406,20 @@ static const uint8_t *extract_msbc_frame(const uint8_t *input, int len,
return NULL;
}
+/* Log value 0 when packet is received. */
+static void log_wbs_packet_received(struct hfp_info *info)
+{
+ if (info->wbs_logger)
+ packet_status_logger_update(info->wbs_logger, 0);
+}
+
+/* Log value 1 when packet is lost. */
+static void log_wbs_packet_lost(struct hfp_info *info)
+{
+ if (info->wbs_logger)
+ packet_status_logger_update(info->wbs_logger, 1);
+}
+
/*
* Handle the case when mSBC frame is considered lost.
* Args:
@@ -419,6 +436,8 @@ static int handle_packet_loss(struct hfp_info *info)
info->msbc_num_in_frames++;
info->msbc_num_lost_frames++;
+ log_wbs_packet_lost(info);
+
in_bytes = buf_write_pointer_size(info->capture_buf, &pcm_avail);
if (pcm_avail < MSBC_CODE_SIZE)
return 0;
@@ -580,6 +599,7 @@ recv_msbc_bytes:
pcm_read += err;
} else {
/* Good mSBC frame decoded. */
+ log_wbs_packet_received(info);
buf_increment_write(info->capture_buf, pcm_decoded);
info->msbc_num_in_frames++;
cras_msbc_plc_handle_good_frames(info->msbc_plc, capture_buf,
@@ -723,6 +743,12 @@ error:
return NULL;
}
+void hfp_info_set_wbs_logger(struct hfp_info *info,
+ struct packet_status_logger *wbs_logger)
+{
+ info->wbs_logger = wbs_logger;
+}
+
int hfp_info_running(struct hfp_info *info)
{
return info->started;
@@ -760,6 +786,8 @@ int hfp_info_start(int fd, unsigned int mtu, int codec, struct hfp_info *info)
info->msbc_read = cras_msbc_codec_create();
info->msbc_write = cras_msbc_codec_create();
info->msbc_plc = cras_msbc_plc_create();
+
+ packet_status_logger_init(info->wbs_logger);
} else {
info->write_cb = hfp_write;
info->read_cb = hfp_read;
diff --git a/cras/src/server/cras_hfp_info.h b/cras/src/server/cras_hfp_info.h
index 96110e2a..3472aeab 100644
--- a/cras/src/server/cras_hfp_info.h
+++ b/cras/src/server/cras_hfp_info.h
@@ -30,6 +30,10 @@ struct hfp_info *hfp_info_create();
/* Destroys given hfp_info instance. */
void hfp_info_destroy(struct hfp_info *info);
+/* Sets the wbs_logger to hfp_info instance. */
+void hfp_info_set_wbs_logger(struct hfp_info *info,
+ struct packet_status_logger *wbs_logger);
+
/* Checks if given hfp_info is running. */
int hfp_info_running(struct hfp_info *info);
diff --git a/cras/src/server/cras_hfp_iodev.c b/cras/src/server/cras_hfp_iodev.c
index bf609cfb..7cce3736 100644
--- a/cras/src/server/cras_hfp_iodev.c
+++ b/cras/src/server/cras_hfp_iodev.c
@@ -350,6 +350,8 @@ struct cras_iodev *hfp_iodev_create(enum CRAS_STREAM_DIRECTION dir,
/* Record max supported channels into cras_iodev_info. */
iodev->info.max_supported_channels = 1;
+ ewma_power_disable(&iodev->ewma);
+
return iodev;
error:
diff --git a/cras/src/server/cras_hfp_slc.c b/cras/src/server/cras_hfp_slc.c
index 1cf003a1..e4f0127d 100644
--- a/cras/src/server/cras_hfp_slc.c
+++ b/cras/src/server/cras_hfp_slc.c
@@ -708,7 +708,14 @@ static int indicator_support(struct hfp_slc_handle *handle, const char *cmd)
* check the Bluetooth SIG Assigned Numbers web page.
*/
BTLOG(btlog, BT_HFP_HF_INDICATOR, 1, 0);
- err = hfp_send(handle, AT_CMD("+BIND: (2)"));
+ /* "2" is for HF Battery Level that we support. We don't
+ * support "1" but this is a workaround for Pixel Buds 2
+ * which expects this exact combination for battery
+ * reporting (HFP 1.7 standard) to work. This workaround
+ * is fine since we don't enable Safety Drive with
+ * +BIND: 1,1 (b/172680041).
+ */
+ err = hfp_send(handle, AT_CMD("+BIND: (1,2)"));
if (err < 0)
return err;
}
@@ -738,6 +745,14 @@ static int indicator_support(struct hfp_slc_handle *handle, const char *cmd)
* indicator
* 1 = enabled, value changes may be sent for this indicator
*/
+
+ /* We don't support Enhanced Driver Status, so explicitly
+ * disable it (b/172680041).
+ */
+ err = hfp_send(handle, AT_CMD("+BIND: 1,0"));
+ if (err < 0)
+ return err;
+
BTLOG(btlog, BT_HFP_HF_INDICATOR, 0, 0);
err = hfp_send(handle, AT_CMD("+BIND: 2,1"));
@@ -927,7 +942,7 @@ static int terminate_call(struct hfp_slc_handle *handle, const char *cmd)
*
* An initialized service level connection is the pre-condition for all
* call related procedures. Note that for the call related commands,
- * we are good to just respond with a dummy "OK".
+ * we are good to just respond with a meaningless "OK".
*
* The procedure to establish a service level connection is described below:
*
diff --git a/cras/src/server/cras_iodev.c b/cras/src/server/cras_iodev.c
index f426eb5f..fd1ce805 100644
--- a/cras/src/server/cras_iodev.c
+++ b/cras/src/server/cras_iodev.c
@@ -239,7 +239,7 @@ int cras_iodev_is_zero_volume(const struct cras_iodev *odev)
* | ---------------- | device from
* | | S1 Open | | audio_thread and
* | ---------------- | closes device
- * | Device with dummy start | |
+ * | Device with empty start | |
* | ops transits into | Sample is ready |
* | no stream state right V |
* | after open. ---------------- |
@@ -527,8 +527,8 @@ static void add_ext_dsp_module_to_pipeline(struct cras_iodev *iodev)
if (!pipeline) {
cras_iodev_alloc_dsp(iodev);
- cras_dsp_load_dummy_pipeline(iodev->dsp_context,
- iodev->format->num_channels);
+ cras_dsp_load_mock_pipeline(iodev->dsp_context,
+ iodev->format->num_channels);
pipeline = cras_dsp_get_pipeline(iodev->dsp_context);
}
/* dsp_context mutex locked. Now it's safe to modify dsp
@@ -953,6 +953,8 @@ int cras_iodev_open(struct cras_iodev *iodev, unsigned int cb_level,
iodev->highest_hw_level = 0;
iodev->input_dsp_offset = 0;
+ ewma_power_init(&iodev->ewma, iodev->format->frame_rate);
+
if (iodev->direction == CRAS_STREAM_OUTPUT) {
/* If device supports start ops, device can be in open state.
* Otherwise, device starts running right after opening. */
@@ -1097,6 +1099,9 @@ int cras_iodev_put_output_buffer(struct cras_iodev *iodev, uint8_t *frames,
loopback->cb_data);
}
+ ewma_power_calculate(&iodev->ewma, (int16_t *)frames,
+ iodev->format->num_channels, nframes);
+
rc = apply_dsp(iodev, frames, nframes);
if (rc)
return rc;
@@ -1200,6 +1205,11 @@ int cras_iodev_get_input_buffer(struct cras_iodev *iodev, unsigned int *frames)
*frames - iodev->input_dsp_offset);
if (rc)
return rc;
+ ewma_power_calculate_area(
+ &iodev->ewma,
+ (int16_t *)(hw_buffer +
+ iodev->input_dsp_offset * frame_bytes),
+ data->area, *frames - iodev->input_dsp_offset);
}
if (cras_system_get_capture_mute())
diff --git a/cras/src/server/cras_iodev.h b/cras/src/server/cras_iodev.h
index 553cb807..db16a0f8 100644
--- a/cras/src/server/cras_iodev.h
+++ b/cras/src/server/cras_iodev.h
@@ -19,6 +19,7 @@
#include "cras_dsp.h"
#include "cras_iodev_info.h"
#include "cras_messages.h"
+#include "ewma_power.h"
struct buffer_share;
struct cras_fmt_conv;
@@ -237,7 +238,7 @@ struct cras_ionode {
* stream side processing.
* initial_ramp_request - The value indicates which type of ramp the device
* should perform when some samples are ready for playback.
- *
+ * ewma - The ewma instance to calculate iodev volume.
*/
struct cras_iodev {
void (*set_volume)(struct cras_iodev *iodev);
@@ -312,6 +313,7 @@ struct cras_iodev {
unsigned int input_dsp_offset;
unsigned int initial_ramp_request;
struct input_data *input_data;
+ struct ewma_power ewma;
struct cras_iodev *prev, *next;
};
diff --git a/cras/src/server/cras_iodev_list.c b/cras/src/server/cras_iodev_list.c
index bba793d1..ada29719 100644
--- a/cras/src/server/cras_iodev_list.c
+++ b/cras/src/server/cras_iodev_list.c
@@ -361,7 +361,8 @@ static void possibly_enable_echo_reference(struct cras_iodev *dev)
if (dev->echo_reference_dev == NULL)
return;
- server_stream_create(stream_list, dev->echo_reference_dev->info.idx);
+ server_stream_create(stream_list, dev->echo_reference_dev->info.idx,
+ dev->format);
}
/*
diff --git a/cras/src/server/cras_loopback_iodev.c b/cras/src/server/cras_loopback_iodev.c
index 0947313f..cf3ba4ae 100644
--- a/cras/src/server/cras_loopback_iodev.c
+++ b/cras/src/server/cras_loopback_iodev.c
@@ -331,7 +331,7 @@ struct cras_iodev *loopback_iodev_create(enum CRAS_LOOPBACK_TYPE type)
if (iodev == NULL)
return NULL;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
node->type = node_type;
diff --git a/cras/src/server/cras_observer.c b/cras/src/server/cras_observer.c
index a73bcccf..0f17dc92 100644
--- a/cras/src/server/cras_observer.c
+++ b/cras/src/server/cras_observer.c
@@ -7,6 +7,7 @@
#include "cras_alert.h"
#include "cras_iodev_list.h"
+#include "cras_types.h"
#include "utlist.h"
struct cras_observer_client {
@@ -35,6 +36,7 @@ struct cras_observer_alerts {
struct cras_alert *num_active_streams[CRAS_NUM_DIRECTIONS];
struct cras_alert *non_empty_audio_state_changed;
struct cras_alert *bt_battery_changed;
+ struct cras_alert *num_input_streams_with_permission;
};
struct cras_observer_server {
@@ -76,6 +78,10 @@ struct cras_observer_alert_data_streams {
uint32_t num_active_streams;
};
+struct cras_observer_alert_data_input_streams {
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE];
+};
+
struct cras_observer_alert_data_hotword_triggered {
int64_t tv_sec;
int64_t tv_nsec;
@@ -253,6 +259,20 @@ static void num_active_streams_alert(void *arg, void *data)
}
}
+static void num_input_streams_with_permission_alert(void *arg, void *data)
+{
+ struct cras_observer_client *client;
+ struct cras_observer_alert_data_input_streams *input_streams_data =
+ (struct cras_observer_alert_data_input_streams *)data;
+
+ DL_FOREACH (g_observer->clients, client) {
+ if (client->ops.num_input_streams_with_permission_changed)
+ client->ops.num_input_streams_with_permission_changed(
+ client->context,
+ input_streams_data->num_input_streams);
+ }
+}
+
static void hotword_triggered_alert(void *arg, void *data)
{
struct cras_observer_client *client;
@@ -353,6 +373,7 @@ int cras_observer_server_init()
CRAS_OBSERVER_SET_ALERT(hotword_triggered, NULL, 0);
CRAS_OBSERVER_SET_ALERT(non_empty_audio_state_changed, NULL, 0);
CRAS_OBSERVER_SET_ALERT(bt_battery_changed, NULL, 0);
+ CRAS_OBSERVER_SET_ALERT(num_input_streams_with_permission, NULL, 0);
CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(num_active_streams,
CRAS_STREAM_OUTPUT);
@@ -386,6 +407,8 @@ void cras_observer_server_free()
cras_alert_destroy(g_observer->alerts.non_empty_audio_state_changed);
cras_alert_destroy(g_observer->alerts.bt_battery_changed);
cras_alert_destroy(
+ g_observer->alerts.num_input_streams_with_permission);
+ cras_alert_destroy(
g_observer->alerts.num_active_streams[CRAS_STREAM_OUTPUT]);
cras_alert_destroy(
g_observer->alerts.num_active_streams[CRAS_STREAM_INPUT]);
@@ -562,6 +585,21 @@ void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
cras_alert_pending_data(alert, &data, sizeof(data));
}
+void cras_observer_notify_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ struct cras_observer_alert_data_input_streams data;
+ struct cras_alert *alert;
+
+ memcpy(&data.num_input_streams, num_input_streams,
+ sizeof(*num_input_streams) * CRAS_NUM_CLIENT_TYPE);
+ alert = g_observer->alerts.num_input_streams_with_permission;
+ if (!alert)
+ return;
+
+ cras_alert_pending_data(alert, &data, sizeof(data));
+}
+
void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec)
{
struct cras_observer_alert_data_hotword_triggered data;
diff --git a/cras/src/server/cras_observer.h b/cras/src/server/cras_observer.h
index 1da5eeaf..2dd013b8 100644
--- a/cras/src/server/cras_observer.h
+++ b/cras/src/server/cras_observer.h
@@ -92,6 +92,10 @@ void cras_observer_notify_suspend_changed(int suspended);
void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
uint32_t num_active_streams);
+/* Notify observers of the number of input streams with permission. */
+void cras_observer_notify_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]);
+
/* Notify observers of the timestamp when hotword triggered. */
void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec);
diff --git a/cras/src/server/cras_rclient.c b/cras/src/server/cras_rclient.c
index 22fbb05c..d2646e75 100644
--- a/cras/src/server/cras_rclient.c
+++ b/cras/src/server/cras_rclient.c
@@ -59,9 +59,16 @@ int cras_rclient_send_message(const struct cras_rclient *client,
return client->ops->send_message_to_client(client, msg, fds, num_fds);
}
+static void cras_rclient_set_client_type(struct cras_rclient *client,
+ enum CRAS_CLIENT_TYPE client_type)
+{
+ client->client_type = client_type;
+}
+
struct cras_rclient *cras_rclient_create(int fd, size_t id,
enum CRAS_CONNECTION_TYPE conn_type)
{
+ struct cras_rclient *client;
if (!cras_validate_connection_type(conn_type))
goto error;
@@ -76,6 +83,14 @@ struct cras_rclient *cras_rclient_create(int fd, size_t id,
return cras_playback_rclient_create(fd, id);
case CRAS_VMS_UNIFIED:
return cras_unified_rclient_create(fd, id);
+ case CRAS_PLUGIN_PLAYBACK:
+ client = cras_playback_rclient_create(fd, id);
+ cras_rclient_set_client_type(client, CRAS_CLIENT_TYPE_PLUGIN);
+ return client;
+ case CRAS_PLUGIN_UNIFIED:
+ client = cras_unified_rclient_create(fd, id);
+ cras_rclient_set_client_type(client, CRAS_CLIENT_TYPE_PLUGIN);
+ return client;
default:
goto error;
}
diff --git a/cras/src/server/cras_rclient.h b/cras/src/server/cras_rclient.h
index 6cffb7d8..3a3988c2 100644
--- a/cras/src/server/cras_rclient.h
+++ b/cras/src/server/cras_rclient.h
@@ -20,6 +20,9 @@ struct cras_server_message;
* fd - Connection for client communication.
* ops - cras_rclient_ops for the cras_rclient.
* supported_directions - Bit mask for supported stream directions.
+ * client_type - Client type of this rclient. If this is set to value other
+ * than CRAS_CLIENT_TYPE_UNKNOWN, rclient will overwrite incoming
+ * messages' client type.
*/
struct cras_rclient {
struct cras_observer_client *observer;
@@ -27,6 +30,7 @@ struct cras_rclient {
int fd;
const struct cras_rclient_ops *ops;
int supported_directions;
+ enum CRAS_CLIENT_TYPE client_type;
};
/* Operations for cras_rclient.
diff --git a/cras/src/server/cras_rclient_util.c b/cras/src/server/cras_rclient_util.c
index da991282..def645e3 100644
--- a/cras/src/server/cras_rclient_util.c
+++ b/cras/src/server/cras_rclient_util.c
@@ -80,6 +80,13 @@ rclient_validate_stream_connect_message(const struct cras_rclient *client,
msg->direction, client->id);
return -EINVAL;
}
+
+ if (!cras_validate_client_type(msg->client_type)) {
+ syslog(LOG_ERR,
+ "stream_connect: invalid stream client_type: %x for "
+ "client: %zx.\n",
+ msg->client_type, client->id);
+ }
return 0;
}
@@ -155,6 +162,9 @@ int rclient_handle_client_stream_connect(struct cras_rclient *client,
stream_config = cras_rstream_config_init_with_message(
client, msg, &aud_fd, &client_shm_fd, &remote_fmt);
+ /* Overwrite client_type if client->client_type is set. */
+ if (client->client_type != CRAS_CLIENT_TYPE_UNKNOWN)
+ stream_config.client_type = client->client_type;
rc = stream_list_add(cras_iodev_list_get_stream_list(), &stream_config,
&stream);
if (rc)
@@ -279,15 +289,11 @@ int rclient_handle_message_from_client(struct cras_rclient *client,
switch (msg->id) {
case CRAS_SERVER_CONNECT_STREAM: {
int client_shm_fd = num_fds > 1 ? fds[1] : -1;
- struct cras_connect_message cmsg;
if (MSG_LEN_VALID(msg, struct cras_connect_message)) {
rclient_handle_client_stream_connect(
client,
(const struct cras_connect_message *)msg, fd,
client_shm_fd);
- } else if (!convert_connect_message_old(msg, &cmsg)) {
- rclient_handle_client_stream_connect(client, &cmsg, fd,
- client_shm_fd);
} else {
return -EINVAL;
}
diff --git a/cras/src/server/cras_rclient_util.h b/cras/src/server/cras_rclient_util.h
index e00f87c9..089c2ecb 100644
--- a/cras/src/server/cras_rclient_util.h
+++ b/cras/src/server/cras_rclient_util.h
@@ -122,33 +122,4 @@ int rclient_handle_message_from_client(struct cras_rclient *client,
const struct cras_server_message *msg,
int *fds, unsigned int num_fds);
-/*
- * Converts an old version of connect message to the correct
- * cras_connect_message. Returns zero on success, negative on failure.
- * Note that this is special check only for libcras transition in
- * clients, from CRAS_PROTO_VER 5 to 7.
- * TODO(fletcherw): clean up the function once transition is done.
- */
-static inline int
-convert_connect_message_old(const struct cras_server_message *msg,
- struct cras_connect_message *cmsg)
-{
- struct cras_connect_message_old *old;
-
- if (!MSG_LEN_VALID(msg, struct cras_connect_message_old))
- return -EINVAL;
-
- old = (struct cras_connect_message_old *)msg;
- if (old->proto_version != 5 || CRAS_PROTO_VER != 7)
- return -EINVAL;
-
- // We want to copy everything except the client_shm_size field, since
- // that overlaps slightly with the now larger client_shm_size.
- memcpy(cmsg, old, sizeof(*old) - sizeof(old->client_shm_size));
- cmsg->client_shm_size = old->client_shm_size;
- cmsg->buffer_offsets[0] = 0;
- cmsg->buffer_offsets[1] = 0;
- return 0;
-}
-
#endif /* CRAS_RCLIENT_UTIL_H_ */
diff --git a/cras/src/server/cras_rstream.c b/cras/src/server/cras_rstream.c
index b5a64901..94adcead 100644
--- a/cras/src/server/cras_rstream.c
+++ b/cras/src/server/cras_rstream.c
@@ -292,6 +292,7 @@ int cras_rstream_create(struct cras_rstream_config *config,
stream->num_missed_cb = 0;
stream->is_pinned = (config->dev_idx != NO_DEVICE);
stream->pinned_dev_idx = config->dev_idx;
+ ewma_power_init(&stream->ewma, stream->format.frame_rate);
rc = setup_shm_area(stream, config);
if (rc < 0) {
@@ -312,7 +313,7 @@ int cras_rstream_create(struct cras_rstream_config *config,
config->stream_id, config->buffer_frames, config->cb_threshold);
*stream_out = stream;
- cras_system_state_stream_added(stream->direction);
+ cras_system_state_stream_added(stream->direction, stream->client_type);
clock_gettime(CLOCK_MONOTONIC_RAW, &stream->start_ts);
@@ -324,7 +325,8 @@ int cras_rstream_create(struct cras_rstream_config *config,
void cras_rstream_destroy(struct cras_rstream *stream)
{
cras_server_metrics_stream_destroy(stream);
- cras_system_state_stream_removed(stream->direction);
+ cras_system_state_stream_removed(stream->direction,
+ stream->client_type);
close(stream->fd);
cras_audio_shm_destroy(stream->shm);
cras_audio_area_destroy(stream->audio_area);
@@ -472,9 +474,16 @@ void cras_rstream_update_input_write_pointer(struct cras_rstream *rstream)
void cras_rstream_update_output_read_pointer(struct cras_rstream *rstream)
{
+ size_t nfr = 0;
+ uint8_t *src;
unsigned int nwritten =
buffer_share_get_new_write_point(rstream->buf_state);
+ /* Retrieve the read pointer |src| start from which to calculate
+ * the EWMA power. */
+ src = cras_shm_get_readable_frames(rstream->shm, 0, &nfr);
+ ewma_power_calculate(&rstream->ewma, (int16_t *)src,
+ rstream->format.num_channels, nwritten);
cras_shm_buffer_read(rstream->shm, nwritten);
}
diff --git a/cras/src/server/cras_rstream.h b/cras/src/server/cras_rstream.h
index 059f2bb7..3bf7df0b 100644
--- a/cras/src/server/cras_rstream.h
+++ b/cras/src/server/cras_rstream.h
@@ -14,6 +14,7 @@
#include "cras_shm.h"
#include "cras_types.h"
#include "cras_rstream_config.h"
+#include "ewma_power.h"
struct cras_connect_message;
struct cras_rclient;
@@ -55,6 +56,7 @@ struct master_dev_info {
* first_missed_cb_ts - The time when the first missed callback happens.
* buf_state - State of the buffer from all devices for this stream.
* apm_list - List of audio processing module instances.
+ * ewma - The ewma instance to calculate stream volume.
* num_attached_devs - Number of iodevs this stream has attached to.
* num_missed_cb - Number of callback schedules have been missed.
* queued_frames - Cached value of the number of queued frames in shm.
@@ -85,6 +87,7 @@ struct cras_rstream {
struct timespec first_missed_cb_ts;
struct buffer_share *buf_state;
struct cras_apm_list *apm_list;
+ struct ewma_power ewma;
int num_attached_devs;
int num_missed_cb;
int queued_frames;
diff --git a/cras/src/server/cras_server_metrics.c b/cras/src/server/cras_server_metrics.c
index 91556d86..ef4011bd 100644
--- a/cras/src/server/cras_server_metrics.c
+++ b/cras/src/server/cras_server_metrics.c
@@ -268,7 +268,7 @@ metrics_device_type_str(enum CRAS_METRICS_DEVICE_TYPE device_type)
return "NoDevice";
case CRAS_METRICS_DEVICE_ALSA_LOOPBACK:
return "AlsaLoopback";
- /* Other dummy devices. */
+ /* Other fallback devices. */
case CRAS_METRICS_DEVICE_NORMAL_FALLBACK:
return "NormalFallback";
case CRAS_METRICS_DEVICE_ABNORMAL_FALLBACK:
diff --git a/cras/src/server/cras_system_state.c b/cras/src/server/cras_system_state.c
index a5834197..331ecb11 100644
--- a/cras/src/server/cras_system_state.c
+++ b/cras/src/server/cras_system_state.c
@@ -156,6 +156,8 @@ void cras_system_state_init(const char *device_config_dir, const char *shm_name,
exp_state->aec_supported = board_config.aec_supported;
exp_state->aec_group_id = board_config.aec_group_id;
exp_state->bt_wbs_enabled = board_config.bt_wbs_enabled;
+ exp_state->deprioritize_bt_wbs_mic =
+ board_config.deprioritize_bt_wbs_mic;
if ((rc = pthread_mutex_init(&state.update_lock, 0) != 0)) {
syslog(LOG_ERR, "Fatal: system state mutex init");
@@ -382,6 +384,11 @@ bool cras_system_get_bt_wbs_enabled()
return !!state.exp_state->bt_wbs_enabled;
}
+bool cras_system_get_deprioritize_bt_wbs_mic()
+{
+ return !!state.exp_state->deprioritize_bt_wbs_mic;
+}
+
void cras_system_set_bt_fix_a2dp_packet_size_enabled(bool enabled)
{
state.bt_fix_a2dp_packet_size = enabled;
@@ -511,7 +518,8 @@ void cras_system_rm_select_fd(int fd)
state.fd_rm(fd, state.select_data);
}
-void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)
+void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type)
{
struct cras_server_state *s;
@@ -521,13 +529,19 @@ void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)
s->num_active_streams[direction]++;
s->num_streams_attached++;
+ if (direction == CRAS_STREAM_INPUT) {
+ s->num_input_streams_with_permission[client_type]++;
+ cras_observer_notify_input_streams_with_permission(
+ s->num_input_streams_with_permission);
+ }
cras_system_state_update_complete();
cras_observer_notify_num_active_streams(
direction, s->num_active_streams[direction]);
}
-void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)
+void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type)
{
struct cras_server_state *s;
unsigned i, sum;
@@ -545,6 +559,11 @@ void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)
cras_clock_gettime(CLOCK_MONOTONIC_RAW,
&s->last_active_stream_time);
s->num_active_streams[direction]--;
+ if (direction == CRAS_STREAM_INPUT) {
+ s->num_input_streams_with_permission[client_type]--;
+ cras_observer_notify_input_streams_with_permission(
+ s->num_input_streams_with_permission);
+ }
cras_system_state_update_complete();
cras_observer_notify_num_active_streams(
@@ -566,6 +585,15 @@ unsigned cras_system_state_get_active_streams_by_direction(
return state.exp_state->num_active_streams[direction];
}
+void cras_system_state_get_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ unsigned type;
+ for (type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type)
+ num_input_streams[type] =
+ state.exp_state->num_input_streams_with_permission[type];
+}
+
void cras_system_state_get_last_stream_active_time(struct cras_timespec *ts)
{
*ts = state.exp_state->last_active_stream_time;
diff --git a/cras/src/server/cras_system_state.h b/cras/src/server/cras_system_state.h
index 7f92625e..ff04606a 100644
--- a/cras/src/server/cras_system_state.h
+++ b/cras/src/server/cras_system_state.h
@@ -122,6 +122,12 @@ void cras_system_set_bt_wbs_enabled(bool enabled);
/* Gets the elable flag of bluetooth wideband speech feature. */
bool cras_system_get_bt_wbs_enabled();
+/*
+ * Returns if Bluetooth WBS mic should be deprioritized for selecting
+ * as default audio input option.
+ */
+bool cras_system_get_deprioritize_bt_wbs_mic();
+
/* Sets the flag to enable or disable Bluetooth fixed A2DP packet size. */
void cras_system_set_bt_fix_a2dp_packet_size_enabled(bool enabled);
@@ -226,16 +232,20 @@ int cras_system_add_task(void (*callback)(void *data), void *callback_data);
* subsystem is idle.
* Args:
* direction - Directions of audio streams.
+ * client_type - CRAS_CLIENT_TYPE of the audio stream.
*/
-void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction);
+void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type);
/* Signals that an audio input or output stream has been removed from the
* system. This allows the count of active streams can be used to notice when
* the audio subsystem is idle.
* Args:
* direction - Directions of audio stream.
+ * client_type - CRAS_CLIENT_TYPE of the audio stream.
*/
-void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction);
+void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type);
/* Returns the number of active playback and capture streams. */
unsigned cras_system_state_get_active_streams();
@@ -247,6 +257,16 @@ unsigned cras_system_state_get_active_streams();
unsigned cras_system_state_get_active_streams_by_direction(
enum CRAS_STREAM_DIRECTION direction);
+/* Returns the number of input streams with permission per CRAS_CLIENT_TYPE.
+ *
+ * Returns:
+ * num_input_streams - An array with length = CRAS_NUM_CLIENT_TYPE and each
+ * element is the number of the current input
+ * streams with permission in each client type.
+ */
+void cras_system_state_get_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]);
+
/* Fills ts with the time the last stream was removed from the system, the time
* the stream count went to zero.
*/
diff --git a/cras/src/server/dev_io.c b/cras/src/server/dev_io.c
index 20b25f7e..42fe9558 100644
--- a/cras/src/server/dev_io.c
+++ b/cras/src/server/dev_io.c
@@ -126,6 +126,19 @@ static bool is_time_to_fetch(const struct dev_stream *dev_stream,
return 0;
}
+/* The log only accepts uint32 arguments, so the float power
+ * must be written as bits and assumed to have a float when
+ * parsing the log.
+ */
+static uint32_t get_ewma_power_as_int(struct ewma_power *ewma)
+{
+ uint32_t pow_as_int = 0;
+
+ if (sizeof(uint32_t) == sizeof(float))
+ memcpy(&pow_as_int, &ewma->power, sizeof(uint32_t));
+ return pow_as_int;
+}
+
/* Asks any stream with room for more data. Sets the time stamp for all streams.
* Args:
* adev - The output device streams are attached to.
@@ -194,7 +207,8 @@ static int fetch_streams(struct open_dev *adev)
dev_stream_set_delay(dev_stream, delay);
ATLOG(atlog, AUDIO_THREAD_FETCH_STREAM, rstream->stream_id,
- cras_rstream_get_cb_threshold(rstream), delay);
+ cras_rstream_get_cb_threshold(rstream),
+ get_ewma_power_as_int(&rstream->ewma));
rc = dev_stream_request_playback_samples(dev_stream, &now);
if (rc < 0) {
@@ -550,7 +564,8 @@ static int capture_to_streams(struct open_dev *adev)
break;
}
- ATLOG(atlog, AUDIO_THREAD_READ_AUDIO_DONE, remainder, 0, 0);
+ ATLOG(atlog, AUDIO_THREAD_READ_AUDIO_DONE, remainder,
+ get_ewma_power_as_int(&idev->ewma), 0);
return 0;
}
@@ -733,7 +748,8 @@ int write_output_samples(struct open_dev **odevs, struct open_dev *adev,
if (cras_iodev_update_rate(odev, hw_level, &hw_tstamp))
update_estimated_rate(adev);
}
- ATLOG(atlog, AUDIO_THREAD_FILL_AUDIO, adev->dev->info.idx, hw_level, 0);
+ ATLOG(atlog, AUDIO_THREAD_FILL_AUDIO, adev->dev->info.idx, hw_level,
+ odev->min_cb_level);
/* Don't request more than hardware can hold. Note that min_buffer_level
* has been subtracted from the actual hw_level so we need to take it
@@ -797,7 +813,7 @@ int write_output_samples(struct open_dev **odevs, struct open_dev *adev,
}
ATLOG(atlog, AUDIO_THREAD_FILL_AUDIO_DONE, hw_level, total_written,
- odev->min_cb_level);
+ get_ewma_power_as_int(&odev->ewma));
return total_written;
}
diff --git a/cras/src/server/dev_stream.c b/cras/src/server/dev_stream.c
index f0fcb71e..025aeddd 100644
--- a/cras/src/server/dev_stream.c
+++ b/cras/src/server/dev_stream.c
@@ -87,9 +87,12 @@ struct dev_stream *dev_stream_create(struct cras_rstream *stream,
} else {
/*
* For input, take into account the stream specific processing
- * like AEC. Use the post processing format to configure format
- * converter.
+ * like AEC. APM exists only in input path, and has no dependency
+ * to dev_stream. Starts APM in dev_stream's constructor just to
+ * align with its life cycle, and then gets the post processing
+ * format to configure format converter.
*/
+ cras_apm_list_start_apm(stream->apm_list, dev_ptr);
ofmt = cras_rstream_post_processing_format(stream, dev_ptr) ?:
dev_fmt,
rc = config_format_converter(&out->conv, stream->direction,
@@ -123,9 +126,8 @@ struct dev_stream *dev_stream_create(struct cras_rstream *stream,
stream_fmt->frame_rate, &stream->sleep_interval_ts);
stream->next_cb_ts = *cb_ts;
- /* Sets up the stream & dev pair and then start APM. */
+ /* Sets up the stream & dev pair. */
cras_rstream_dev_attach(stream, dev_id, dev_ptr);
- cras_apm_list_start_apm(stream->apm_list, dev_ptr);
return out;
}
diff --git a/cras/src/server/ewma_power.c b/cras/src/server/ewma_power.c
new file mode 100644
index 00000000..5270ef0e
--- /dev/null
+++ b/cras/src/server/ewma_power.c
@@ -0,0 +1,81 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "ewma_power.h"
+#include "math.h"
+
+/* One sample per 1ms. */
+#define EWMA_SAMPLE_RATE 1000
+
+/* Smooth factor for EWMA, 1 - expf(-1.0/(rate * 0.01))
+ * where the 0.01 corresponds to 10ms interval that is chosen and
+ * being used in Chrome for a long time.
+ * Here the |rate| is set to the down sampled EWMA_SAMPLE_RATE and
+ * whenever it changes the calculated |smooth_factor| should be updated
+ * accordingly.
+ */
+const static float smooth_factor = 0.095;
+
+void ewma_power_disable(struct ewma_power *ewma)
+{
+ ewma->enabled = 0;
+}
+
+void ewma_power_init(struct ewma_power *ewma, unsigned int rate)
+{
+ ewma->enabled = 1;
+ ewma->power_set = 0;
+ ewma->step_fr = rate / EWMA_SAMPLE_RATE;
+}
+
+void ewma_power_calculate(struct ewma_power *ewma, const int16_t *buf,
+ unsigned int channels, unsigned int size)
+{
+ int i, ch;
+ float power, f;
+
+ if (!ewma->enabled)
+ return;
+ for (i = 0; i < size; i += ewma->step_fr * channels) {
+ power = 0.0f;
+ for (ch = 0; ch < channels; ch++) {
+ f = buf[i + ch] / 32768.0f;
+ power += f * f / channels;
+ }
+ if (!ewma->power_set) {
+ ewma->power = power;
+ ewma->power_set = 1;
+ } else {
+ ewma->power = smooth_factor * power +
+ (1 - smooth_factor) * ewma->power;
+ }
+ }
+}
+
+void ewma_power_calculate_area(struct ewma_power *ewma, const int16_t *buf,
+ struct cras_audio_area *area, unsigned int size)
+{
+ int i, ch;
+ float power, f;
+
+ if (!ewma->enabled)
+ return;
+ for (i = 0; i < size; i += ewma->step_fr * area->num_channels) {
+ power = 0.0f;
+ for (ch = 0; ch < area->num_channels; ch++) {
+ if (area->channels[ch].ch_set == 0)
+ continue;
+ f = buf[i + ch] / 32768.0f;
+ power += f * f / area->num_channels;
+ }
+ if (!ewma->power_set) {
+ ewma->power = power;
+ ewma->power_set = 1;
+ } else {
+ ewma->power = smooth_factor * power +
+ (1 - smooth_factor) * ewma->power;
+ }
+ }
+}
diff --git a/cras/src/server/ewma_power.h b/cras/src/server/ewma_power.h
new file mode 100644
index 00000000..78d2e504
--- /dev/null
+++ b/cras/src/server/ewma_power.h
@@ -0,0 +1,65 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef EWMA_POWER_H_
+#define EWMA_POWER_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "cras_audio_area.h"
+
+/*
+ * The exponentially weighted moving average power module used to
+ * calculate the energe level in audio stream.
+ * Members:
+ * power_set - Flag to note if the first power value has set.
+ * enabled - Flag to enable ewma calculation. Set to false to
+ * make all calculations no-ops.
+ * power - The power value.
+ * step_fr - How many frames to sample one for EWMA calculation.
+ */
+struct ewma_power {
+ bool power_set;
+ bool enabled;
+ float power;
+ unsigned int step_fr;
+};
+
+/*
+ * Disables the ewma instance.
+ */
+void ewma_power_disable(struct ewma_power *ewma);
+
+/*
+ * Initializes the ewma_power object.
+ * Args:
+ * ewma - The ewma_power object to initialize.
+ * rate - The sample rate of the audio data that the ewma object
+ * will calculate power from.
+ */
+void ewma_power_init(struct ewma_power *ewma, unsigned int rate);
+
+/*
+ * Feeds an audio buffer to ewma_power object to calculate the
+ * latest power value.
+ * Args:
+ * ewma - The ewma_power object to calculate power.
+ * buf - Pointer to the audio data.
+ * channels - Number of channels of the audio data.
+ * size - Length in frames of the audio data.
+ */
+void ewma_power_calculate(struct ewma_power *ewma, const int16_t *buf,
+ unsigned int channels, unsigned int size);
+
+/*
+ * Feeds non-interleaved audio data to ewma_power to calculate the
+ * latest power value. This is similar to ewma_power_calculate but
+ * accepts cras_audio_area.
+ */
+void ewma_power_calculate_area(struct ewma_power *ewma, const int16_t *buf,
+ struct cras_audio_area *area, unsigned int size);
+
+#endif /* EWMA_POWER_H_ */
diff --git a/cras/src/server/server_stream.c b/cras/src/server/server_stream.c
index 48dd6a30..6644c469 100644
--- a/cras/src/server/server_stream.c
+++ b/cras/src/server/server_stream.c
@@ -16,18 +16,6 @@
static unsigned int server_stream_block_size = 480;
/*
- * Server stream doesn't care what format is used, because no
- * client is reading data from stream. The main point is to
- * make pinned device open and let data flow through its dsp
- * pipeline.
- */
-static struct cras_audio_format format = {
- SND_PCM_FORMAT_S16_LE,
- 48000,
- 2,
-};
-
-/*
* Information of a stream created by server. Currently only
* one server stream is allowed, for echo reference use.
*/
@@ -45,7 +33,8 @@ static void server_stream_add_cb(void *data)
stream_list_add(stream_list, stream_config, &stream);
}
-void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx)
+void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx,
+ struct cras_audio_format *format)
{
int audio_fd = -1;
int client_shm_fd = -1;
@@ -64,7 +53,7 @@ void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx)
CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_SERVER_STREAM,
CRAS_STREAM_INPUT, dev_idx,
/*flags=*/SERVER_ONLY,
- /*effects=*/0, &format, server_stream_block_size,
+ /*effects=*/0, format, server_stream_block_size,
server_stream_block_size, &audio_fd, &client_shm_fd,
/*client_shm_size=*/0, buffer_offsets, stream_config);
diff --git a/cras/src/server/server_stream.h b/cras/src/server/server_stream.h
index 595987cb..e1eb8e10 100644
--- a/cras/src/server/server_stream.h
+++ b/cras/src/server/server_stream.h
@@ -14,8 +14,8 @@ struct stream_list;
* stream_list - List of stream to add new server stream to.
* dev_idx - The id of the device that new server stream will pin to.
*/
-void server_stream_create(struct stream_list *stream_list,
- unsigned int dev_idx);
+void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx,
+ struct cras_audio_format *format);
/*
* Asynchronously destroys existing server stream pinned to device of given idx.
diff --git a/cras/src/server/test_iodev.c b/cras/src/server/test_iodev.c
index 266b62a8..cb7d5f3a 100644
--- a/cras/src/server/test_iodev.c
+++ b/cras/src/server/test_iodev.c
@@ -201,7 +201,7 @@ struct cras_iodev *test_iodev_create(enum CRAS_STREAM_DIRECTION direction,
*/
iodev->info.max_supported_channels = 1;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
node->plugged = 1;