summaryrefslogtreecommitdiffstats
path: root/src/modules/alsa
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/alsa')
-rw-r--r--src/modules/alsa/alsa-sink.c22
-rw-r--r--src/modules/alsa/alsa-source.c20
-rw-r--r--src/modules/alsa/alsa-util.c63
-rw-r--r--src/modules/alsa/alsa-util.h12
4 files changed, 89 insertions, 28 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 401b003f..2fbcd7be 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -483,7 +483,13 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
}
}
- *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) - process_usec;
+ *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec);
+
+ if (*sleep_usec > process_usec)
+ *sleep_usec -= process_usec;
+ else
+ *sleep_usec = 0;
+
return work_done ? 1 : 0;
}
@@ -605,7 +611,13 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
}
}
- *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) - process_usec;
+ *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec);
+
+ if (*sleep_usec > process_usec)
+ *sleep_usec -= process_usec;
+ else
+ *sleep_usec = 0;
+
return work_done ? 1 : 0;
}
@@ -919,7 +931,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
return 0;
if (mask & SND_CTL_EVENT_MASK_VALUE) {
- pa_sink_get_volume(u->sink, TRUE);
+ pa_sink_get_volume(u->sink, TRUE, FALSE);
pa_sink_get_mute(u->sink, TRUE);
}
@@ -1652,7 +1664,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
/* ALSA might tweak the sample spec, so recalculate the frame size */
frame_size = pa_frame_size(&ss);
- pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL));
+ pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile);
pa_sink_new_data_init(&data);
data.driver = driver;
@@ -1662,7 +1674,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
- pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
+ pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle, u->mixer_elem);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 99e825c4..c59fc75f 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -465,7 +465,13 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
}
}
- *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec) - process_usec;
+ *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec);
+
+ if (*sleep_usec > process_usec)
+ *sleep_usec -= process_usec;
+ else
+ *sleep_usec = 0;
+
return work_done ? 1 : 0;
}
@@ -575,7 +581,13 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
}
}
- *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec) - process_usec;
+ *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec);
+
+ if (*sleep_usec > process_usec)
+ *sleep_usec -= process_usec;
+ else
+ *sleep_usec = 0;
+
return work_done ? 1 : 0;
}
@@ -1507,7 +1519,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
/* ALSA might tweak the sample spec, so recalculate the frame size */
frame_size = pa_frame_size(&ss);
- pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL));
+ pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile);
pa_source_new_data_init(&data);
data.driver = driver;
@@ -1517,7 +1529,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
pa_source_new_data_set_sample_spec(&data, &ss);
pa_source_new_data_set_channel_map(&data, &map);
- pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
+ pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle, u->mixer_elem);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index fbf88b08..d2dc6e87 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -529,39 +529,51 @@ static const struct pa_alsa_profile_info device_table[] = {
"hw",
N_("Analog Mono"),
"analog-mono",
- 1 },
+ 1,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
"front",
N_("Analog Stereo"),
"analog-stereo",
- 10 },
+ 10,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
"iec958",
N_("Digital Stereo (IEC958)"),
"iec958-stereo",
- 5 },
+ 5,
+ "IEC958", NULL,
+ "IEC958 In", NULL },
{{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
"hdmi",
N_("Digital Stereo (HDMI)"),
"hdmi-stereo",
- 4 },
+ 4,
+ "IEC958", NULL,
+ "IEC958 In", NULL },
{{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
"surround40",
N_("Analog Surround 4.0"),
"analog-surround-40",
- 7 },
+ 7,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
"a52",
N_("Digital Surround 4.0 (IEC958/AC3)"),
"iec958-ac3-surround-40",
- 2 },
+ 2,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -569,7 +581,9 @@ static const struct pa_alsa_profile_info device_table[] = {
"surround41",
N_("Analog Surround 4.1"),
"analog-surround-41",
- 7 },
+ 7,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -577,7 +591,9 @@ static const struct pa_alsa_profile_info device_table[] = {
"surround50",
N_("Analog Surround 5.0"),
"analog-surround-50",
- 7 },
+ 7,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -585,7 +601,9 @@ static const struct pa_alsa_profile_info device_table[] = {
"surround51",
N_("Analog Surround 5.1"),
"analog-surround-51",
- 8 },
+ 8,
+ "Master", "PCM",
+ "Capture", "Mic" },
{{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -593,7 +611,9 @@ static const struct pa_alsa_profile_info device_table[] = {
"a52",
N_("Digital Surround 5.1 (IEC958/AC3)"),
"iec958-ac3-surround-51",
- 3 },
+ 3,
+ "IEC958", NULL,
+ "IEC958 In", NULL },
{{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -602,9 +622,11 @@ static const struct pa_alsa_profile_info device_table[] = {
"surround71",
N_("Analog Surround 7.1"),
"analog-surround-71",
- 7 },
+ 7,
+ "Master", "PCM",
+ "Capture", "Mic" },
- {{ 0, { 0 }}, NULL, NULL, NULL, 0 }
+ {{ 0, { 0 }}, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
};
snd_pcm_t *pa_alsa_open_by_device_id_auto(
@@ -1095,7 +1117,8 @@ int pa_alsa_find_mixer_and_elem(
snd_pcm_t *pcm,
snd_mixer_t **_m,
snd_mixer_elem_t **_e,
- const char *control_name) {
+ const char *control_name,
+ const pa_alsa_profile_info *profile) {
int err;
snd_mixer_t *m;
@@ -1107,6 +1130,11 @@ int pa_alsa_find_mixer_and_elem(
pa_assert(_m);
pa_assert(_e);
+ if (control_name && *control_name == 0) {
+ pa_log_debug("Hardware mixer usage disabled because empty control name passed");
+ return -1;
+ }
+
if ((err = snd_mixer_open(&m, 0)) < 0) {
pa_log("Error opening mixer: %s", snd_strerror(err));
return -1;
@@ -1149,6 +1177,8 @@ int pa_alsa_find_mixer_and_elem(
case SND_PCM_STREAM_PLAYBACK:
if (control_name)
e = pa_alsa_find_elem(m, control_name, NULL, TRUE);
+ else if (profile)
+ e = pa_alsa_find_elem(m, profile->playback_control_name, profile->playback_control_fallback, TRUE);
else
e = pa_alsa_find_elem(m, "Master", "PCM", TRUE);
break;
@@ -1156,6 +1186,8 @@ int pa_alsa_find_mixer_and_elem(
case SND_PCM_STREAM_CAPTURE:
if (control_name)
e = pa_alsa_find_elem(m, control_name, NULL, FALSE);
+ else if (profile)
+ e = pa_alsa_find_elem(m, profile->record_control_name, profile->record_control_fallback, FALSE);
else
e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE);
break;
@@ -1483,7 +1515,7 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *
pa_alsa_init_proplist_card(c, p, card);
}
-void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
+void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem) {
snd_pcm_hw_params_t *hwparams;
snd_pcm_info_t *info;
int bits, err;
@@ -1499,6 +1531,9 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
}
+ if (elem)
+ pa_proplist_sets(p, "alsa.mixer_element", snd_mixer_selem_get_name(elem));
+
if ((err = snd_pcm_info(pcm, info)) < 0)
pa_log_warn("Error fetching PCM info: %s", snd_strerror(err));
else
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index 9fce6daf..c8acc7c9 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -53,18 +53,20 @@ int pa_alsa_set_hw_params(
int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min);
-int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev);
-snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback);
-int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name);
-
typedef struct pa_alsa_profile_info {
pa_channel_map map;
const char *alsa_name;
const char *description; /* internationalized */
const char *name;
unsigned priority;
+ const char *playback_control_name, *playback_control_fallback;
+ const char *record_control_name, *record_control_fallback;
} pa_alsa_profile_info;
+int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev);
+snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback);
+int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name, const pa_alsa_profile_info*profile);
+
/* Picks a working profile based on the specified ss/map */
snd_pcm_t *pa_alsa_open_by_device_id_auto(
const char *dev_id,
@@ -123,7 +125,7 @@ void pa_alsa_redirect_errors_dec(void);
void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info);
void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card);
-void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm);
+void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem);
pa_bool_t pa_alsa_init_description(pa_proplist *p);
int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);