mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-05 13:29:57 -05:00
commit glitch-free work
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2124 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
ebecf3d3e1
commit
d6bd152b4d
22 changed files with 1266 additions and 504 deletions
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/util.h>
|
||||
#include <pulse/timeval.h>
|
||||
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/core.h>
|
||||
|
|
@ -47,6 +48,8 @@
|
|||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/thread-mq.h>
|
||||
#include <pulsecore/rtpoll.h>
|
||||
#include <pulsecore/time-smoother.h>
|
||||
#include <pulsecore/rtclock.h>
|
||||
|
||||
#include "alsa-util.h"
|
||||
#include "module-alsa-source-symdef.h"
|
||||
|
|
@ -60,14 +63,19 @@ PA_MODULE_USAGE(
|
|||
"device=<ALSA device> "
|
||||
"device_id=<ALSA device id> "
|
||||
"format=<sample format> "
|
||||
"channels=<number of channels> "
|
||||
"rate=<sample rate> "
|
||||
"channels=<number of channels> "
|
||||
"channel_map=<channel map> "
|
||||
"fragments=<number of fragments> "
|
||||
"fragment_size=<fragment size> "
|
||||
"channel_map=<channel map> "
|
||||
"mmap=<enable memory mapping?>");
|
||||
"mmap=<enable memory mapping?> "
|
||||
"tsched=<enable system timer based scheduling mode?> "
|
||||
"tsched_buffer_size=<buffer size when using timer based scheduling> "
|
||||
"tsched_buffer_watermark=<upper fill watermark>");
|
||||
|
||||
#define DEFAULT_DEVICE "default"
|
||||
#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC)
|
||||
#define DEFAULT_TSCHED_WATERMARK_USEC (10*PA_USEC_PER_MSEC)
|
||||
|
||||
struct userdata {
|
||||
pa_core *core;
|
||||
|
|
@ -85,29 +93,35 @@ struct userdata {
|
|||
snd_mixer_elem_t *mixer_elem;
|
||||
long hw_volume_max, hw_volume_min;
|
||||
|
||||
size_t frame_size, fragment_size, hwbuf_size;
|
||||
size_t frame_size, fragment_size, hwbuf_size, tsched_watermark;
|
||||
unsigned nfragments;
|
||||
|
||||
char *device_name;
|
||||
|
||||
pa_bool_t use_mmap;
|
||||
pa_bool_t use_mmap, use_tsched;
|
||||
|
||||
pa_rtpoll_item *alsa_rtpoll_item;
|
||||
|
||||
snd_mixer_selem_channel_id_t mixer_map[SND_MIXER_SCHN_LAST];
|
||||
|
||||
pa_smoother *smoother;
|
||||
int64_t frame_index;
|
||||
};
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
"source_name",
|
||||
"device",
|
||||
"device_id",
|
||||
"source_name",
|
||||
"channels",
|
||||
"rate",
|
||||
"format",
|
||||
"rate",
|
||||
"channels",
|
||||
"channel_map",
|
||||
"fragments",
|
||||
"fragment_size",
|
||||
"channel_map",
|
||||
"mmap",
|
||||
"tsched",
|
||||
"tsched_buffer_size",
|
||||
"tsched_buffer_watermark",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -125,7 +139,7 @@ static int mmap_read(struct userdata *u) {
|
|||
pa_memchunk chunk;
|
||||
void *p;
|
||||
|
||||
if ((n = snd_pcm_avail_update(u->pcm_handle)) < 0) {
|
||||
if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
|
||||
|
||||
if (n == -EPIPE)
|
||||
pa_log_debug("snd_pcm_avail_update: Buffer underrun!");
|
||||
|
|
@ -140,14 +154,12 @@ static int mmap_read(struct userdata *u) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* pa_log("Got request for %i samples", (int) n); */
|
||||
|
||||
if (n <= 0)
|
||||
if (PA_UNLIKELY(n <= 0))
|
||||
return work_done;
|
||||
|
||||
frames = n;
|
||||
|
||||
if ((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0) {
|
||||
if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) {
|
||||
|
||||
if (err == -EPIPE)
|
||||
pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!");
|
||||
|
|
@ -182,7 +194,7 @@ static int mmap_read(struct userdata *u) {
|
|||
* a little bit longer around? */
|
||||
pa_memblock_unref_fixed(chunk.memblock);
|
||||
|
||||
if ((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0) {
|
||||
if (PA_UNLIKELY((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0)) {
|
||||
|
||||
if (err == -EPIPE)
|
||||
pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!");
|
||||
|
|
@ -199,7 +211,10 @@ static int mmap_read(struct userdata *u) {
|
|||
|
||||
work_done = 1;
|
||||
|
||||
/* pa_log("wrote %i samples", (int) frames); */
|
||||
u->frame_index += frames;
|
||||
|
||||
if (PA_LIKELY(frames >= (snd_pcm_uframes_t) n))
|
||||
return work_done;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -214,87 +229,98 @@ static int unix_read(struct userdata *u) {
|
|||
|
||||
for (;;) {
|
||||
void *p;
|
||||
snd_pcm_sframes_t t, k;
|
||||
ssize_t l;
|
||||
snd_pcm_sframes_t n, frames;
|
||||
int err;
|
||||
pa_memchunk chunk;
|
||||
|
||||
if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) {
|
||||
if (PA_UNLIKELY((err = snd_pcm_status(u->pcm_handle, status)) < 0)) {
|
||||
pa_log("Failed to query DSP status data: %s", snd_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size)
|
||||
if (PA_UNLIKELY(snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size))
|
||||
pa_log_debug("Buffer overrun!");
|
||||
|
||||
l = snd_pcm_status_get_avail(status) * u->frame_size;
|
||||
n = snd_pcm_status_get_avail(status);
|
||||
|
||||
if (l <= 0)
|
||||
if (PA_UNLIKELY(n <= 0))
|
||||
return work_done;
|
||||
|
||||
chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
|
||||
|
||||
k = pa_memblock_get_length(chunk.memblock);
|
||||
frames = pa_memblock_get_length(chunk.memblock) / u->frame_size;
|
||||
|
||||
if (k > l)
|
||||
k = l;
|
||||
|
||||
k = (k/u->frame_size)*u->frame_size;
|
||||
if (frames > n)
|
||||
frames = n;
|
||||
|
||||
p = pa_memblock_acquire(chunk.memblock);
|
||||
t = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, k / u->frame_size);
|
||||
frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, frames);
|
||||
pa_memblock_release(chunk.memblock);
|
||||
|
||||
/* pa_log("wrote %i bytes of %u (%u)", t*u->frame_size, u->memchunk.length, l); */
|
||||
pa_assert(frames != 0);
|
||||
|
||||
pa_assert(t != 0);
|
||||
|
||||
if (t < 0) {
|
||||
if (PA_UNLIKELY(frames < 0)) {
|
||||
pa_memblock_unref(chunk.memblock);
|
||||
|
||||
if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0)
|
||||
if ((frames = snd_pcm_recover(u->pcm_handle, frames, 1)) == 0)
|
||||
continue;
|
||||
|
||||
if (t == -EAGAIN) {
|
||||
pa_log_debug("EAGAIN");
|
||||
if (frames == -EAGAIN)
|
||||
return work_done;
|
||||
} else {
|
||||
pa_log("Failed to read data from DSP: %s", snd_strerror(t));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pa_log("Failed to read data from DSP: %s", snd_strerror(frames));
|
||||
return -1;
|
||||
}
|
||||
|
||||
chunk.index = 0;
|
||||
chunk.length = t * u->frame_size;
|
||||
chunk.length = frames * u->frame_size;
|
||||
|
||||
pa_source_post(u->source, &chunk);
|
||||
pa_memblock_unref(chunk.memblock);
|
||||
|
||||
work_done = 1;
|
||||
|
||||
if (t * u->frame_size >= (unsigned) l)
|
||||
u->frame_index += frames;
|
||||
|
||||
if (PA_LIKELY(frames >= n))
|
||||
return work_done;
|
||||
}
|
||||
}
|
||||
|
||||
static pa_usec_t source_get_latency(struct userdata *u) {
|
||||
pa_usec_t r = 0;
|
||||
static int update_smoother(struct userdata *u) {
|
||||
snd_pcm_status_t *status;
|
||||
snd_pcm_sframes_t frames = 0;
|
||||
int64_t frames;
|
||||
int err;
|
||||
|
||||
snd_pcm_status_alloca(&status);
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->pcm_handle);
|
||||
|
||||
if ((err = snd_pcm_status(u->pcm_handle, status)) < 0)
|
||||
pa_log("Failed to get delay: %s", snd_strerror(err));
|
||||
else
|
||||
frames = snd_pcm_status_get_delay(status);
|
||||
snd_pcm_status_alloca(&status);
|
||||
|
||||
if (frames > 0)
|
||||
r = pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec);
|
||||
/* Let's update the time smoother */
|
||||
|
||||
if (PA_UNLIKELY((err = snd_pcm_status(u->pcm_handle, status)) < 0)) {
|
||||
pa_log("Failed to get delay: %s", snd_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
frames = u->frame_index + snd_pcm_status_get_delay(status);
|
||||
|
||||
pa_smoother_put(u->smoother, pa_rtclock_usec(), pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static pa_usec_t source_get_latency(struct userdata *u) {
|
||||
pa_usec_t r = 0;
|
||||
int64_t delay;
|
||||
|
||||
pa_assert(u);
|
||||
|
||||
delay = pa_smoother_get(u->smoother, pa_rtclock_usec()) - u->frame_index;
|
||||
|
||||
if (delay > 0)
|
||||
r = pa_bytes_to_usec(delay * u->frame_size, &u->source->sample_spec);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -330,6 +356,8 @@ static int suspend(struct userdata *u) {
|
|||
pa_assert(u);
|
||||
pa_assert(u->pcm_handle);
|
||||
|
||||
pa_smoother_pause(u->smoother, pa_rtclock_usec());
|
||||
|
||||
/* Let's suspend */
|
||||
snd_pcm_close(u->pcm_handle);
|
||||
u->pcm_handle = NULL;
|
||||
|
|
@ -344,10 +372,55 @@ static int suspend(struct userdata *u) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static pa_usec_t hw_sleep_time(struct userdata *u) {
|
||||
pa_usec_t usec;
|
||||
|
||||
pa_assert(u);
|
||||
|
||||
usec = pa_source_get_requested_latency(u->source);
|
||||
|
||||
if (usec <= 0)
|
||||
usec = pa_bytes_to_usec(u->hwbuf_size, &u->source->sample_spec);
|
||||
|
||||
if (usec >= u->tsched_watermark)
|
||||
usec -= u->tsched_watermark;
|
||||
else
|
||||
usec /= 2;
|
||||
|
||||
return usec;
|
||||
}
|
||||
|
||||
static int update_sw_params(struct userdata *u) {
|
||||
size_t avail_min;
|
||||
int err;
|
||||
|
||||
pa_assert(u);
|
||||
|
||||
if (u->use_tsched) {
|
||||
pa_usec_t usec;
|
||||
|
||||
usec = hw_sleep_time(u);
|
||||
|
||||
avail_min = pa_usec_to_bytes(usec, &u->source->sample_spec);
|
||||
|
||||
if (avail_min <= 0)
|
||||
avail_min = 1;
|
||||
|
||||
} else
|
||||
avail_min = 1;
|
||||
|
||||
if ((err = pa_alsa_set_sw_params(u->pcm_handle, avail_min)) < 0) {
|
||||
pa_log("Failed to set software parameters: %s", snd_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unsuspend(struct userdata *u) {
|
||||
pa_sample_spec ss;
|
||||
int err;
|
||||
pa_bool_t b;
|
||||
pa_bool_t b, d;
|
||||
unsigned nfrags;
|
||||
snd_pcm_uframes_t period_size;
|
||||
|
||||
|
|
@ -366,13 +439,14 @@ static int unsuspend(struct userdata *u) {
|
|||
nfrags = u->nfragments;
|
||||
period_size = u->fragment_size / u->frame_size;
|
||||
b = u->use_mmap;
|
||||
d = u->use_tsched;
|
||||
|
||||
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b, TRUE)) < 0) {
|
||||
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) {
|
||||
pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (b != u->use_mmap) {
|
||||
if (b != u->use_mmap || d != u->use_tsched) {
|
||||
pa_log_warn("Resume failed, couldn't get original access mode.");
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -387,17 +461,17 @@ static int unsuspend(struct userdata *u) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) {
|
||||
pa_log("Failed to set software parameters: %s", snd_strerror(err));
|
||||
if (update_sw_params(u) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (build_pollfd(u) < 0)
|
||||
goto fail;
|
||||
|
||||
/* FIXME: We need to reload the volume somehow */
|
||||
|
||||
snd_pcm_start(u->pcm_handle);
|
||||
|
||||
/* FIXME: We need to reload the volume somehow */
|
||||
pa_smoother_resume(u->smoother, pa_rtclock_usec());
|
||||
|
||||
pa_log_info("Resumed successfully...");
|
||||
|
||||
|
|
@ -609,15 +683,39 @@ static void thread_func(void *userdata) {
|
|||
|
||||
/* Read some data and pass it to the sources */
|
||||
if (PA_SOURCE_OPENED(u->source->thread_info.state)) {
|
||||
int work_done = 0;
|
||||
|
||||
if (u->use_mmap) {
|
||||
if (mmap_read(u) < 0)
|
||||
if ((work_done = mmap_read(u)) < 0)
|
||||
goto fail;
|
||||
|
||||
} else {
|
||||
if (unix_read(u) < 0)
|
||||
if ((work_done = unix_read(u) < 0))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (update_smoother(u) < 0)
|
||||
goto fail;
|
||||
|
||||
if (u->use_tsched && work_done) {
|
||||
pa_usec_t usec, cusec;
|
||||
|
||||
/* OK, the capture buffer is now empty, let's
|
||||
* calculate when to wake up next */
|
||||
|
||||
usec = hw_sleep_time(u);
|
||||
|
||||
pa_log_debug("Waking up in %0.2fms (sound card clock).", (double) usec / PA_USEC_PER_MSEC);
|
||||
|
||||
/* Convert from the sound card time domain to the
|
||||
* system time domain */
|
||||
cusec = pa_smoother_translate(u->smoother, pa_rtclock_usec(), usec);
|
||||
|
||||
pa_log_debug("Waking up in %0.2fms (system clock).", (double) cusec / PA_USEC_PER_MSEC);
|
||||
|
||||
/* We don't trust the conversion, so we wake up whatever comes first */
|
||||
pa_rtpoll_set_timer_relative(u->rtpoll, PA_MIN(usec, cusec));
|
||||
}
|
||||
}
|
||||
|
||||
/* Hmm, nothing to do. Let's sleep */
|
||||
|
|
@ -699,16 +797,22 @@ int pa__init(pa_module*m) {
|
|||
const char *dev_id;
|
||||
pa_sample_spec ss;
|
||||
pa_channel_map map;
|
||||
uint32_t nfrags, frag_size;
|
||||
snd_pcm_uframes_t period_size;
|
||||
uint32_t nfrags, frag_size, tsched_size, tsched_watermark;
|
||||
snd_pcm_uframes_t period_frames, tsched_frames;
|
||||
size_t frame_size;
|
||||
snd_pcm_info_t *pcm_info = NULL;
|
||||
int err;
|
||||
char *t;
|
||||
const char *name;
|
||||
char *name_buf = NULL;
|
||||
int namereg_fail;
|
||||
pa_bool_t use_mmap = TRUE, b;
|
||||
pa_bool_t namereg_fail;
|
||||
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
|
||||
pa_source_new_data data;
|
||||
static const char * const class_table[SND_PCM_CLASS_LAST+1] = {
|
||||
[SND_PCM_CLASS_GENERIC] = "sound",
|
||||
[SND_PCM_CLASS_MULTI] = NULL,
|
||||
[SND_PCM_CLASS_MODEM] = "modem",
|
||||
[SND_PCM_CLASS_DIGITIZER] = NULL
|
||||
};
|
||||
|
||||
snd_pcm_info_alloca(&pcm_info);
|
||||
|
||||
|
|
@ -728,34 +832,55 @@ int pa__init(pa_module*m) {
|
|||
frame_size = pa_frame_size(&ss);
|
||||
|
||||
nfrags = m->core->default_n_fragments;
|
||||
frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
|
||||
frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*PA_USEC_PER_MSEC, &ss);
|
||||
if (frag_size <= 0)
|
||||
frag_size = frame_size;
|
||||
tsched_size = pa_usec_to_bytes(DEFAULT_TSCHED_BUFFER_USEC, &ss);
|
||||
tsched_watermark = pa_usec_to_bytes(DEFAULT_TSCHED_WATERMARK_USEC, &ss);
|
||||
|
||||
if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) {
|
||||
if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 ||
|
||||
pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 ||
|
||||
pa_modargs_get_value_u32(ma, "tsched_buffer_size", &tsched_size) < 0 ||
|
||||
pa_modargs_get_value_u32(ma, "tsched_buffer_watermark", &tsched_watermark) < 0) {
|
||||
pa_log("Failed to parse buffer metrics");
|
||||
goto fail;
|
||||
}
|
||||
period_size = frag_size/frame_size;
|
||||
|
||||
period_frames = frag_size/frame_size;
|
||||
tsched_frames = tsched_size/frame_size;
|
||||
|
||||
if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
|
||||
pa_log("Failed to parse mmap argument.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pa_modargs_get_value_boolean(ma, "tsched", &use_tsched) < 0) {
|
||||
pa_log("Failed to parse timer_scheduling argument.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (use_tsched && !pa_rtclock_hrtimer()) {
|
||||
pa_log("Disabling timer-based scheduling because high-resolution timers are not available from the kernel.");
|
||||
use_tsched = FALSE;
|
||||
}
|
||||
|
||||
u = pa_xnew0(struct userdata, 1);
|
||||
u->core = m->core;
|
||||
u->module = m;
|
||||
m->userdata = u;
|
||||
u->use_mmap = use_mmap;
|
||||
u->use_tsched = use_tsched;
|
||||
pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
|
||||
u->rtpoll = pa_rtpoll_new();
|
||||
u->alsa_rtpoll_item = NULL;
|
||||
pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
|
||||
u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC, DEFAULT_TSCHED_WATERMARK_USEC, TRUE);
|
||||
pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
|
||||
|
||||
snd_config_update_free_global();
|
||||
|
||||
b = use_mmap;
|
||||
d = use_tsched;
|
||||
|
||||
if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) {
|
||||
|
||||
|
|
@ -764,8 +889,8 @@ int pa__init(pa_module*m) {
|
|||
&u->device_name,
|
||||
&ss, &map,
|
||||
SND_PCM_STREAM_CAPTURE,
|
||||
&nfrags, &period_size,
|
||||
&b)))
|
||||
&nfrags, &period_frames, tsched_frames,
|
||||
&b, &d)))
|
||||
goto fail;
|
||||
|
||||
} else {
|
||||
|
|
@ -775,8 +900,8 @@ int pa__init(pa_module*m) {
|
|||
&u->device_name,
|
||||
&ss, &map,
|
||||
SND_PCM_STREAM_CAPTURE,
|
||||
&nfrags, &period_size,
|
||||
&b)))
|
||||
&nfrags, &period_frames, tsched_frames,
|
||||
&b, &d)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -788,18 +913,24 @@ int pa__init(pa_module*m) {
|
|||
u->use_mmap = use_mmap = b;
|
||||
}
|
||||
|
||||
if (use_tsched && (!b || !d)) {
|
||||
pa_log_info("Cannot enabled timer-based scheduling, falling back to sound IRQ scheduling.");
|
||||
u->use_tsched = use_tsched = FALSE;
|
||||
}
|
||||
|
||||
if (u->use_mmap)
|
||||
pa_log_info("Successfully enabled mmap() mode.");
|
||||
|
||||
if (u->use_tsched)
|
||||
pa_log_info("Successfully enabled timer-based scheduling mode.");
|
||||
|
||||
if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) {
|
||||
pa_log("Error fetching PCM info: %s", snd_strerror(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) {
|
||||
pa_log("Failed to set software parameters: %s", snd_strerror(err));
|
||||
if (update_sw_params(u) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ALSA might tweak the sample spec, so recalculate the frame size */
|
||||
frame_size = pa_frame_size(&ss);
|
||||
|
|
@ -832,13 +963,31 @@ int pa__init(pa_module*m) {
|
|||
}
|
||||
|
||||
if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
|
||||
namereg_fail = 1;
|
||||
namereg_fail = TRUE;
|
||||
else {
|
||||
name = name_buf = pa_sprintf_malloc("alsa_input.%s", u->device_name);
|
||||
namereg_fail = 0;
|
||||
namereg_fail = FALSE;
|
||||
}
|
||||
|
||||
u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
|
||||
pa_source_new_data_init(&data);
|
||||
data.driver = __FILE__;
|
||||
data.module = m;
|
||||
pa_source_new_data_set_name(&data, name);
|
||||
data.namereg_fail = namereg_fail;
|
||||
pa_source_new_data_set_sample_spec(&data, &ss);
|
||||
pa_source_new_data_set_channel_map(&data, &map);
|
||||
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "alsa");
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, snd_pcm_info_get_name(pcm_info));
|
||||
|
||||
if (class_table[snd_pcm_info_get_class(pcm_info)])
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, class_table[snd_pcm_info_get_class(pcm_info)]);
|
||||
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap_rewrite" : (u->use_mmap ? "mmap" : "serial"));
|
||||
|
||||
u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
|
||||
pa_source_new_data_done(&data);
|
||||
pa_xfree(name_buf);
|
||||
|
||||
if (!u->source) {
|
||||
|
|
@ -849,22 +998,15 @@ int pa__init(pa_module*m) {
|
|||
u->source->parent.process_msg = source_process_msg;
|
||||
u->source->userdata = u;
|
||||
|
||||
pa_source_set_module(u->source, m);
|
||||
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
|
||||
pa_source_set_rtpoll(u->source, u->rtpoll);
|
||||
pa_source_set_description(u->source, t = pa_sprintf_malloc(
|
||||
"ALSA PCM on %s (%s)%s",
|
||||
u->device_name,
|
||||
snd_pcm_info_get_name(pcm_info),
|
||||
use_mmap ? " via DMA" : ""));
|
||||
pa_xfree(t);
|
||||
|
||||
u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY;
|
||||
|
||||
u->frame_size = frame_size;
|
||||
u->fragment_size = frag_size = period_size * frame_size;
|
||||
u->fragment_size = frag_size = period_frames * frame_size;
|
||||
u->nfragments = nfrags;
|
||||
u->hwbuf_size = u->fragment_size * nfrags;
|
||||
u->tsched_watermark = tsched_watermark;
|
||||
u->frame_index = 0;
|
||||
|
||||
pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size);
|
||||
|
||||
|
|
@ -961,6 +1103,9 @@ void pa__done(pa_module*m) {
|
|||
snd_pcm_close(u->pcm_handle);
|
||||
}
|
||||
|
||||
if (u->smoother)
|
||||
pa_smoother_free(u->smoother);
|
||||
|
||||
pa_xfree(u->device_name);
|
||||
pa_xfree(u);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue