From: Takashi Iwai Date: Fri, 12 Aug 2005 15:53:02 +0000 (+0000) Subject: Fix direct plugins running on 32bit emulation with 64bit arch X-Git-Tag: v1.0.10rc1~10 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=e80f80866fe269e35d505ee164361aa40ae653ad;p=alsa-lib.git Fix direct plugins running on 32bit emulation with 64bit arch Fix the problems of dmix/dsnoop/dshare plugins running on 32bit mode with 64bit biarch. --- diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index f146ebf1..3d3f1d4a 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -532,7 +532,7 @@ static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, - snd_pcm_hw_params_t *src) + snd_interval_t *src) { snd_interval_t *i; @@ -543,7 +543,7 @@ static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, SNDERR("dshare interval %i empty?", (int)var); return -EINVAL; } - if (snd_interval_refine(i, hw_param_interval(src, var))) + if (snd_interval_refine(i, src)) params->cmask |= 1<private_data; - snd_pcm_hw_params_t *hw_params = &dshare->shmptr->hw_params; static snd_mask_t access = { .bits = { (1<shmptr->hw.format)) params->cmask |= 1<shmptr->hw.rate); if (err < 0) return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, hw_params); + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + &dshare->shmptr->hw.buffer_size); if (err < 0) return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, hw_params); + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, + &dshare->shmptr->hw.buffer_time); if (err < 0) return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, hw_params); + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, + &dshare->shmptr->hw.period_size); if (err < 0) return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, hw_params); + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, + &dshare->shmptr->hw.period_time); if (err < 0) return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, hw_params); + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, + &dshare->shmptr->hw.periods); if (err < 0) return err; params->info = dshare->shmptr->s.info; @@ -675,8 +680,8 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str struct pollfd fd; int loops = 10; - hw_params = &dmix->shmptr->hw_params; - sw_params = &dmix->shmptr->sw_params; + snd_pcm_hw_params_alloca(&hw_params); + snd_pcm_sw_params_alloca(&sw_params); __again: if (loops-- <= 0) { @@ -800,6 +805,16 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str return ret; } + /* store some hw_params values to shared info */ + dmix->shmptr->hw.format = snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)); + dmix->shmptr->hw.rate = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_RATE); + dmix->shmptr->hw.buffer_size = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_BUFFER_SIZE); + dmix->shmptr->hw.buffer_time = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_BUFFER_TIME); + dmix->shmptr->hw.period_size = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIOD_SIZE); + dmix->shmptr->hw.period_time = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIOD_TIME); + dmix->shmptr->hw.periods = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIODS); + + ret = snd_pcm_sw_params_current(spcm, sw_params); if (ret < 0) { SNDERR("unable to get current sw_params"); @@ -865,10 +880,20 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str dmix->shmptr->s.channels = spcm->channels; dmix->shmptr->s.rate = spcm->rate; dmix->shmptr->s.format = spcm->format; - dmix->shmptr->s.boundary = spcm->boundary; dmix->shmptr->s.info = spcm->info & ~SND_PCM_INFO_PAUSE; dmix->shmptr->s.msbits = spcm->msbits; + /* Currently, we assume that each dmix client has the same + * hw_params setting. + * If the arbitrary hw_parmas is supported in future, + * boundary has to be taken from the slave config but + * recalculated for the native boundary size (for 32bit + * emulation on 64bit arch). + */ + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = spcm->period_size; + dmix->slave_boundary = spcm->boundary; + spcm->donot_close = 1; return 0; } @@ -936,6 +961,54 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) return 0; } +static snd_pcm_uframes_t recalc_boundary_size(unsigned long long bsize, snd_pcm_uframes_t buffer_size) +{ + if (bsize > LONG_MAX) { + bsize = buffer_size; + while (bsize * 2 <= LONG_MAX - buffer_size) + bsize *= 2; + } + return (snd_pcm_uframes_t)bsize; +} + +/* + * open a slave PCM as secondary client (dup'ed fd) + */ +int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name) +{ + int ret; + snd_pcm_t *spcm; + + ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0, 0); + if (ret < 0) { + SNDERR("unable to open hardware"); + return ret; + } + + spcm = *spcmp; + spcm->donot_close = 1; + spcm->setup = 1; + /* we copy the slave setting */ + spcm->buffer_size = dmix->shmptr->s.buffer_size; + spcm->sample_bits = dmix->shmptr->s.sample_bits; + spcm->channels = dmix->shmptr->s.channels; + spcm->format = dmix->shmptr->s.format; + spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size); + spcm->info = dmix->shmptr->s.info; + + /* Use the slave setting as SPCM, so far */ + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = dmix->shmptr->s.period_size; + dmix->slave_boundary = spcm->boundary; + + ret = snd_pcm_mmap(spcm); + if (ret < 0) { + SNDERR("unable to mmap channels"); + return ret; + } + return 0; +} + int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) { snd_timer_params_t *params; diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 5b6b938b..da300b78 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -48,13 +48,20 @@ struct slave_params { typedef struct { char socket_name[256]; /* name of communication socket */ snd_pcm_type_t type; /* PCM type (currently only hw) */ - snd_pcm_hw_params_t hw_params; - snd_pcm_sw_params_t sw_params; struct { - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t period_size; - snd_pcm_uframes_t boundary; - snd_pcm_uframes_t channels; + unsigned int format; + snd_interval_t rate; + snd_interval_t buffer_size; + snd_interval_t buffer_time; + snd_interval_t period_size; + snd_interval_t period_time; + snd_interval_t periods; + } hw; + struct { + unsigned int buffer_size; + unsigned int period_size; + unsigned long long boundary; + unsigned int channels; unsigned int sample_bits; unsigned int rate; snd_pcm_format_t format; @@ -85,6 +92,9 @@ struct snd_pcm_direct { snd_pcm_uframes_t avail_max; snd_pcm_uframes_t slave_appl_ptr; snd_pcm_uframes_t slave_hw_ptr; + snd_pcm_uframes_t slave_period_size; + snd_pcm_uframes_t slave_buffer_size; + snd_pcm_uframes_t slave_boundary; int (*sync_ptr)(snd_pcm_t *pcm); snd_pcm_state_t state; snd_htimestamp_t trigger_tstamp; @@ -146,6 +156,7 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm); int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); +int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index af4a67a9..36a7a5c9 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -238,8 +238,8 @@ static void mix_areas(snd_pcm_direct_t *dmix, static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) { snd_pcm_direct_t *dmix = pcm->private_data; - snd_pcm_uframes_t appl_ptr, slave_appl_ptr, slave_bsize; - snd_pcm_uframes_t size, slave_size, slave_hw_ptr; + snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; + snd_pcm_uframes_t appl_ptr, size; const snd_pcm_channel_area_t *src_areas, *dst_areas; /* calculate the size to transfer */ @@ -253,17 +253,16 @@ static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) size = pcm->boundary - size; /* check the available size in the slave PCM buffer */ - slave_bsize = dmix->shmptr->s.buffer_size; slave_hw_ptr = dmix->slave_hw_ptr; /* don't write on the last active period - this area may be cleared * by the driver during mix operation... */ - slave_hw_ptr -= slave_hw_ptr % dmix->shmptr->s.period_size; - slave_hw_ptr += slave_bsize; - if (slave_hw_ptr >= dmix->shmptr->s.boundary) - slave_hw_ptr -= dmix->shmptr->s.boundary; + slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size; + slave_hw_ptr += dmix->slave_buffer_size; + if (slave_hw_ptr >= dmix->slave_boundary) + slave_hw_ptr -= dmix->slave_boundary; if (slave_hw_ptr < dmix->slave_appl_ptr) - slave_size = slave_hw_ptr + (dmix->shmptr->s.boundary - dmix->slave_appl_ptr); + slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr); else slave_size = slave_hw_ptr - dmix->slave_appl_ptr; if (slave_size < size) @@ -277,22 +276,22 @@ static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; dmix->last_appl_ptr += size; dmix->last_appl_ptr %= pcm->boundary; - slave_appl_ptr = dmix->slave_appl_ptr % slave_bsize; + slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; dmix->slave_appl_ptr += size; - dmix->slave_appl_ptr %= dmix->shmptr->s.boundary; + dmix->slave_appl_ptr %= dmix->slave_boundary; dmix_down_sem(dmix); for (;;) { snd_pcm_uframes_t transfer = size; if (appl_ptr + transfer > pcm->buffer_size) transfer = pcm->buffer_size - appl_ptr; - if (slave_appl_ptr + transfer > slave_bsize) - transfer = slave_bsize - slave_appl_ptr; + if (slave_appl_ptr + transfer > dmix->slave_buffer_size) + transfer = dmix->slave_buffer_size - slave_appl_ptr; mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); size -= transfer; if (! size) break; slave_appl_ptr += transfer; - slave_appl_ptr %= slave_bsize; + slave_appl_ptr %= dmix->slave_buffer_size; appl_ptr += transfer; appl_ptr %= pcm->buffer_size; } @@ -327,7 +326,7 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) /* not really started yet - don't update hw_ptr */ return 0; if (diff < 0) { - slave_hw_ptr += dmix->shmptr->s.boundary; + slave_hw_ptr += dmix->slave_boundary; diff = slave_hw_ptr - old_slave_hw_ptr; } dmix->hw_ptr += diff; @@ -451,7 +450,6 @@ static int snd_pcm_dmix_prepare(snd_pcm_t *pcm) snd_pcm_direct_t *dmix = pcm->private_data; snd_pcm_direct_check_interleave(dmix, pcm); - // assert(pcm->boundary == dmix->shmptr->s.boundary); /* for sure */ dmix->state = SND_PCM_STATE_PREPARED; dmix->appl_ptr = dmix->last_appl_ptr = 0; dmix->hw_ptr = 0; @@ -861,25 +859,9 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, } snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_hw_open_fd(&spcm, "dmix_client", dmix->hw_fd, 0, 0); - if (ret < 0) { - SNDERR("unable to open hardware"); - goto _err; - } - - spcm->donot_close = 1; - spcm->setup = 1; - spcm->buffer_size = dmix->shmptr->s.buffer_size; - spcm->sample_bits = dmix->shmptr->s.sample_bits; - spcm->channels = dmix->shmptr->s.channels; - spcm->format = dmix->shmptr->s.format; - spcm->boundary = dmix->shmptr->s.boundary; - spcm->info = dmix->shmptr->s.info; - ret = snd_pcm_mmap(spcm); - if (ret < 0) { - SNDERR("unable to mmap channels"); + ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client"); + if (ret < 0) goto _err; - } dmix->spcm = spcm; } diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 434428f4..a90cd636 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -103,48 +103,52 @@ static void share_areas(snd_pcm_direct_t *dshare, static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) { snd_pcm_direct_t *dshare = pcm->private_data; - snd_pcm_uframes_t appl_ptr, slave_appl_ptr, slave_bsize; - snd_pcm_uframes_t size, slave_hw_ptr; + snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; + snd_pcm_uframes_t appl_ptr, size; const snd_pcm_channel_area_t *src_areas, *dst_areas; /* calculate the size to transfer */ size = dshare->appl_ptr - dshare->last_appl_ptr; if (! size) return; - slave_bsize = dshare->shmptr->s.buffer_size; slave_hw_ptr = dshare->slave_hw_ptr; /* don't write on the last active period - this area may be cleared * by the driver during write operation... */ - slave_hw_ptr -= slave_hw_ptr % dshare->shmptr->s.period_size; - slave_hw_ptr += slave_bsize; - if (dshare->slave_hw_ptr > dshare->slave_appl_ptr) - slave_hw_ptr -= dshare->shmptr->s.boundary; - if (dshare->slave_appl_ptr + size >= slave_hw_ptr) - size = slave_hw_ptr - dshare->slave_appl_ptr; + slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size; + slave_hw_ptr += dshare->slave_buffer_size; + if (dshare->slave_hw_ptr > dshare->slave_boundary) + slave_hw_ptr -= dshare->slave_boundary; + if (slave_hw_ptr < dshare->slave_appl_ptr) + slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr); + else + slave_size = slave_hw_ptr - dshare->slave_appl_ptr; + if (slave_size < size) + size = slave_size; if (! size) return; + /* add sample areas here */ src_areas = snd_pcm_mmap_areas(pcm); dst_areas = snd_pcm_mmap_areas(dshare->spcm); appl_ptr = dshare->last_appl_ptr % pcm->buffer_size; dshare->last_appl_ptr += size; dshare->last_appl_ptr %= pcm->boundary; - slave_appl_ptr = dshare->slave_appl_ptr % slave_bsize; + slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size; dshare->slave_appl_ptr += size; - dshare->slave_appl_ptr %= dshare->shmptr->s.boundary; + dshare->slave_appl_ptr %= dshare->slave_boundary; for (;;) { snd_pcm_uframes_t transfer = size; if (appl_ptr + transfer > pcm->buffer_size) transfer = pcm->buffer_size - appl_ptr; - if (slave_appl_ptr + transfer > slave_bsize) - transfer = slave_bsize - slave_appl_ptr; + if (slave_appl_ptr + transfer > dshare->slave_buffer_size) + transfer = dshare->slave_buffer_size - slave_appl_ptr; share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); size -= transfer; if (! size) break; slave_appl_ptr += transfer; - slave_appl_ptr %= slave_bsize; + slave_appl_ptr %= dshare->slave_buffer_size; appl_ptr += transfer; appl_ptr %= pcm->buffer_size; } @@ -178,7 +182,7 @@ static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) /* not really started yet - don't update hw_ptr */ return 0; if (diff < 0) { - slave_hw_ptr += dshare->shmptr->s.boundary; + slave_hw_ptr += dshare->slave_boundary; diff = slave_hw_ptr - old_slave_hw_ptr; } dshare->hw_ptr += diff; @@ -299,7 +303,6 @@ static int snd_pcm_dshare_prepare(snd_pcm_t *pcm) snd_pcm_direct_t *dshare = pcm->private_data; snd_pcm_direct_check_interleave(dshare, pcm); - // assert(pcm->boundary == dshare->shmptr->s.boundary); /* for sure */ dshare->state = SND_PCM_STATE_PREPARED; dshare->appl_ptr = dshare->last_appl_ptr = 0; dshare->hw_ptr = 0; @@ -706,25 +709,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, } snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client"); ret = snd_pcm_hw_open_fd(&spcm, "dshare_client", dshare->hw_fd, 0, 0); - if (ret < 0) { - SNDERR("unable to open hardware"); + if (ret < 0) goto _err; - } - - spcm->donot_close = 1; - spcm->setup = 1; - spcm->buffer_size = dshare->shmptr->s.buffer_size; - spcm->sample_bits = dshare->shmptr->s.sample_bits; - spcm->channels = dshare->shmptr->s.channels; - spcm->format = dshare->shmptr->s.format; - spcm->boundary = dshare->shmptr->s.boundary; - spcm->info = dshare->shmptr->s.info; - ret = snd_pcm_mmap(spcm); - if (ret < 0) { - SNDERR("unable to mmap channels"); - goto _err; - } dshare->spcm = spcm; } diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 82b55087..d0f43576 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -93,14 +93,15 @@ static void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ dst_areas = snd_pcm_mmap_areas(pcm); src_areas = snd_pcm_mmap_areas(dsnoop->spcm); hw_ptr %= pcm->buffer_size; - slave_hw_ptr %= dsnoop->shmptr->s.buffer_size; + slave_hw_ptr %= dsnoop->slave_buffer_size; while (size > 0) { transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size; - transfer = slave_hw_ptr + transfer > dsnoop->shmptr->s.buffer_size ? dsnoop->shmptr->s.buffer_size - slave_hw_ptr : transfer; + transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ? + dsnoop->slave_buffer_size - slave_hw_ptr : transfer; size -= transfer; snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer); slave_hw_ptr += transfer; - slave_hw_ptr %= dsnoop->shmptr->s.buffer_size; + slave_hw_ptr %= dsnoop->slave_buffer_size; hw_ptr += transfer; hw_ptr %= pcm->buffer_size; } @@ -130,7 +131,7 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) if (diff == 0) /* fast path */ return 0; if (diff < 0) { - slave_hw_ptr += dsnoop->shmptr->s.boundary; + slave_hw_ptr += dsnoop->slave_boundary; diff = slave_hw_ptr - old_slave_hw_ptr; } snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff); @@ -245,7 +246,6 @@ static int snd_pcm_dsnoop_prepare(snd_pcm_t *pcm) snd_pcm_direct_t *dsnoop = pcm->private_data; snd_pcm_direct_check_interleave(dsnoop, pcm); - // assert(pcm->boundary == dsnoop->shmptr->s.boundary); /* for sure */ dsnoop->state = SND_PCM_STATE_PREPARED; dsnoop->appl_ptr = 0; dsnoop->hw_ptr = 0; @@ -597,25 +597,10 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, } snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_hw_open_fd(&spcm, "dsnoop_client", dsnoop->hw_fd, 0, 0); - if (ret < 0) { - SNDERR("unable to open hardware"); - goto _err; - } - - spcm->donot_close = 1; - spcm->setup = 1; - spcm->buffer_size = dsnoop->shmptr->s.buffer_size; - spcm->sample_bits = dsnoop->shmptr->s.sample_bits; - spcm->channels = dsnoop->shmptr->s.channels; - spcm->format = dsnoop->shmptr->s.format; - spcm->boundary = dsnoop->shmptr->s.boundary; - spcm->info = dsnoop->shmptr->s.info; - ret = snd_pcm_mmap(spcm); - if (ret < 0) { - SNDERR("unable to mmap channels"); + + ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client"); + if (ret < 0) goto _err; - } dsnoop->spcm = spcm; }