diff options
Diffstat (limited to 'cras/src/server/cras_alsa_io.c')
-rw-r--r-- | cras/src/server/cras_alsa_io.c | 462 |
1 files changed, 165 insertions, 297 deletions
diff --git a/cras/src/server/cras_alsa_io.c b/cras/src/server/cras_alsa_io.c index 275a6810..4aec9d68 100644 --- a/cras/src/server/cras_alsa_io.c +++ b/cras/src/server/cras_alsa_io.c @@ -38,6 +38,7 @@ #include "softvol_curve.h" #include "utlist.h" +#define MAX_ALSA_DEV_NAME_LENGTH 9 /* Alsa names "hw:XX,YY" + 1 for null. */ #define HOTWORD_DEV "Wake on Voice" #define DEFAULT "(default)" #define HDMI "HDMI" @@ -47,8 +48,6 @@ #define HEADPHONE "Headphone" #define MIC "Mic" #define USB "USB" -#define LOOPBACK_CAPTURE "Loopback Capture" -#define LOOPBACK_PLAYBACK "Loopback Playback" /* * For USB, pad the output buffer. This avoids a situation where there isn't a @@ -80,14 +79,12 @@ static const struct timespec no_stream_fill_zeros_duration = { * This extends cras_ionode to include alsa-specific information. * Members: * mixer_output - From cras_alsa_mixer. - * pcm_name - PCM name for snd_pcm_open. * volume_curve - Volume curve for this node. * jack - The jack associated with the node. */ struct alsa_output_node { struct cras_ionode base; struct mixer_control *mixer_output; - const char *pcm_name; struct cras_volume_curve *volume_curve; const struct cras_alsa_jack *jack; }; @@ -95,7 +92,6 @@ struct alsa_output_node { struct alsa_input_node { struct cras_ionode base; struct mixer_control *mixer_input; - const char *pcm_name; const struct cras_alsa_jack *jack; int8_t *channel_layout; }; @@ -103,7 +99,7 @@ struct alsa_input_node { /* * Child of cras_iodev, alsa_io handles ALSA interaction for sound devices. * base - The cras_iodev structure "base class". - * pcm_name - The PCM name passed to snd_pcm_open() (e.g. "hw:0,0"). + * dev - String that names this device (e.g. "hw:0,0"). * dev_name - value from snd_pcm_info_get_name * dev_id - value from snd_pcm_info_get_id * device_index - ALSA index of device, Y in "hw:X:Y". @@ -113,7 +109,10 @@ 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. + * jack_always_plugged - true if this node is always plugged even without jack. + * enable_htimestamp - True when the device's htimestamp is used. * handle - Handle to the opened ALSA device. + * num_underruns - Number of times we have run out of data (playback only). * num_severe_underruns - Number of times we have run out of data badly. Unlike num_underruns which records for the duration where device is opened, num_severe_underruns records @@ -125,6 +124,8 @@ struct alsa_input_node { * jack_list - List of alsa jack controls for this device. * ucm - CRAS use case manager, if configuration is found. * mmap_offset - offset returned from mmap_begin. + * dsp_name_default - the default dsp name for the device. It can be overridden + * by the jack specific dsp name. * poll_fd - Descriptor used to block until data is ready. * dma_period_set_microsecs - If non-zero, the value to apply to the dma_period. * free_running - true if device is playing zeros in the buffer without @@ -135,11 +136,10 @@ struct alsa_input_node { * severe_underrun_frames - The threshold for severe underrun. * default_volume_curve - Default volume curve that converts from an index * to dBFS. - * has_dependent_dev - true if this iodev has dependent device. */ struct alsa_io { struct cras_iodev base; - char *pcm_name; + char *dev; char *dev_name; char *dev_id; uint32_t device_index; @@ -147,7 +147,10 @@ struct alsa_io { enum CRAS_ALSA_CARD_TYPE card_type; int is_first; int fully_specified; + int jack_always_plugged; + int enable_htimestamp; snd_pcm_t *handle; + unsigned int num_underruns; unsigned int num_severe_underruns; snd_pcm_stream_t alsa_stream; struct cras_alsa_mixer *mixer; @@ -155,6 +158,7 @@ struct alsa_io { struct cras_alsa_jack_list *jack_list; struct cras_use_case_mgr *ucm; snd_pcm_uframes_t mmap_offset; + const char *dsp_name_default; int poll_fd; unsigned int dma_period_set_microsecs; int free_running; @@ -162,7 +166,6 @@ struct alsa_io { snd_pcm_uframes_t severe_underrun_frames; struct cras_volume_curve *default_volume_curve; int hwparams_set; - int has_dependent_dev; }; static void init_device_settings(struct alsa_io *aio); @@ -171,10 +174,6 @@ static int alsa_iodev_set_active_node(struct cras_iodev *iodev, struct cras_ionode *ionode, unsigned dev_enabled); -static int get_fixed_rate(struct alsa_io *aio); - -static int update_supported_formats(struct cras_iodev *iodev); - /* * Defines the default values of nodes. */ @@ -268,21 +267,6 @@ static const struct { .type = CRAS_NODE_TYPE_BLUETOOTH, .position = NODE_POSITION_EXTERNAL, }, - { - .name = "Echo Reference", - .type = CRAS_NODE_TYPE_ECHO_REFERENCE, - .position = NODE_POSITION_INTERNAL, - }, - { - .name = LOOPBACK_CAPTURE, - .type = CRAS_NODE_TYPE_ALSA_LOOPBACK, - .position = NODE_POSITION_INTERNAL, - }, - { - .name = LOOPBACK_PLAYBACK, - .type = CRAS_NODE_TYPE_ALSA_LOOPBACK, - .position = NODE_POSITION_INTERNAL, - }, }; static int set_hwparams(struct cras_iodev *iodev) @@ -329,7 +313,8 @@ static int frames_queued(const struct cras_iodev *iodev, aio->num_severe_underruns++; return rc; } - clock_gettime(CLOCK_MONOTONIC_RAW, tstamp); + if (!aio->enable_htimestamp) + clock_gettime(CLOCK_MONOTONIC_RAW, tstamp); if (iodev->direction == CRAS_STREAM_INPUT) return (int)frames; @@ -371,7 +356,7 @@ static int close_dev(struct cras_iodev *iodev) return 0; } -static int empty_hotword_cb(void *arg, int revents) +static int dummy_hotword_cb(void *arg) { /* Only need this once. */ struct alsa_io *aio = (struct alsa_io *)arg; @@ -390,42 +375,13 @@ static int open_dev(struct cras_iodev *iodev) struct alsa_io *aio = (struct alsa_io *)iodev; snd_pcm_t *handle; int rc; - const char *pcm_name = NULL; - int enable_noise_cancellation; - if (aio->base.direction == CRAS_STREAM_OUTPUT) { - struct alsa_output_node *aout = - (struct alsa_output_node *)aio->base.active_node; - pcm_name = aout->pcm_name; - } else { - struct alsa_input_node *ain = - (struct alsa_input_node *)aio->base.active_node; - pcm_name = ain->pcm_name; - } - - /* For legacy UCM path which doesn't have PlaybackPCM or CapturePCM. */ - if (pcm_name == NULL) - pcm_name = aio->pcm_name; - - rc = cras_alsa_pcm_open(&handle, pcm_name, aio->alsa_stream); + rc = cras_alsa_pcm_open(&handle, aio->dev, aio->alsa_stream); if (rc < 0) return rc; aio->handle = handle; - /* Enable or disable noise cancellation if it supports. */ - if (aio->ucm && iodev->direction == CRAS_STREAM_INPUT && - ucm_node_noise_cancellation_exists(aio->ucm, - iodev->active_node->name)) { - enable_noise_cancellation = - cras_system_get_noise_cancellation_enabled(); - rc = ucm_enable_node_noise_cancellation( - aio->ucm, iodev->active_node->name, - enable_noise_cancellation); - if (rc < 0) - return rc; - } - return 0; } @@ -439,6 +395,7 @@ static int configure_dev(struct cras_iodev *iodev) */ if (iodev->format == NULL) return -EINVAL; + aio->num_underruns = 0; aio->free_running = 0; aio->filled_zeros_for_draining = 0; aio->severe_underrun_frames = @@ -447,7 +404,7 @@ static int configure_dev(struct cras_iodev *iodev) cras_iodev_init_audio_area(iodev, iodev->format->num_channels); syslog(LOG_DEBUG, "Configure alsa device %s rate %zuHz, %zu channels", - aio->pcm_name, iodev->format->frame_rate, + aio->dev, iodev->format->frame_rate, iodev->format->num_channels); rc = set_hwparams(iodev); @@ -460,7 +417,7 @@ static int configure_dev(struct cras_iodev *iodev) return rc; /* Configure software params. */ - rc = cras_alsa_set_swparams(aio->handle); + rc = cras_alsa_set_swparams(aio->handle, &aio->enable_htimestamp); if (rc < 0) return rc; @@ -500,8 +457,8 @@ static int configure_dev(struct cras_iodev *iodev) free(ufds); if (aio->poll_fd >= 0) - audio_thread_add_events_callback( - aio->poll_fd, empty_hotword_cb, aio, POLLIN); + audio_thread_add_callback(aio->poll_fd, + dummy_hotword_cb, aio); } /* Capture starts right away, playback will wait for samples. */ @@ -791,7 +748,8 @@ static void set_alsa_capture_gain(struct cras_iodev *iodev) { const struct alsa_io *aio = (const struct alsa_io *)iodev; struct alsa_input_node *ain; - long min_capture_gain, max_capture_gain, gain; + long gain; + assert(aio); if (aio->mixer == NULL) return; @@ -799,31 +757,20 @@ static void set_alsa_capture_gain(struct cras_iodev *iodev) /* Only set the volume if the dev is active. */ if (!has_handle(aio)) return; - - ain = get_active_input(aio); - - cras_alsa_mixer_set_capture_mute(aio->mixer, - cras_system_get_capture_mute(), - ain ? ain->mixer_input : NULL); - - /* For USB device without UCM config, not change a gain control. */ - if (ain && ain->base.type == CRAS_NODE_TYPE_USB && !aio->ucm) - return; + gain = cras_iodev_adjust_active_node_gain( + iodev, cras_system_get_capture_gain()); /* Set hardware gain to 0dB if software gain is needed. */ if (cras_iodev_software_volume_needed(iodev)) gain = 0; - else { - min_capture_gain = cras_alsa_mixer_get_minimum_capture_gain( - aio->mixer, ain ? ain->mixer_input : NULL); - max_capture_gain = cras_alsa_mixer_get_maximum_capture_gain( - aio->mixer, ain ? ain->mixer_input : NULL); - gain = MAX(iodev->active_node->capture_gain, min_capture_gain); - gain = MIN(gain, max_capture_gain); - } + + ain = get_active_input(aio); cras_alsa_mixer_set_capture_dBFS(aio->mixer, gain, ain ? ain->mixer_input : NULL); + cras_alsa_mixer_set_capture_mute(aio->mixer, + cras_system_get_capture_mute(), + ain ? ain->mixer_input : NULL); } /* @@ -851,6 +798,28 @@ static void init_device_settings(struct alsa_io *aio) set_alsa_volume(&aio->base); set_alsa_mute(&aio->base); } else { + struct mixer_control *mixer_input = NULL; + struct alsa_input_node *ain = get_active_input(aio); + long min_capture_gain, max_capture_gain; + + if (ain) + mixer_input = ain->mixer_input; + + if (cras_iodev_software_volume_needed(&aio->base)) { + min_capture_gain = + cras_iodev_minimum_software_gain(&aio->base); + max_capture_gain = + cras_iodev_maximum_software_gain(&aio->base); + } else { + min_capture_gain = + cras_alsa_mixer_get_minimum_capture_gain( + aio->mixer, mixer_input); + max_capture_gain = + cras_alsa_mixer_get_maximum_capture_gain( + aio->mixer, mixer_input); + } + cras_system_set_capture_gain_limits(min_capture_gain, + max_capture_gain); set_alsa_capture_gain(&aio->base); } } @@ -868,7 +837,6 @@ static void free_alsa_iodev_resources(struct alsa_io *aio) { struct cras_ionode *node; struct alsa_output_node *aout; - struct alsa_input_node *ain; free(aio->base.supported_rates); free(aio->base.supported_channel_counts); @@ -878,10 +846,6 @@ static void free_alsa_iodev_resources(struct alsa_io *aio) if (aio->base.direction == CRAS_STREAM_OUTPUT) { aout = (struct alsa_output_node *)node; cras_volume_curve_destroy(aout->volume_curve); - free((void *)aout->pcm_name); - } else { - ain = (struct alsa_input_node *)node; - free((void *)ain->pcm_name); } cras_iodev_rm_node(&aio->base, node); free(node->softvol_scalers); @@ -889,8 +853,9 @@ static void free_alsa_iodev_resources(struct alsa_io *aio) free(node); } + free((void *)aio->dsp_name_default); cras_iodev_free_resources(&aio->base); - free(aio->pcm_name); + free(aio->dev); if (aio->dev_id) free(aio->dev_id); if (aio->dev_name) @@ -1102,50 +1067,71 @@ set_output_node_software_volume_needed(struct alsa_output_node *output, output->base.name); } -static void set_input_default_node_gain(struct alsa_input_node *input, - struct alsa_io *aio) +static void set_input_node_software_volume_needed(struct alsa_input_node *input, + struct alsa_io *aio) { - long gain; + long min_software_gain; + long max_software_gain; + int rc; - input->base.capture_gain = DEFAULT_CAPTURE_GAIN; - input->base.ui_gain_scaler = 1.0f; + input->base.software_volume_needed = 0; + input->base.min_software_gain = DEFAULT_MIN_CAPTURE_GAIN; + input->base.max_software_gain = 0; + /* Enable software gain only if max software gain is specified in UCM. */ if (!aio->ucm) return; - if (ucm_get_default_node_gain(aio->ucm, input->base.name, &gain) == 0) - input->base.capture_gain = gain; + rc = ucm_get_max_software_gain(aio->ucm, input->base.name, + &max_software_gain); + + /* If max software gain doesn't exist, skip min software gain setting. */ + if (rc) + return; + + input->base.software_volume_needed = 1; + input->base.max_software_gain = max_software_gain; + syslog(LOG_INFO, + "Use software gain for %s with max %ld because it is specified" + " in UCM", + input->base.name, max_software_gain); + + /* Enable min software gain if it is specified in UCM. */ + rc = ucm_get_min_software_gain(aio->ucm, input->base.name, + &min_software_gain); + if (rc) + return; + + if (min_software_gain > max_software_gain) { + syslog(LOG_ERR, + "Ignore MinSoftwareGain %ld because it is larger than " + "MaxSoftwareGain %ld", + min_software_gain, max_software_gain); + return; + } + + syslog(LOG_INFO, + "Use software gain for %s with min %ld because it is specified" + " in UCM", + input->base.name, min_software_gain); + input->base.min_software_gain = min_software_gain; } -static void set_input_node_intrinsic_sensitivity(struct alsa_input_node *input, - struct alsa_io *aio) +static void set_input_default_node_gain(struct alsa_input_node *input, + struct alsa_io *aio) { - long sensitivity; + long default_node_gain; int rc; - input->base.intrinsic_sensitivity = 0; + if (!aio->ucm) + return; - if (aio->ucm) { - rc = ucm_get_intrinsic_sensitivity(aio->ucm, input->base.name, - &sensitivity); - if (rc) - return; - } else if (input->base.type == CRAS_NODE_TYPE_USB) { - /* - * For USB devices without UCM config, trust the default capture gain. - * Set sensitivity to the default dbfs so the capture gain is 0. - */ - sensitivity = DEFAULT_CAPTURE_VOLUME_DBFS; - } else { + rc = ucm_get_default_node_gain(aio->ucm, input->base.name, + &default_node_gain); + if (rc) return; - } - input->base.intrinsic_sensitivity = sensitivity; - input->base.capture_gain = DEFAULT_CAPTURE_VOLUME_DBFS - sensitivity; - syslog(LOG_INFO, - "Use software gain %ld for %s because IntrinsicSensitivity %ld is" - " specified in UCM", - input->base.capture_gain, input->base.name, sensitivity); + input->base.capture_gain = default_node_gain; } static void check_auto_unplug_output_node(struct alsa_io *aio, @@ -1263,6 +1249,7 @@ static struct alsa_input_node *new_input(struct alsa_io *aio, { struct cras_iodev *iodev = &aio->base; struct alsa_input_node *input; + char *mic_positions; int err; input = (struct alsa_input_node *)calloc(1, sizeof(*input)); @@ -1279,10 +1266,22 @@ static struct alsa_input_node *new_input(struct alsa_io *aio, input->mixer_input = cras_input; strncpy(input->base.name, name, sizeof(input->base.name) - 1); set_node_initial_state(&input->base, aio->card_type); + set_input_node_software_volume_needed(input, aio); set_input_default_node_gain(input, aio); - set_input_node_intrinsic_sensitivity(input, aio); if (aio->ucm) { + /* Check mic positions only for internal mic. */ + if ((input->base.type == CRAS_NODE_TYPE_MIC) && + (input->base.position == NODE_POSITION_INTERNAL)) { + mic_positions = ucm_get_mic_positions(aio->ucm); + if (mic_positions) { + strncpy(input->base.mic_positions, + mic_positions, + sizeof(input->base.mic_positions) - 1); + free(mic_positions); + } + } + /* Check if channel map is specified in UCM. */ input->channel_layout = (int8_t *)malloc( CRAS_CH_MAX * sizeof(*input->channel_layout)); @@ -1388,7 +1387,8 @@ static const struct cras_alsa_jack *get_jack_from_node(struct cras_ionode *node) /* * Returns the dsp name specified in the ucm config. If there is a dsp name - * specified for the active node, use that. Otherwise NULL should be returned. + * specified for the active node, use that. Otherwise use the default dsp name + * for the alsa_io device. */ static const char *get_active_dsp_name(struct alsa_io *aio) { @@ -1397,7 +1397,7 @@ static const char *get_active_dsp_name(struct alsa_io *aio) if (node == NULL) return NULL; - return node->dsp_name; + return node->dsp_name ?: aio->dsp_name_default; } /* @@ -1426,73 +1426,6 @@ create_volume_curve_for_jack(const struct cras_card_config *config, } /* - * Updates max_supported_channels value into cras_iodev_info. - * Note that supported_rates, supported_channel_counts, and supported_formats of - * iodev will be updated to the latest values after calling. - */ -static void update_max_supported_channels(struct cras_iodev *iodev) -{ - struct alsa_io *aio = (struct alsa_io *)iodev; - unsigned int max_channels = 0; - size_t i; - bool active_node_predicted = false; - int rc; - - /* - * max_supported_channels might be wrong in dependent PCM cases. Always - * return 2 for such cases. - */ - if (aio->has_dependent_dev) { - max_channels = 2; - goto update_info; - } - - if (aio->handle) { - syslog(LOG_ERR, - "update_max_supported_channels should not be called " - "while device is opened."); - return; - } - - /* - * In the case of updating max_supported_channels on changing jack - * plugging status of devices, the active node may not be determined - * yet. Use the first node as the active node for obtaining the value of - * max_supported_channels. - */ - if (!iodev->active_node) { - if (!iodev->nodes) - goto update_info; - iodev->active_node = iodev->nodes; - syslog(LOG_DEBUG, - "Predict ionode %s as active node temporarily.", - iodev->active_node->name); - active_node_predicted = true; - } - - rc = open_dev(iodev); - if (active_node_predicted) - iodev->active_node = NULL; // Reset the predicted active_node. - if (rc) - goto update_info; - - rc = update_supported_formats(iodev); - if (rc) - goto close_iodev; - - for (i = 0; iodev->supported_channel_counts[i] != 0; i++) { - if (iodev->supported_channel_counts[i] > max_channels) - max_channels = iodev->supported_channel_counts[i]; - } - -close_iodev: - close_dev(iodev); - -update_info: - iodev->info.max_supported_channels = max_channels; -} - -/* * Callback that is called when an output jack is plugged or unplugged. */ static void jack_output_plug_event(const struct cras_alsa_jack *jack, @@ -1555,13 +1488,6 @@ static void jack_output_plug_event(const struct cras_alsa_jack *jack, cras_iodev_set_node_plugged(&node->base, plugged); check_auto_unplug_output_node(aio, &node->base, plugged); - - /* - * For HDMI plug event cases, update max supported channels according - * to the current active node. - */ - if (node->base.type == CRAS_NODE_TYPE_HDMI && plugged) - update_max_supported_channels(&aio->base); } /* @@ -1675,29 +1601,6 @@ static int get_fixed_rate(struct alsa_io *aio) return ucm_get_sample_rate_for_dev(aio->ucm, name, aio->base.direction); } -static size_t get_fixed_channels(struct alsa_io *aio) -{ - const char *name; - int rc; - size_t channels; - - if (aio->base.direction == CRAS_STREAM_OUTPUT) { - struct alsa_output_node *active = get_active_output(aio); - if (!active) - return -ENOENT; - name = active->base.name; - } else { - struct alsa_input_node *active = get_active_input(aio); - if (!active) - return -ENOENT; - name = active->base.name; - } - - rc = ucm_get_channels_for_dev(aio->ucm, name, aio->base.direction, - &channels); - return (rc) ? 0 : channels; -} - /* * Updates the supported sample rates and channel counts. */ @@ -1706,7 +1609,6 @@ static int update_supported_formats(struct cras_iodev *iodev) struct alsa_io *aio = (struct alsa_io *)iodev; int err; int fixed_rate; - size_t fixed_channels; free(iodev->supported_rates); iodev->supported_rates = NULL; @@ -1731,16 +1633,6 @@ static int update_supported_formats(struct cras_iodev *iodev) iodev->supported_rates[0] = fixed_rate; iodev->supported_rates[1] = 0; } - - /* Allow UCM to override supported channel counts. */ - fixed_channels = get_fixed_channels(aio); - if (fixed_channels > 0) { - free(iodev->supported_channel_counts); - iodev->supported_channel_counts = (size_t *)malloc( - 2 * sizeof(iodev->supported_channel_counts[0])); - iodev->supported_channel_counts[0] = fixed_channels; - iodev->supported_channel_counts[1] = 0; - } } return 0; } @@ -1861,8 +1753,8 @@ static int adjust_appl_ptr_samples_remaining(struct cras_iodev *odev) * If underrun happened, handle it. Because alsa_output_underrun function * has already called adjust_appl_ptr, we don't need to call it again. */ - if (real_hw_level <= odev->min_buffer_level) - return cras_iodev_output_underrun(odev, real_hw_level, 0); + if (real_hw_level < odev->min_buffer_level) + return odev->output_underrun(odev); if (real_hw_level > aio->filled_zeros_for_draining) valid_sample = real_hw_level - aio->filled_zeros_for_draining; @@ -1880,8 +1772,12 @@ static int adjust_appl_ptr_samples_remaining(struct cras_iodev *odev) static int alsa_output_underrun(struct cras_iodev *odev) { + struct alsa_io *aio = (struct alsa_io *)odev; int rc; + /* Update number of underruns we got. */ + aio->num_underruns++; + /* Fill whole buffer with zeros. This avoids samples left in buffer causing * noise when device plays them. */ rc = fill_whole_buffer_with_zeros(odev); @@ -1910,8 +1806,8 @@ static int possibly_enter_free_run(struct cras_iodev *odev) real_hw_level = rc; /* If underrun happened, handle it and enter free run state. */ - if (real_hw_level <= odev->min_buffer_level) { - rc = cras_iodev_output_underrun(odev, real_hw_level, 0); + if (real_hw_level < odev->min_buffer_level) { + rc = odev->output_underrun(odev); if (rc < 0) return rc; aio->free_running = 1; @@ -1944,10 +1840,6 @@ static int leave_free_run(struct cras_iodev *odev) struct alsa_io *aio = (struct alsa_io *)odev; int rc; - /* Restart rate estimation because free run internval should not - * be included. */ - cras_iodev_reset_rate_estimator(odev); - if (aio->free_running) rc = adjust_appl_ptr_for_leaving_free_run(odev); else @@ -1984,6 +1876,12 @@ static int is_free_running(const struct cras_iodev *odev) return aio->free_running; } +static unsigned int get_num_underruns(const struct cras_iodev *iodev) +{ + const struct alsa_io *aio = (const struct alsa_io *)iodev; + return aio->num_underruns; +} + static unsigned int get_num_severe_underruns(const struct cras_iodev *iodev) { const struct alsa_io *aio = (const struct alsa_io *)iodev; @@ -2008,7 +1906,8 @@ static void set_default_hotword_model(struct cras_iodev *iodev) return; } -static int get_valid_frames(struct cras_iodev *odev, struct timespec *tstamp) +static int get_valid_frames(const struct cras_iodev *odev, + struct timespec *tstamp) { struct alsa_io *aio = (struct alsa_io *)odev; int rc; @@ -2035,26 +1934,15 @@ static int get_valid_frames(struct cras_iodev *odev, struct timespec *tstamp) return 0; } -static int support_noise_cancellation(const struct cras_iodev *iodev) -{ - struct alsa_io *aio = (struct alsa_io *)iodev; - - if (!aio->ucm || !iodev->active_node) - return 0; - - return ucm_node_noise_cancellation_exists(aio->ucm, - iodev->active_node->name); -} - /* * Exported Interface. */ struct cras_iodev * alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index, - const char *pcm_name, const char *dev_name, - const char *dev_id, enum CRAS_ALSA_CARD_TYPE card_type, - int is_first, struct cras_alsa_mixer *mixer, + const char *dev_name, const char *dev_id, + enum CRAS_ALSA_CARD_TYPE card_type, int is_first, + struct cras_alsa_mixer *mixer, const struct cras_card_config *config, struct cras_use_case_mgr *ucm, snd_hctl_t *hctl, enum CRAS_STREAM_DIRECTION direction, size_t usb_vid, @@ -2077,6 +1965,7 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index, aio->is_first = is_first; aio->handle = NULL; aio->num_severe_underruns = 0; + aio->jack_always_plugged = 0; if (dev_name) { aio->dev_name = strdup(dev_name); if (!aio->dev_name) @@ -2089,10 +1978,11 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index, } aio->free_running = 0; aio->filled_zeros_for_draining = 0; - aio->has_dependent_dev = 0; - aio->pcm_name = strdup(pcm_name); - if (aio->pcm_name == NULL) + aio->dev = (char *)malloc(MAX_ALSA_DEV_NAME_LENGTH); + if (aio->dev == NULL) goto cleanup_iodev; + snprintf(aio->dev, MAX_ALSA_DEV_NAME_LENGTH, "hw:%zu,%zu", card_index, + device_index); if (direction == CRAS_STREAM_INPUT) { aio->alsa_stream = SND_PCM_STREAM_CAPTURE; @@ -2120,10 +2010,10 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index, iodev->get_hotword_models = get_hotword_models; iodev->no_stream = no_stream; iodev->is_free_running = is_free_running; + iodev->get_num_underruns = get_num_underruns; iodev->get_num_severe_underruns = get_num_severe_underruns; iodev->get_valid_frames = get_valid_frames; iodev->set_swap_mode_for_node = cras_iodev_dsp_set_swap_mode_for_node; - iodev->support_noise_cancellation = support_noise_cancellation; if (card_type == ALSA_CARD_TYPE_USB) iodev->min_buffer_level = USB_EXTRA_BUFFER_FRAMES; @@ -2131,7 +2021,6 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index, iodev->ramp = cras_ramp_create(); if (iodev->ramp == NULL) goto cleanup_iodev; - iodev->initial_ramp_request = CRAS_IODEV_RAMP_REQUEST_UP_START_PLAYBACK; aio->mixer = mixer; aio->config = config; @@ -2148,6 +2037,8 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index, unsigned int level; int rc; + aio->dsp_name_default = + ucm_get_dsp_name_default(ucm, direction); /* Set callback for swap mode if it is supported * in ucm modifier. */ if (ucm_swap_mode_exists(ucm)) @@ -2157,6 +2048,8 @@ 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, @@ -2270,9 +2163,6 @@ int alsa_iodev_legacy_complete_init(struct cras_iodev *iodev) set_default_hotword_model(iodev); - /* Record max supported channels into cras_iodev_info. */ - update_max_supported_channels(iodev); - return 0; } @@ -2288,17 +2178,9 @@ int alsa_iodev_ucm_add_nodes_and_jacks(struct cras_iodev *iodev, if (!aio || !section) return -EINVAL; - - /* Allow this section to add as a new node only if the device id - * or dependent device id matches this iodev. */ - if (((uint32_t)section->dev_idx != aio->device_index) && - ((uint32_t)section->dependent_dev_idx != aio->device_index)) + if ((uint32_t)section->dev_idx != aio->device_index) return -EINVAL; - /* Set flag has_dependent_dev for the case of dependent device. */ - if (section->dependent_dev_idx != -1) - aio->has_dependent_dev = 1; - /* This iodev is fully specified. Avoid automatic node creation. */ aio->fully_specified = 1; @@ -2315,14 +2197,15 @@ int alsa_iodev_ucm_add_nodes_and_jacks(struct cras_iodev *iodev, output_node = new_output(aio, control, section->name); if (!output_node) return -ENOMEM; - output_node->pcm_name = strdup(section->pcm_name); } else if (iodev->direction == CRAS_STREAM_INPUT) { input_node = new_input(aio, control, section->name); if (!input_node) return -ENOMEM; - input_node->pcm_name = strdup(section->pcm_name); } + if (section->jack_type && !strcmp(section->jack_type, "always")) + aio->jack_always_plugged = 1; + /* Find any jack controls for this device. */ rc = cras_alsa_jack_list_add_jack_for_section(aio->jack_list, section, &jack); @@ -2347,7 +2230,6 @@ int alsa_iodev_ucm_add_nodes_and_jacks(struct cras_iodev *iodev, void alsa_iodev_ucm_complete_init(struct cras_iodev *iodev) { struct alsa_io *aio = (struct alsa_io *)iodev; - struct cras_ionode *node; if (!iodev) return; @@ -2365,22 +2247,15 @@ void alsa_iodev_ucm_complete_init(struct cras_iodev *iodev) /* * Set plugged for the USB device per card when it appears if - * there is no jack reporting plug status + * there is no jack reporting plug status and the jack is set + * to be always plugged. */ - if (aio->card_type == ALSA_CARD_TYPE_USB) { - DL_FOREACH (iodev->nodes, node) { - if (!get_jack_from_node(node)) - cras_iodev_set_node_plugged(node, 1); - } + if (aio->card_type == ALSA_CARD_TYPE_USB && aio->jack_always_plugged && + !get_jack_from_node(iodev->active_node)) { + cras_iodev_set_node_plugged(iodev->active_node, 1); } set_default_hotword_model(iodev); - - node = iodev->active_node; - - /* Record max supported channels into cras_iodev_info. */ - if (node && node->plugged) - update_max_supported_channels(iodev); } void alsa_iodev_destroy(struct cras_iodev *iodev) @@ -2444,10 +2319,12 @@ static int alsa_iodev_set_active_node(struct cras_iodev *iodev, unsigned dev_enabled) { struct alsa_io *aio = (struct alsa_io *)iodev; - int rc = 0; - if (iodev->active_node == ionode) - goto skip; + if (iodev->active_node == ionode) { + enable_active_ucm(aio, dev_enabled); + init_device_settings(aio); + return 0; + } /* Disable jack ucm before switching node. */ enable_active_ucm(aio, 0); @@ -2457,16 +2334,7 @@ static int alsa_iodev_set_active_node(struct cras_iodev *iodev, cras_iodev_set_active_node(iodev, ionode); aio->base.dsp_name = get_active_dsp_name(aio); cras_iodev_update_dsp(iodev); -skip: enable_active_ucm(aio, dev_enabled); - if (ionode->type == CRAS_NODE_TYPE_HOTWORD) { - if (dev_enabled) { - rc = ucm_enable_hotword_model(aio->ucm); - if (rc < 0) - return rc; - } else - ucm_disable_all_hotword_models(aio->ucm); - } /* Setting the volume will also unmute if the system isn't muted. */ init_device_settings(aio); return 0; |