mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-06 13:29:56 -05:00
instead of using the mixer ioctl()s on the dsp fd, open a seperate fd for the mixer. This allows us the keep the mixer fd open while closing the dsp device while suspending.
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1893 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
fc00eaf1d4
commit
77ed60ce4c
3 changed files with 292 additions and 194 deletions
|
|
@ -36,8 +36,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/* TODO: handle restoring of volume after suspend */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
|
@ -115,14 +113,14 @@ struct userdata {
|
|||
int use_getospace, use_getispace;
|
||||
int use_getodelay;
|
||||
|
||||
int use_pcm_volume;
|
||||
int use_input_volume;
|
||||
|
||||
int sink_suspended, source_suspended;
|
||||
|
||||
int fd;
|
||||
int mode;
|
||||
|
||||
int mixer_fd;
|
||||
int mixer_devmask;
|
||||
|
||||
int nfrags, frag_size;
|
||||
|
||||
int use_mmap;
|
||||
|
|
@ -583,6 +581,11 @@ static int unsuspend(struct userdata *u) {
|
|||
pollfd->events = 0;
|
||||
pollfd->revents = 0;
|
||||
|
||||
if (u->sink)
|
||||
pa_sink_get_volume(u->sink);
|
||||
if (u->source)
|
||||
pa_source_get_volume(u->source);
|
||||
|
||||
pa_log_info("Resumed successfully...");
|
||||
|
||||
return 0;
|
||||
|
|
@ -659,31 +662,6 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
|
|||
|
||||
break;
|
||||
|
||||
case PA_SINK_MESSAGE_SET_VOLUME:
|
||||
|
||||
if (u->use_pcm_volume && u->fd >= 0) {
|
||||
|
||||
if (pa_oss_set_pcm_volume(u->fd, &u->sink->sample_spec, ((pa_cvolume*) data)) < 0) {
|
||||
pa_log_info("Device doesn't support setting mixer settings: %s", pa_cstrerror(errno));
|
||||
u->use_pcm_volume = 0;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_SINK_MESSAGE_GET_VOLUME:
|
||||
|
||||
if (u->use_pcm_volume && u->fd >= 0) {
|
||||
|
||||
if (pa_oss_get_pcm_volume(u->fd, &u->sink->sample_spec, ((pa_cvolume*) data)) < 0) {
|
||||
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
|
||||
u->use_pcm_volume = 0;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ret = pa_sink_process_msg(o, code, data, offset, chunk);
|
||||
|
|
@ -757,31 +735,6 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
|
|||
}
|
||||
break;
|
||||
|
||||
case PA_SOURCE_MESSAGE_SET_VOLUME:
|
||||
|
||||
if (u->use_input_volume && u->fd >= 0) {
|
||||
|
||||
if (pa_oss_set_input_volume(u->fd, &u->source->sample_spec, ((pa_cvolume*) data)) < 0) {
|
||||
pa_log_info("Device doesn't support setting mixer settings: %s", pa_cstrerror(errno));
|
||||
u->use_input_volume = 0;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_SOURCE_MESSAGE_GET_VOLUME:
|
||||
|
||||
if (u->use_input_volume && u->fd >= 0) {
|
||||
|
||||
if (pa_oss_get_input_volume(u->fd, &u->source->sample_spec, ((pa_cvolume*) data)) < 0) {
|
||||
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
|
||||
u->use_input_volume = 0;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ret = pa_source_process_msg(o, code, data, offset, chunk);
|
||||
|
|
@ -792,6 +745,86 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int sink_get_volume(pa_sink *s) {
|
||||
struct userdata *u;
|
||||
int r;
|
||||
|
||||
pa_assert_se(u = s->userdata);
|
||||
|
||||
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_VOLUME)
|
||||
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_PCM)
|
||||
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sink_set_volume(pa_sink *s) {
|
||||
struct userdata *u;
|
||||
int r;
|
||||
|
||||
pa_assert_se(u = s->userdata);
|
||||
|
||||
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_VOLUME)
|
||||
if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_PCM)
|
||||
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int source_get_volume(pa_source *s) {
|
||||
struct userdata *u;
|
||||
int r;
|
||||
|
||||
pa_assert_se(u = s->userdata);
|
||||
|
||||
pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_IGAIN)
|
||||
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_RECLEV)
|
||||
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int source_set_volume(pa_source *s) {
|
||||
struct userdata *u;
|
||||
int r;
|
||||
|
||||
pa_assert_se(u = s->userdata);
|
||||
|
||||
pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_IGAIN)
|
||||
if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
if (u->mixer_devmask & SOUND_MASK_RECLEV)
|
||||
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0)
|
||||
return r;
|
||||
|
||||
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void thread_func(void *userdata) {
|
||||
struct userdata *u = userdata;
|
||||
int write_type = 0, read_type = 0;
|
||||
|
|
@ -1135,9 +1168,9 @@ int pa__init(pa_module*m) {
|
|||
u->module = m;
|
||||
m->userdata = u;
|
||||
u->fd = fd;
|
||||
u->mixer_fd = -1;
|
||||
u->use_getospace = u->use_getispace = 1;
|
||||
u->use_getodelay = 1;
|
||||
u->use_input_volume = u->use_pcm_volume = 1;
|
||||
u->mode = mode;
|
||||
u->frame_size = pa_frame_size(&ss);
|
||||
u->device_name = pa_xstrdup(dev);
|
||||
|
|
@ -1210,7 +1243,7 @@ int pa__init(pa_module*m) {
|
|||
hwdesc[0] ? ")" : "",
|
||||
use_mmap ? " via DMA" : ""));
|
||||
pa_xfree(t);
|
||||
u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_CAN_SUSPEND|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
|
||||
u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_CAN_SUSPEND|PA_SOURCE_LATENCY;
|
||||
u->source->refresh_volume = 1;
|
||||
|
||||
if (use_mmap)
|
||||
|
|
@ -1265,13 +1298,44 @@ int pa__init(pa_module*m) {
|
|||
hwdesc[0] ? ")" : "",
|
||||
use_mmap ? " via DMA" : ""));
|
||||
pa_xfree(t);
|
||||
u->sink->flags = PA_SINK_HARDWARE|PA_SINK_CAN_SUSPEND|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL;
|
||||
u->sink->flags = PA_SINK_HARDWARE|PA_SINK_CAN_SUSPEND|PA_SINK_LATENCY;
|
||||
u->sink->refresh_volume = 1;
|
||||
|
||||
if (use_mmap)
|
||||
u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
|
||||
}
|
||||
|
||||
if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
|
||||
int do_close = 1;
|
||||
u->mixer_devmask = 0;
|
||||
|
||||
if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
|
||||
pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
|
||||
|
||||
else {
|
||||
if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) {
|
||||
pa_log_debug("Found hardware mixer track for playback.");
|
||||
u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
|
||||
u->sink->get_volume = sink_get_volume;
|
||||
u->sink->set_volume = sink_set_volume;
|
||||
do_close = 0;
|
||||
}
|
||||
|
||||
if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) {
|
||||
pa_log_debug("Found hardware mixer track for recording.");
|
||||
u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
|
||||
u->source->get_volume = source_get_volume;
|
||||
u->source->set_volume = source_set_volume;
|
||||
do_close = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_close) {
|
||||
pa_close(u->mixer_fd);
|
||||
u->mixer_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
go_on:
|
||||
|
||||
pa_assert(u->source || u->sink);
|
||||
|
|
@ -1284,10 +1348,10 @@ go_on:
|
|||
}
|
||||
|
||||
/* Read mixer settings */
|
||||
if (u->source)
|
||||
pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL);
|
||||
if (u->sink)
|
||||
pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL);
|
||||
if (u->sink && u->sink->get_volume)
|
||||
sink_get_volume(u->sink);
|
||||
if (u->source && u->source->get_volume)
|
||||
source_get_volume(u->source);
|
||||
|
||||
if (u->sink)
|
||||
pa_sink_put(u->sink);
|
||||
|
|
@ -1372,6 +1436,9 @@ void pa__done(pa_module*m) {
|
|||
if (u->fd >= 0)
|
||||
pa_close(u->fd);
|
||||
|
||||
if (u->mixer_fd >= 0)
|
||||
pa_close(u->mixer_fd);
|
||||
|
||||
pa_xfree(u->device_name);
|
||||
|
||||
pa_xfree(u);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
|
|
@ -248,7 +249,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) {
|
||||
int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) {
|
||||
char cv[PA_CVOLUME_SNPRINT_MAX];
|
||||
unsigned vol;
|
||||
|
||||
|
|
@ -259,16 +260,18 @@ static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvo
|
|||
if (ioctl(fd, mixer, &vol) < 0)
|
||||
return -1;
|
||||
|
||||
pa_cvolume_reset(volume, ss->channels);
|
||||
|
||||
volume->values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100;
|
||||
|
||||
if ((volume->channels = ss->channels) >= 2)
|
||||
if (volume->channels >= 2)
|
||||
volume->values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100;
|
||||
|
||||
pa_log_debug("Read mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume) {
|
||||
int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume) {
|
||||
char cv[PA_CVOLUME_SNPRINT_MAX];
|
||||
unsigned vol;
|
||||
pa_volume_t l, r;
|
||||
|
|
@ -289,40 +292,38 @@ static int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) {
|
||||
return pa_oss_get_volume(fd, SOUND_MIXER_READ_PCM, ss, volume);
|
||||
}
|
||||
static int get_device_number(const char *dev) {
|
||||
char buf[PATH_MAX];
|
||||
const char *p, *e;
|
||||
|
||||
int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) {
|
||||
return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_PCM, ss, volume);
|
||||
}
|
||||
if (readlink(dev, buf, sizeof(buf)) < 0) {
|
||||
if (errno != EINVAL && errno != ENOLINK)
|
||||
return -1;
|
||||
|
||||
int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) {
|
||||
return pa_oss_get_volume(fd, SOUND_MIXER_READ_IGAIN, ss, volume);
|
||||
}
|
||||
p = dev;
|
||||
} else
|
||||
p = buf;
|
||||
|
||||
int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) {
|
||||
return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_IGAIN, ss, volume);
|
||||
if ((e = strrchr(p, '/')))
|
||||
p = e+1;
|
||||
|
||||
if (p == 0)
|
||||
return 0;
|
||||
|
||||
p = strchr(p, 0) -1;
|
||||
|
||||
if (*p >= '0' && *p <= '9')
|
||||
return *p - '0';
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pa_oss_get_hw_description(const char *dev, char *name, size_t l) {
|
||||
FILE *f;
|
||||
const char *e = NULL;
|
||||
int n, r = -1;
|
||||
int b = 0;
|
||||
|
||||
if (strncmp(dev, "/dev/dsp", 8) == 0)
|
||||
e = dev+8;
|
||||
else if (strncmp(dev, "/dev/adsp", 9) == 0)
|
||||
e = dev+9;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (*e == 0)
|
||||
n = 0;
|
||||
else if (*e >= '0' && *e <= '9' && *(e+1) == 0)
|
||||
n = *e - '0';
|
||||
else
|
||||
if ((n = get_device_number(dev)) < 0)
|
||||
return -1;
|
||||
|
||||
if (!(f = fopen("/dev/sndstat", "r")) &&
|
||||
|
|
@ -373,3 +374,34 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) {
|
|||
fclose(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int open_mixer(const char *mixer) {
|
||||
int fd;
|
||||
|
||||
if ((fd = open(mixer, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0)
|
||||
return fd;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pa_oss_open_mixer_for_device(const char *device) {
|
||||
int n;
|
||||
char *fn;
|
||||
int fd;
|
||||
|
||||
if ((n = get_device_number(device)) < 0)
|
||||
return -1;
|
||||
|
||||
if (n == 0)
|
||||
if ((fd = open_mixer("/dev/mixer")) >= 0)
|
||||
return fd;
|
||||
|
||||
fn = pa_sprintf_malloc("/dev/mixer%i", n);
|
||||
fd = open_mixer(fn);
|
||||
pa_xfree(fn);
|
||||
|
||||
if (fd < 0)
|
||||
pa_log_warn("Failed to open mixer '%s': %s", device, pa_cstrerror(errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,12 +33,11 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss);
|
|||
|
||||
int pa_oss_set_fragments(int fd, int frags, int frag_size);
|
||||
|
||||
int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume);
|
||||
int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume);
|
||||
|
||||
int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume);
|
||||
int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume);
|
||||
int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume);
|
||||
int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume);
|
||||
|
||||
int pa_oss_get_hw_description(const char *dev, char *name, size_t l);
|
||||
|
||||
int pa_oss_open_mixer_for_device(const char *device);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue