diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index c6f37e04a..a41c216ac 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -2486,6 +2486,24 @@ int acp_device_set_volume(struct acp_device *dev, const float *volume, uint32_t return 0; } +int acp_device_set_volume_updown(struct acp_device *dev, bool up) +{ + pa_alsa_device *d = (pa_alsa_device*)dev; + pa_card *impl = d->card; + + if (!impl->card.ext_volume.client) + return -EINVAL; + + if (!d->active_port) + return -EINVAL; + + pa_log_info("Volume %s", up ? "up" : "down"); + + /* TODO: use step size from capabilities */ + return spa_acp_ext_volume_write_volume_relative(&impl->card.ext_volume, impl->name, + d->active_port->name, up ? 1.0 : -1.0); +} + static int get_volume(pa_cvolume *v, float *volume, uint32_t n_volume) { uint32_t i; @@ -2539,6 +2557,23 @@ int acp_device_get_mute(struct acp_device *dev, bool *mute) return 0; } +int acp_device_toggle_mute(struct acp_device *dev) +{ + pa_alsa_device *d = (pa_alsa_device*)dev; + pa_card *impl = d->card; + + if (!impl->card.ext_volume.client) + return -EINVAL; + + if (!d->active_port) + return -EINVAL; + + pa_log_info("Toggle mute"); + + return spa_acp_ext_volume_write_mute_toggle(&impl->card.ext_volume, impl->name, + d->active_port->name); +} + void acp_set_log_func(acp_log_func func, void *data) { _acp_log_func = func; diff --git a/spa/plugins/alsa/acp/acp.h b/spa/plugins/alsa/acp/acp.h index da305b1ad..491c96991 100644 --- a/spa/plugins/alsa/acp/acp.h +++ b/spa/plugins/alsa/acp/acp.h @@ -308,9 +308,11 @@ uint32_t acp_device_find_best_port_index(struct acp_device *dev, const char *nam int acp_device_set_port(struct acp_device *dev, uint32_t port_index, uint32_t flags); int acp_device_set_volume(struct acp_device *dev, const float *volume, uint32_t n_volume); +int acp_device_set_volume_updown(struct acp_device *dev, bool up); int acp_device_get_soft_volume(struct acp_device *dev, float *volume, uint32_t n_volume); int acp_device_get_volume(struct acp_device *dev, float *volume, uint32_t n_volume); int acp_device_set_mute(struct acp_device *dev, bool mute); +int acp_device_toggle_mute(struct acp_device *dev); int acp_device_get_mute(struct acp_device *dev, bool *mute); typedef void (*acp_log_func) (void *data, diff --git a/spa/plugins/alsa/alsa-acp-device.c b/spa/plugins/alsa/alsa-acp-device.c index b5274670c..38daf6e4b 100644 --- a/spa/plugins/alsa/alsa-acp-device.c +++ b/spa/plugins/alsa/alsa-acp-device.c @@ -893,12 +893,74 @@ static int impl_set_param(void *object, return 0; } +static int impl_send_command(void *object, const struct spa_command *command) +{ + struct impl *this = object; + struct acp_card *card = this->card; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(command != NULL, -EINVAL); + + switch (SPA_DEVICE_COMMAND_ID(command)) { + case SPA_DEVICE_COMMAND_VolumeControl: + { + const struct spa_pod_prop *prop; + + /* We support some volume control commands for external volumes */ + if (card->ext_volume.client == NULL) + return -ENOTSUP; + + SPA_POD_OBJECT_FOREACH(&command->body, prop) { + struct acp_port *port; + struct acp_device *dev = NULL; + uint32_t id, i; + + if (spa_pod_get_id(&prop->value, &id) < 0 || id > card->n_ports) + return -EINVAL; + + port = card->ports[id]; + + for (i = 0; i < port->n_devices; i++) { + if (port->devices[i]->flags & ACP_DEVICE_ACTIVE) { + dev = port->devices[i]; + break; + } + } + + if (dev == NULL) + return -EINVAL; + + switch (prop->key) { + case SPA_COMMAND_DEVICE_volumeUp: + acp_device_set_volume_updown(dev, true); + break; + case SPA_COMMAND_DEVICE_volumeDown: + acp_device_set_volume_updown(dev, false); + break; + case SPA_COMMAND_DEVICE_muteToggle: + acp_device_toggle_mute(dev); + break; + default: + return -ENOTSUP; + } + } + + break; + } + default: + return -ENOTSUP; + } + + return 0; +} + static const struct spa_device_methods impl_device = { SPA_VERSION_DEVICE_METHODS, .add_listener = impl_add_listener, .sync = impl_sync, .enum_params = impl_enum_params, .set_param = impl_set_param, + .send_command = impl_send_command, }; static void card_props_changed(void *data)