From patchwork Fri Mar 16 09:33:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feng Wei X-Patchwork-Id: 7331 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id E517B23E13 for ; Fri, 16 Mar 2012 09:33:58 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 8E54DA18286 for ; Fri, 16 Mar 2012 09:33:58 +0000 (UTC) Received: by mail-iy0-f180.google.com with SMTP id e36so6920755iag.11 for ; Fri, 16 Mar 2012 02:33:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :x-spamscore:x-bigfish:x-forefront-antispam-report :x-fb-domain-ip-match:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:mime-version:content-type:x-originatororg :x-gm-message-state; bh=ROPENRAqNpsSj+lVVbXu22xa34L/GluWtfiYtS2dxOU=; b=A3r3mKH5+wSKk0572EfxxZD3QcqQKeGbPDrs8VD6u8MBd8tIVky/wf2gJxmDgFd7qQ 9QfLjIiXJTay0IL7QB97bf7dgGOv2SlBSPNybHOgI/xOODNAYy9pNDdQ8Cmn2vMaD2wa WGMno0XN9j+XKcBkOBrwLZzi0qznbz/rAU4xrkCrFTyETWxDT305VXO8Ud07PuIY8Xj8 BhZpNxUnpGASTq9WBlBavE3a9TUYqCUDzfYDtXAkVU1ZmrI6htrpH285WCyECJRINjOB pcD1gZSFdOPhKvCs/fYu8IuU7Hj0b2snNltRkfopKZBJ3CWSwsSGAyJwxF7E6JNmozBL Cf2A== Received: by 10.50.197.132 with SMTP id iu4mr1783643igc.74.1331890438296; Fri, 16 Mar 2012 02:33:58 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.53.18 with SMTP id k18csp3860ibg; Fri, 16 Mar 2012 02:33:57 -0700 (PDT) Received: by 10.180.19.196 with SMTP id h4mr4847078wie.12.1331890436429; Fri, 16 Mar 2012 02:33:56 -0700 (PDT) Received: from db3outboundpool.messaging.microsoft.com (db3ehsobe003.messaging.microsoft.com. [213.199.154.141]) by mx.google.com with ESMTPS id l33si5186587weq.6.2012.03.16.02.33.55 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 16 Mar 2012 02:33:56 -0700 (PDT) Received-SPF: neutral (google.com: 213.199.154.141 is neither permitted nor denied by best guess record for domain of feng.wei@linaro.org) client-ip=213.199.154.141; Authentication-Results: mx.google.com; spf=neutral (google.com: 213.199.154.141 is neither permitted nor denied by best guess record for domain of feng.wei@linaro.org) smtp.mail=feng.wei@linaro.org Received: from mail15-db3-R.bigfish.com (10.3.81.230) by DB3EHSOBE002.bigfish.com (10.3.84.22) with Microsoft SMTP Server id 14.1.225.23; Fri, 16 Mar 2012 09:33:55 +0000 Received: from mail15-db3 (localhost [127.0.0.1]) by mail15-db3-R.bigfish.com (Postfix) with ESMTP id 3A4573607A7; Fri, 16 Mar 2012 09:33:55 +0000 (UTC) X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzzz2dh87h2a8h668h839hd24h) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-FB-DOMAIN-IP-MATCH: fail Received: from mail15-db3 (localhost.localdomain [127.0.0.1]) by mail15-db3 (MessageSwitch) id 1331890432297884_339; Fri, 16 Mar 2012 09:33:52 +0000 (UTC) Received: from DB3EHSMHS011.bigfish.com (unknown [10.3.81.243]) by mail15-db3.bigfish.com (Postfix) with ESMTP id 45A111800ED; Fri, 16 Mar 2012 09:33:52 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by DB3EHSMHS011.bigfish.com (10.3.87.111) with Microsoft SMTP Server (TLS) id 14.1.225.23; Fri, 16 Mar 2012 09:33:51 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-003.039d.mgd.msft.net (10.84.1.16) with Microsoft SMTP Server (TLS) id 14.1.355.3; Fri, 16 Mar 2012 04:33:50 -0500 Received: from wayne-Latitude-E6410.ap.freescale.net ([10.213.130.145]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id q2G9XdSi018483; Fri, 16 Mar 2012 02:33:48 -0700 From: Feng Wei To: CC: , , , Feng Wei Subject: [pulseaudio-discuss][RFC PATCH v2] Add UCM jack detection into alsa card module Date: Fri, 16 Mar 2012 17:33:10 +0800 Message-ID: <1331890390-24053-2-git-send-email-feng.wei@linaro.org> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1331890390-24053-1-git-send-email-feng.wei@linaro.org> References: <1331890390-24053-1-git-send-email-feng.wei@linaro.org> MIME-Version: 1.0 X-OriginatorOrg: sigmatel.com X-Gm-Message-State: ALoCoQm9KNqCztGBImkqBJPehjS1fY76u4iWHwgTmzas28u6+/0VAc/1NBfuyv2Qqa/HXoQNv4w7 Jack in UCM is decided by UCM device name, although in fact not all UCM devices have "jacks". Because port is also mapped to UCM device, we can always find target port when some jack event happens. --- src/modules/alsa/alsa-mixer.c | 32 ++++-- src/modules/alsa/alsa-mixer.h | 1 + src/modules/alsa/alsa-ucm.c | 197 +++++++++++++++++++++++++++++++++-- src/modules/alsa/alsa-ucm.h | 8 ++ src/modules/alsa/module-alsa-card.c | 54 +++++++--- 5 files changed, 255 insertions(+), 37 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 317fe12..39a4633 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -3294,7 +3294,7 @@ static void mapping_free(pa_alsa_mapping *m) { pa_assert(!m->input_pcm); pa_assert(!m->output_pcm); - pa_xfree(m->ucm_context.ucm_devices); + ucm_mapping_context_free(&m->ucm_context); pa_xfree(m); } @@ -4449,17 +4449,7 @@ void pa_alsa_profile_set_probe( /* Clean up */ profile_finalize_probing(last, NULL); - PA_HASHMAP_FOREACH(p, ps->profiles, state) - if (!p->supported) { - pa_hashmap_remove(ps->profiles, p->name); - profile_free(p); - } - - PA_HASHMAP_FOREACH(m, ps->mappings, state) - if (m->supported <= 0) { - pa_hashmap_remove(ps->mappings, m->name); - mapping_free(m); - } + pa_alsa_profile_set_drop_unsupported(ps); paths_drop_unsupported(ps->input_paths); paths_drop_unsupported(ps->output_paths); @@ -4494,6 +4484,24 @@ void pa_alsa_profile_set_dump(pa_alsa_profile_set *ps) { pa_alsa_decibel_fix_dump(db_fix); } +void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *ps) { + pa_alsa_profile *p; + pa_alsa_mapping *m; + void *state; + + PA_HASHMAP_FOREACH(p, ps->profiles, state) + if (!p->supported) { + pa_hashmap_remove(ps->profiles, p->name); + profile_free(p); + } + + PA_HASHMAP_FOREACH(m, ps->mappings, state) + if (m->supported <= 0) { + pa_hashmap_remove(ps->mappings, m->name); + mapping_free(m); + } +} + static pa_device_port* device_port_alsa_init(pa_hashmap *ports, const char* name, const char* description, diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index 4234a2b..c640915 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -323,6 +323,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec); void pa_alsa_profile_set_free(pa_alsa_profile_set *s); void pa_alsa_profile_set_dump(pa_alsa_profile_set *s); +void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s); snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device, snd_hctl_t **hctl); diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 2d299e3..705518b 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -590,6 +590,7 @@ static void ucm_add_port_combination(pa_hashmap *hash, pa_alsa_ucm_mapping_conte pa_log_debug("Add port %s: %s", port->name, port->description); port->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); } + port->priority = priority; if (is_sink) port->is_output = TRUE; @@ -926,8 +927,8 @@ static int ucm_create_mapping_direction(struct pa_alsa_ucm_config *ucm, channels = is_sink ? device->playback_channels : device->capture_channels; if (m->ucm_context.ucm_devices_num == 0) { /* new mapping */ - m->supported = TRUE; m->ucm_context.ucm = ucm; + m->ucm_context.direction = is_sink ? PA_ALSA_UCM_DIRECT_SINK : PA_ALSA_UCM_DIRECT_SOURCE; m->device_strings = pa_xnew0(char*, 2); m->device_strings[0] = pa_xstrdup(device_str); @@ -970,6 +971,24 @@ static int ucm_create_mapping(struct pa_alsa_ucm_config *ucm, return ret; } +static pa_alsa_jack* ucm_get_jack(struct pa_alsa_ucm_config *ucm, const char *dev_name) { + pa_alsa_jack *j; + + PA_LLIST_FOREACH(j, ucm->jacks) + if (pa_streq(j->name, dev_name)) + return j; + + j = pa_xnew0(pa_alsa_jack, 1); + j->state_unplugged = PA_PORT_AVAILABLE_NO; + j->state_plugged = PA_PORT_AVAILABLE_YES; + j->name = pa_xstrdup(dev_name); + j->alsa_name = pa_sprintf_malloc("%s Jack", dev_name); + + PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j); + + return j; +} + static int ucm_create_profile(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, struct pa_alsa_ucm_verb *verb, const char *verb_name, const char *verb_desc) { struct pa_alsa_profile *p; @@ -991,7 +1010,7 @@ static int ucm_create_profile(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_se p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - p->supported = 1; + p->supported = TRUE; pa_hashmap_put(ps->profiles, p->name, p); /* TODO: get profile priority from ucm info or policy management */ @@ -1026,12 +1045,146 @@ static int ucm_create_profile(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_se source = pa_proplist_gets(dev->proplist, PA_PROP_UCM_SOURCE); ucm_create_mapping(ucm, ps, p, dev, verb_name, dev_name, sink, source); + dev->jack = ucm_get_jack(ucm, dev_name); } pa_alsa_profile_dump(p); return 0; } +static snd_pcm_t* mapping_open_pcm(struct pa_alsa_ucm_config *ucm, + pa_alsa_mapping *m, int mode) { + pa_sample_spec try_ss = ucm->core->default_sample_spec; + pa_channel_map try_map = m->channel_map; + snd_pcm_uframes_t try_period_size, try_buffer_size; + + try_ss.channels = try_map.channels; + + try_period_size = + pa_usec_to_bytes(ucm->core->default_fragment_size_msec * PA_USEC_PER_MSEC, &try_ss) / + pa_frame_size(&try_ss); + try_buffer_size = ucm->core->default_n_fragments * try_period_size; + + return pa_alsa_open_by_device_string(m->device_strings[0], NULL, &try_ss, + &try_map, mode, &try_period_size, + &try_buffer_size, 0, NULL, NULL, TRUE); +} + +static void profile_finalize_probing(pa_alsa_profile *p) { + pa_alsa_mapping *m; + uint32_t idx; + + PA_IDXSET_FOREACH(m, p->output_mappings, idx) { + if (!m->output_pcm) + continue; + + if (p->supported) + m->supported++; + + snd_pcm_close(m->output_pcm); + m->output_pcm = NULL; + } + + PA_IDXSET_FOREACH(m, p->input_mappings, idx) { + if (!m->input_pcm) + continue; + + if (p->supported) + m->supported++; + + snd_pcm_close(m->input_pcm); + m->input_pcm = NULL; + } +} + +static struct pa_alsa_ucm_device *find_ucm_dev( + struct pa_alsa_ucm_verb *verb, const char *dev_name) { + struct pa_alsa_ucm_device *dev; + + PA_LLIST_FOREACH(dev, verb->devices) { + const char *name = pa_proplist_gets(dev->proplist, PA_PROP_UCM_NAME); + if (pa_streq(name, dev_name)) + return dev; + } + + return NULL; +} + +static void ucm_mapping_jack_probe(pa_alsa_mapping *m) { + snd_pcm_t *pcm_handle; + snd_mixer_t *mixer_handle; + snd_hctl_t *hctl_handle; + pa_alsa_ucm_mapping_context *context = &m->ucm_context; + struct pa_alsa_ucm_device *dev; + int i; + + pcm_handle = m->direction == PA_ALSA_DIRECTION_OUTPUT ? m->output_pcm : m->input_pcm; + mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL, &hctl_handle); + if (!mixer_handle || !hctl_handle) + return; + + for (i=0; iucm_devices_num; i++) { + dev = context->ucm_devices[i]; + pa_assert (dev->jack); + dev->jack->has_control = pa_alsa_find_jack(hctl_handle, dev->jack->alsa_name) != NULL; + pa_log_info("ucm_mapping_jack_probe: %s has_control=%d", dev->jack->name, dev->jack->has_control); + } + + snd_mixer_close(mixer_handle); +} + +static void ucm_probe_jacks(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps) { + void *state; + pa_alsa_profile *p; + pa_alsa_mapping *m; + uint32_t idx; + + PA_HASHMAP_FOREACH(p, ps->profiles, state) { + /* change verb */ + pa_log_info("ucm_probe_jacks: set ucm verb to %s", p->name); + if ((snd_use_case_set(ucm->ucm_mgr, "_verb", p->name)) < 0) { + pa_log("ucm_probe_jacks: failed to set verb %s", p->name); + p->supported = FALSE; + continue; + } + PA_IDXSET_FOREACH(m, p->output_mappings, idx) { + m->output_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_PLAYBACK); + if (!m->output_pcm) { + p->supported = FALSE; + break; + } + } + if (p->supported) { + PA_IDXSET_FOREACH(m, p->input_mappings, idx) { + m->input_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_CAPTURE); + if (!m->input_pcm) { + p->supported = FALSE; + break; + } + } + } + if (!p->supported) { + profile_finalize_probing(p); + continue; + } + + pa_log_debug("Profile %s supported.", p->name); + + PA_IDXSET_FOREACH(m, p->output_mappings, idx) + ucm_mapping_jack_probe(m); + + PA_IDXSET_FOREACH(m, p->input_mappings, idx) + ucm_mapping_jack_probe(m); + + profile_finalize_probing(p); + } + + /* restore ucm state */ + snd_use_case_set(ucm->ucm_mgr, "_verb", SND_USE_CASE_VERB_INACTIVE); + + pa_alsa_profile_set_drop_unsupported(ps); +} + pa_alsa_profile_set* ucm_add_profile_set(struct pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map) { struct pa_alsa_ucm_verb *verb; pa_alsa_profile_set *ps; @@ -1055,6 +1208,8 @@ pa_alsa_profile_set* ucm_add_profile_set(struct pa_alsa_ucm_config *ucm, pa_chan ucm_create_profile(ucm, ps, verb, verb_name, verb_desc); } + + ucm_probe_jacks(ucm, ps); ps->probed = TRUE; return ps; @@ -1090,11 +1245,18 @@ static void free_verb(struct pa_alsa_ucm_verb *verb) { void ucm_free(struct pa_alsa_ucm_config *ucm) { struct pa_alsa_ucm_verb *vi, *vn; + pa_alsa_jack *ji, *jn; PA_LLIST_FOREACH_SAFE(vi, vn, ucm->verbs) { PA_LLIST_REMOVE(pa_alsa_ucm_verb, ucm->verbs, vi); free_verb(vi); } + PA_LLIST_FOREACH_SAFE(ji, jn, ucm->jacks) { + PA_LLIST_REMOVE(pa_alsa_jack, ucm->jacks, ji); + pa_xfree(ji->alsa_name); + pa_xfree(ji->name); + pa_xfree(ji); + } if (ucm->ucm_mgr) { snd_use_case_mgr_close(ucm->ucm_mgr); @@ -1102,6 +1264,22 @@ void ucm_free(struct pa_alsa_ucm_config *ucm) { } } +void ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context) { + struct pa_alsa_ucm_device *dev; + int i; + + /* clear ucm device pointer to mapping */ + for (i=0; iucm_devices_num; i++) { + dev = context->ucm_devices[i]; + if (context->direction == PA_ALSA_UCM_DIRECT_SINK) + dev->playback_mapping = NULL; + else + dev->capture_mapping = NULL; + } + + pa_xfree(context->ucm_devices); +} + static pa_bool_t stream_routed_to_mod_intent (struct pa_alsa_ucm_verb *verb, struct pa_alsa_ucm_modifier *mod, const char *mapping_name) { int i; @@ -1113,15 +1291,12 @@ static pa_bool_t stream_routed_to_mod_intent (struct pa_alsa_ucm_verb *verb, for (i=0; in_suppdev; i++) { dev_name = mod->supported_devices[i]; /* first find the supported device */ - PA_LLIST_FOREACH(dev, verb->devices) { - const char *name = pa_proplist_gets(dev->proplist, PA_PROP_UCM_NAME); - if (pa_streq(name, dev_name)) { - /* then match the mapping name */ - mapping = mod->action_direct == PA_ALSA_UCM_DIRECT_SINK ? dev->playback_mapping : dev->capture_mapping; - if (mapping && pa_streq(mapping->name, mapping_name)) - return TRUE; - break; - } + dev = find_ucm_dev(verb, dev_name); + if (dev) { + /* then match the mapping name */ + mapping = mod->action_direct == PA_ALSA_UCM_DIRECT_SINK ? dev->playback_mapping : dev->capture_mapping; + if (mapping && pa_streq(mapping->name, mapping_name)) + return TRUE; } } diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 680be5a..625de18 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -27,6 +27,8 @@ #include #include +typedef struct pa_core pa_core; +typedef struct pa_device_port pa_device_port; typedef struct pa_alsa_mapping pa_alsa_mapping; typedef struct pa_alsa_ucm_verb pa_alsa_ucm_verb; @@ -35,9 +37,11 @@ typedef struct pa_alsa_ucm_device pa_alsa_ucm_device; typedef struct pa_alsa_ucm_config pa_alsa_ucm_config; typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context; typedef struct pa_alsa_port_data_ucm pa_alsa_port_data_ucm; +typedef struct pa_alsa_jack pa_alsa_jack; int ucm_set_profile(struct pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile); void ucm_free(struct pa_alsa_ucm_config *ucm); +void ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context); pa_alsa_profile_set* ucm_add_profile_set(struct pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map); int ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, struct pa_alsa_ucm_verb ** p_verb); void ucm_add_ports(pa_hashmap **p, pa_proplist *proplist, pa_alsa_ucm_mapping_context *context, int is_sink, pa_card *card); @@ -70,6 +74,7 @@ struct pa_alsa_ucm_device { int n_suppdev; char **conflicting_devices; char **supported_devices; + pa_alsa_jack *jack; }; struct pa_alsa_ucm_modifier { @@ -94,14 +99,17 @@ struct pa_alsa_ucm_verb { }; struct pa_alsa_ucm_config { + pa_core *core; snd_use_case_mgr_t *ucm_mgr; pa_alsa_ucm_verb *active_verb; PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs); + PA_LLIST_HEAD(pa_alsa_jack, jacks); }; struct pa_alsa_ucm_mapping_context { pa_alsa_ucm_config *ucm; + int direction; int ucm_devices_num; pa_alsa_ucm_device **ucm_devices; }; diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index d7f1043..659bddb 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -326,14 +326,22 @@ static void report_port_state(pa_device_port *p, struct userdata *u) void *state; pa_alsa_jack *jack; pa_port_available_t pa = PA_PORT_AVAILABLE_UNKNOWN; + pa_device_port *port; PA_HASHMAP_FOREACH(jack, u->jacks, state) { pa_port_available_t cpa; - if (!jack->path) - continue; + if (u->use_ucm) { + port = pa_hashmap_get(u->card->ports, jack->name); + } + else { + if (jack->path) + port = jack->path->port; + else + continue; + } - if (p != jack->path->port) + if (p != port) continue; cpa = jack->plugged_in ? jack->state_plugged : jack->state_unplugged; @@ -359,6 +367,7 @@ static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask) pa_bool_t plugged_in; void *state; pa_alsa_jack *jack; + pa_device_port *port; pa_assert(u); @@ -378,8 +387,16 @@ static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask) PA_HASHMAP_FOREACH(jack, u->jacks, state) if (jack->hctl_elem == elem) { jack->plugged_in = plugged_in; - pa_assert(jack->path && jack->path->port); - report_port_state(jack->path->port, u); + if (u->use_ucm) { + pa_assert(u->card->ports); + port = pa_hashmap_get(u->card->ports, jack->name); + pa_assert(port); + } + else { + pa_assert(jack->path && jack->path->port); + port = jack->path->port; + } + report_port_state(port, u); } return 0; } @@ -391,18 +408,25 @@ static void init_jacks(struct userdata *u) { u->jacks = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - /* See if we have any jacks */ - if (u->profile_set->output_paths) - PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state) - PA_LLIST_FOREACH(jack, path->jacks) + if (u->use_ucm) { + PA_LLIST_FOREACH(jack, u->ucm.jacks) + if (jack->has_control) + pa_hashmap_put(u->jacks, jack, jack); + } + else { + /* See if we have any jacks */ + if (u->profile_set->output_paths) + PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state) + PA_LLIST_FOREACH(jack, path->jacks) if (jack->has_control) pa_hashmap_put(u->jacks, jack, jack); - if (u->profile_set->input_paths) - PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state) - PA_LLIST_FOREACH(jack, path->jacks) + if (u->profile_set->input_paths) + PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state) + PA_LLIST_FOREACH(jack, path->jacks) if (jack->has_control) pa_hashmap_put(u->jacks, jack, jack); + } pa_log_debug("Found %d jacks.", pa_hashmap_size(u->jacks)); @@ -652,6 +676,8 @@ int pa__init(pa_module *m) { u->device_id = pa_xstrdup(pa_modargs_get_value(ma, "device_id", DEFAULT_DEVICE_ID)); u->modargs = ma; + u->ucm.core = m->core; + if ((u->alsa_card_index = snd_card_get_index(u->device_id)) < 0) { pa_log("Card '%s' doesn't exist: %s", u->device_id, pa_alsa_strerror(u->alsa_card_index)); goto fail; @@ -881,8 +907,6 @@ void pa__done(pa_module*m) { pa_alsa_source_free(s); } - ucm_free(&u->ucm); - if (u->card) pa_card_free(u->card); @@ -892,6 +916,8 @@ void pa__done(pa_module*m) { if (u->profile_set) pa_alsa_profile_set_free(u->profile_set); + ucm_free(&u->ucm); + pa_xfree(u->device_id); pa_xfree(u);