From patchwork Fri May 18 10:06:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feng Wei X-Patchwork-Id: 8806 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 3FDBD23EAB for ; Fri, 18 May 2012 10:07:54 +0000 (UTC) Received: from mail-yw0-f52.google.com (mail-yw0-f52.google.com [209.85.213.52]) by fiordland.canonical.com (Postfix) with ESMTP id EC68EA18C49 for ; Fri, 18 May 2012 10:07:53 +0000 (UTC) Received: by mail-yw0-f52.google.com with SMTP id p61so3213306yhp.11 for ; Fri, 18 May 2012 03:07:53 -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=aEKlV0kr+iGOf16RB+WYxK+k7Ogms36muVhgFJ6x7n0=; b=mD7erkB38E9vrE+dei2e/zC8jTUAbpLEFsC1w3fTO4w+fRoAXh+Ezeoo3xsM27zF/m AydLTA8C+U0myc8xxsAXHTodLfjjGRN7fquCyghte5AI/1u79ozH4NMpDWTfXPhvJWX/ RuBPhUn/9CYwVscv/ex/Lm5qXwKjZemG4w3mWYjAWjViiNEpX9PF3Q2IKcbtQQVT3hX0 W/uEGgdwF158V+P0KR27kJSz4cV7B8FtUUvyuiuwuaYEBdI5qwYMa3ARnNoub58FuhAS RgJTP065MEQXhgArIurS8bQCMhCsa7Tas0D/2z7H8pHx+l00aE/2XlcCxiqcAbGSTfSl yLXw== Received: by 10.50.222.202 with SMTP id qo10mr30914igc.0.1337335673513; Fri, 18 May 2012 03:07:53 -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.35.72 with SMTP id o8csp92192ibd; Fri, 18 May 2012 03:07:53 -0700 (PDT) Received: by 10.42.19.72 with SMTP id a8mr6541936icb.39.1337335672272; Fri, 18 May 2012 03:07:52 -0700 (PDT) Received: from ch1outboundpool.messaging.microsoft.com (ch1ehsobe002.messaging.microsoft.com. [216.32.181.182]) by mx.google.com with ESMTPS id vb2si1306860igc.71.2012.05.18.03.07.52 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 18 May 2012 03:07:52 -0700 (PDT) Received-SPF: neutral (google.com: 216.32.181.182 is neither permitted nor denied by best guess record for domain of feng.wei@linaro.org) client-ip=216.32.181.182; Authentication-Results: mx.google.com; spf=neutral (google.com: 216.32.181.182 is neither permitted nor denied by best guess record for domain of feng.wei@linaro.org) smtp.mail=feng.wei@linaro.org Received: from mail161-ch1-R.bigfish.com (10.43.68.233) by CH1EHSOBE012.bigfish.com (10.43.70.62) with Microsoft SMTP Server id 14.1.225.23; Fri, 18 May 2012 10:07:43 +0000 Received: from mail161-ch1 (localhost [127.0.0.1]) by mail161-ch1-R.bigfish.com (Postfix) with ESMTP id 02E5A260097; Fri, 18 May 2012 10:07:43 +0000 (UTC) X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275dhz2dh87h2a8h668h839hd24he5bhe96hf0ah) 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 mail161-ch1 (localhost.localdomain [127.0.0.1]) by mail161-ch1 (MessageSwitch) id 1337335660205426_595; Fri, 18 May 2012 10:07:40 +0000 (UTC) Received: from CH1EHSMHS027.bigfish.com (snatpool1.int.messaging.microsoft.com [10.43.68.240]) by mail161-ch1.bigfish.com (Postfix) with ESMTP id 2B76E1C0062; Fri, 18 May 2012 10:07:40 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CH1EHSMHS027.bigfish.com (10.43.70.27) with Microsoft SMTP Server (TLS) id 14.1.225.23; Fri, 18 May 2012 10:07:39 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-001.039d.mgd.msft.net (10.84.1.13) with Microsoft SMTP Server (TLS) id 14.2.298.5; Fri, 18 May 2012 05:07:47 -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 q4IA7IVe016083; Fri, 18 May 2012 03:07:44 -0700 From: To: CC: , , , Feng Wei Subject: [RFC PATCH 4/4] Add UCM jack detection into alsa card module Date: Fri, 18 May 2012 18:06:48 +0800 Message-ID: <1337335608-6901-5-git-send-email-feng.wei@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1337335608-6901-1-git-send-email-feng.wei@linaro.org> References: <1337335608-6901-1-git-send-email-feng.wei@linaro.org> MIME-Version: 1.0 X-OriginatorOrg: sigmatel.com X-Gm-Message-State: ALoCoQn/+guxW8LsSZdGN9sX3bWpSUCz821zVbIbbTNt10NXmtlD7QGahsaM35fqFlaXrhD9PYCI From: Feng Wei 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. Signed-off-by: Feng Wei --- src/modules/alsa/alsa-mixer.c | 32 ++++--- src/modules/alsa/alsa-mixer.h | 1 + src/modules/alsa/alsa-ucm.c | 165 ++++++++++++++++++++++++++++++++++- src/modules/alsa/alsa-ucm.h | 8 ++ src/modules/alsa/module-alsa-card.c | 63 +++++++++---- 5 files changed, 237 insertions(+), 32 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 1151b8d..c0d0e2f 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); + pa_ucm_mapping_context_free(&m->ucm_context); pa_xfree(m); } @@ -4450,17 +4450,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); @@ -4495,6 +4485,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 1e424bd..40d2f2a 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 b74a3e7..7341bc9 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -584,6 +584,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; @@ -910,8 +911,8 @@ static int ucm_create_mapping_direction(pa_alsa_ucm_config *ucm, priority = is_sink ? device->playback_priority : device->capture_priority; 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); @@ -952,6 +953,24 @@ static int ucm_create_mapping(pa_alsa_ucm_config *ucm, return ret; } +static pa_alsa_jack* ucm_get_jack(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(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, pa_alsa_ucm_verb *verb, const char *verb_name, const char *verb_desc) { pa_alsa_profile *p; @@ -1007,12 +1026,56 @@ static int ucm_create_profile(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, 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(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 pa_alsa_ucm_device *find_ucm_dev(pa_alsa_ucm_verb *verb, const char *dev_name) { pa_alsa_ucm_device *dev; @@ -1025,6 +1088,81 @@ static pa_alsa_ucm_device *find_ucm_dev(pa_alsa_ucm_verb *verb, const char *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; + 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(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* pa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map) { pa_alsa_ucm_verb *verb; pa_alsa_profile_set *ps; @@ -1048,6 +1186,8 @@ pa_alsa_profile_set* pa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_ ucm_create_profile(ucm, ps, verb, verb_name, verb_desc); } + + ucm_probe_jacks(ucm, ps); ps->probed = TRUE; return ps; @@ -1083,17 +1223,40 @@ static void free_verb(pa_alsa_ucm_verb *verb) { void pa_ucm_free(pa_alsa_ucm_config *ucm) { 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); ucm->ucm_mgr = NULL; } } +void pa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context) { + 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 (pa_alsa_ucm_verb *verb, pa_alsa_ucm_modifier *mod, const char *mapping_name) { int i; diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 8e2dd71..24f9eec 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; typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier; @@ -34,6 +36,7 @@ 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; pa_alsa_profile_set* pa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map); int pa_ucm_set_profile(pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile); @@ -48,6 +51,7 @@ void pa_ucm_add_ports_combination(pa_hashmap *hash, pa_alsa_ucm_mapping_context int pa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, int is_sink); void pa_ucm_free(pa_alsa_ucm_config *ucm); +void pa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context); void pa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm, const char *role, const char *mapping_name, int is_sink); void pa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, const char *mapping_name, int is_sink); @@ -74,6 +78,7 @@ struct pa_alsa_ucm_device { int n_suppdev; char **conflicting_devices; char **supported_devices; + pa_alsa_jack *jack; }; struct pa_alsa_ucm_modifier { @@ -98,14 +103,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 4802a39..7d8716f 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -326,14 +326,21 @@ 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 +366,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 +386,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 +407,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 (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 (jack->has_control) - pa_hashmap_put(u->jacks, jack, jack); + 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 (jack->has_control) + pa_hashmap_put(u->jacks, jack, jack); + } pa_log_debug("Found %d jacks.", pa_hashmap_size(u->jacks)); @@ -651,6 +674,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; @@ -880,8 +905,6 @@ void pa__done(pa_module*m) { pa_alsa_source_free(s); } - pa_ucm_free(&u->ucm); - if (u->card) pa_card_free(u->card); @@ -891,6 +914,8 @@ void pa__done(pa_module*m) { if (u->profile_set) pa_alsa_profile_set_free(u->profile_set); + pa_ucm_free(&u->ucm); + pa_xfree(u->device_id); pa_xfree(u);