mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-03 09:01:52 -05:00
pcm - fix the buffer allocation for NONINTERLEAVED mmap access
The previous code did not allocated a separate buffer for all channels when a NONINTERLEAVED access was used. The result was that only one "shared" buffer was incorrectly allocated. Also, the code was a bit cleaned (cosmetic change only).
This commit is contained in:
parent
2f65643c1c
commit
b08e01ca9e
1 changed files with 113 additions and 105 deletions
|
|
@ -326,122 +326,130 @@ int snd_pcm_mmap(snd_pcm_t *pcm)
|
||||||
for (c = 0; c < pcm->channels; ++c) {
|
for (c = 0; c < pcm->channels; ++c) {
|
||||||
snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
|
snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
|
||||||
snd_pcm_channel_area_t *a = &pcm->running_areas[c];
|
snd_pcm_channel_area_t *a = &pcm->running_areas[c];
|
||||||
|
char *ptr;
|
||||||
|
size_t size;
|
||||||
unsigned int c1;
|
unsigned int c1;
|
||||||
if (!i->addr) {
|
if (i->addr) {
|
||||||
char *ptr;
|
a->addr = i->addr;
|
||||||
size_t size = i->first + i->step * (pcm->buffer_size - 1) + pcm->sample_bits;
|
a->first = i->first;
|
||||||
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
a->step = i->step;
|
||||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
continue;
|
||||||
size_t s;
|
}
|
||||||
if (i1->type != i->type)
|
size = i->first + i->step * (pcm->buffer_size - 1) + pcm->sample_bits;
|
||||||
continue;
|
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
||||||
switch (i1->type) {
|
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||||
case SND_PCM_AREA_MMAP:
|
size_t s;
|
||||||
if (i1->u.mmap.fd != i->u.mmap.fd ||
|
if (i1->type != i->type)
|
||||||
i1->u.mmap.offset != i->u.mmap.offset)
|
continue;
|
||||||
continue;
|
switch (i1->type) {
|
||||||
break;
|
|
||||||
case SND_PCM_AREA_SHM:
|
|
||||||
if (i1->u.shm.shmid != i->u.shm.shmid)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
case SND_PCM_AREA_LOCAL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
s = i1->first + i1->step * (pcm->buffer_size - 1) + pcm->sample_bits;
|
|
||||||
if (s > size)
|
|
||||||
size = s;
|
|
||||||
}
|
|
||||||
size = (size + 7) / 8;
|
|
||||||
size = page_align(size);
|
|
||||||
switch (i->type) {
|
|
||||||
case SND_PCM_AREA_MMAP:
|
case SND_PCM_AREA_MMAP:
|
||||||
ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
|
if (i1->u.mmap.fd != i->u.mmap.fd ||
|
||||||
if (ptr == MAP_FAILED) {
|
i1->u.mmap.offset != i->u.mmap.offset)
|
||||||
SYSERR("mmap failed");
|
continue;
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
i->addr = ptr;
|
|
||||||
break;
|
break;
|
||||||
case SND_PCM_AREA_SHM:
|
case SND_PCM_AREA_SHM:
|
||||||
if (i->u.shm.shmid < 0) {
|
if (i1->u.shm.shmid != i->u.shm.shmid)
|
||||||
int id;
|
continue;
|
||||||
/* FIXME: safer permission? */
|
|
||||||
id = shmget(IPC_PRIVATE, size, 0666);
|
|
||||||
if (id < 0) {
|
|
||||||
SYSERR("shmget failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
i->u.shm.shmid = id;
|
|
||||||
ptr = shmat(i->u.shm.shmid, 0, 0);
|
|
||||||
if (ptr == (void *) -1) {
|
|
||||||
SYSERR("shmat failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
/* automatically remove segment if not used */
|
|
||||||
if (shmctl(id, IPC_RMID, NULL) < 0){
|
|
||||||
SYSERR("shmctl mark remove failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
i->u.shm.area = snd_shm_area_create(id, ptr);
|
|
||||||
if (i->u.shm.area == NULL) {
|
|
||||||
SYSERR("snd_shm_area_create failed");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
|
|
||||||
pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
|
||||||
unsigned int c1;
|
|
||||||
for (c1 = c + 1; c1 < pcm->channels; c1++) {
|
|
||||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
|
||||||
if (i1->u.shm.shmid < 0) {
|
|
||||||
i1->u.shm.shmid = id;
|
|
||||||
i1->u.shm.area = snd_shm_area_share(i->u.shm.area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ptr = shmat(i->u.shm.shmid, 0, 0);
|
|
||||||
if (ptr == (void*) -1) {
|
|
||||||
SYSERR("shmat failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i->addr = ptr;
|
|
||||||
break;
|
break;
|
||||||
case SND_PCM_AREA_LOCAL:
|
case SND_PCM_AREA_LOCAL:
|
||||||
ptr = malloc(size);
|
|
||||||
if (ptr == NULL) {
|
|
||||||
SYSERR("malloc failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
i->addr = ptr;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
s = i1->first + i1->step * (pcm->buffer_size - 1) + pcm->sample_bits;
|
||||||
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
if (s > size)
|
||||||
if (i1->type != i->type)
|
size = s;
|
||||||
continue;
|
}
|
||||||
switch (i1->type) {
|
size = (size + 7) / 8;
|
||||||
case SND_PCM_AREA_MMAP:
|
size = page_align(size);
|
||||||
if (i1->u.mmap.fd != i->u.mmap.fd ||
|
switch (i->type) {
|
||||||
i1->u.mmap.offset != i->u.mmap.offset)
|
case SND_PCM_AREA_MMAP:
|
||||||
continue;
|
ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
|
||||||
break;
|
if (ptr == MAP_FAILED) {
|
||||||
case SND_PCM_AREA_SHM:
|
SYSERR("mmap failed");
|
||||||
if (i1->u.shm.shmid != i->u.shm.shmid)
|
return -errno;
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
case SND_PCM_AREA_LOCAL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
i1->addr = i->addr;
|
|
||||||
}
|
}
|
||||||
|
i->addr = ptr;
|
||||||
|
break;
|
||||||
|
case SND_PCM_AREA_SHM:
|
||||||
|
if (i->u.shm.shmid < 0) {
|
||||||
|
int id;
|
||||||
|
/* FIXME: safer permission? */
|
||||||
|
id = shmget(IPC_PRIVATE, size, 0666);
|
||||||
|
if (id < 0) {
|
||||||
|
SYSERR("shmget failed");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
i->u.shm.shmid = id;
|
||||||
|
ptr = shmat(i->u.shm.shmid, 0, 0);
|
||||||
|
if (ptr == (void *) -1) {
|
||||||
|
SYSERR("shmat failed");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
/* automatically remove segment if not used */
|
||||||
|
if (shmctl(id, IPC_RMID, NULL) < 0){
|
||||||
|
SYSERR("shmctl mark remove failed");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
i->u.shm.area = snd_shm_area_create(id, ptr);
|
||||||
|
if (i->u.shm.area == NULL) {
|
||||||
|
SYSERR("snd_shm_area_create failed");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
|
||||||
|
pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
|
unsigned int c1;
|
||||||
|
for (c1 = c + 1; c1 < pcm->channels; c1++) {
|
||||||
|
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||||
|
if (i1->u.shm.shmid < 0) {
|
||||||
|
i1->u.shm.shmid = id;
|
||||||
|
i1->u.shm.area = snd_shm_area_share(i->u.shm.area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptr = shmat(i->u.shm.shmid, 0, 0);
|
||||||
|
if (ptr == (void*) -1) {
|
||||||
|
SYSERR("shmat failed");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i->addr = ptr;
|
||||||
|
break;
|
||||||
|
case SND_PCM_AREA_LOCAL:
|
||||||
|
ptr = malloc(size);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
SYSERR("malloc failed");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
i->addr = ptr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
for (c1 = c + 1; c1 < pcm->channels; ++c1) {
|
||||||
|
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
|
||||||
|
if (i1->type != i->type)
|
||||||
|
continue;
|
||||||
|
switch (i1->type) {
|
||||||
|
case SND_PCM_AREA_MMAP:
|
||||||
|
if (i1->u.mmap.fd != i->u.mmap.fd ||
|
||||||
|
i1->u.mmap.offset != i->u.mmap.offset)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case SND_PCM_AREA_SHM:
|
||||||
|
if (i1->u.shm.shmid != i->u.shm.shmid)
|
||||||
|
continue;
|
||||||
|
/* follow thru */
|
||||||
|
case SND_PCM_AREA_LOCAL:
|
||||||
|
if (pcm->access != SND_PCM_ACCESS_MMAP_INTERLEAVED &&
|
||||||
|
pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
i1->addr = i->addr;
|
||||||
}
|
}
|
||||||
a->addr = i->addr;
|
a->addr = i->addr;
|
||||||
a->first = i->first;
|
a->first = i->first;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue