mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 04:25:41 +01:00
c2f79d9fdf
In alsa-lib PCM API, snd_pcm_read[i|n]() and snd_pcm_write[i|n]() are used to transfer data frames from/to hardware. When a handler is not opened with specific flags, these functions perform blocking operation; i.e. the function call doesn't return till all of request number of data frames are actually handled, or call is interrupted by Unix signals, or PCM substeam corrupts due to hardware reasons. This commit adds support for this type of data transmission. For cases that requested data frames are not processed by container interface, this commit adds internal cache mechanism to handle rest of data frames in next timing. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
111 lines
2.8 KiB
C
111 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// frame-cache.c - maintainer of cache for data frame.
|
|
//
|
|
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
|
//
|
|
// Licensed under the terms of the GNU General Public License, version 2.
|
|
|
|
#include "frame-cache.h"
|
|
|
|
static void align_frames_in_i(struct frame_cache *cache,
|
|
unsigned int consumed_count)
|
|
{
|
|
char *buf = cache->buf;
|
|
unsigned int offset;
|
|
unsigned int size;
|
|
|
|
cache->remained_count -= consumed_count;
|
|
|
|
offset = cache->bytes_per_sample * cache->samples_per_frame *
|
|
consumed_count;
|
|
size = cache->bytes_per_sample * cache->samples_per_frame *
|
|
cache->remained_count;
|
|
memmove(buf, buf + offset, size);
|
|
|
|
cache->buf_ptr = buf + size;
|
|
}
|
|
|
|
static void align_frames_in_n(struct frame_cache *cache,
|
|
unsigned int consumed_count)
|
|
{
|
|
char **bufs = cache->buf;
|
|
char **buf_ptrs = cache->buf_ptr;
|
|
unsigned int offset;
|
|
unsigned int size;
|
|
int i;
|
|
|
|
cache->remained_count -= consumed_count;
|
|
|
|
for (i = 0; i < cache->samples_per_frame; ++i) {
|
|
offset = cache->bytes_per_sample * consumed_count;
|
|
size = cache->bytes_per_sample * cache->remained_count;
|
|
memmove(bufs[i], bufs[i] + offset, size);
|
|
buf_ptrs[i] = bufs[i] + size;
|
|
}
|
|
}
|
|
|
|
int frame_cache_init(struct frame_cache *cache, snd_pcm_access_t access,
|
|
unsigned int bytes_per_sample,
|
|
unsigned int samples_per_frame,
|
|
unsigned int frames_per_cache)
|
|
{
|
|
if (access == SND_PCM_ACCESS_RW_INTERLEAVED)
|
|
cache->align_frames = align_frames_in_i;
|
|
else if (access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
|
|
cache->align_frames = align_frames_in_n;
|
|
else
|
|
return -EINVAL;
|
|
cache->access = access;
|
|
|
|
if (access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
|
char *buf;
|
|
|
|
buf = calloc(frames_per_cache,
|
|
bytes_per_sample * samples_per_frame);
|
|
if (buf == NULL)
|
|
return -ENOMEM;
|
|
cache->buf = buf;
|
|
cache->buf_ptr = buf;
|
|
} else {
|
|
char **bufs;
|
|
char **buf_ptrs;
|
|
int i;
|
|
|
|
bufs = calloc(samples_per_frame, sizeof(*bufs));
|
|
if (bufs == NULL)
|
|
return -ENOMEM;
|
|
buf_ptrs = calloc(samples_per_frame, sizeof(*buf_ptrs));
|
|
if (buf_ptrs == NULL)
|
|
return -ENOMEM;
|
|
for (i = 0; i < samples_per_frame; ++i) {
|
|
bufs[i] = calloc(frames_per_cache, bytes_per_sample);
|
|
if (bufs[i] == NULL)
|
|
return -ENOMEM;
|
|
buf_ptrs[i] = bufs[i];
|
|
}
|
|
cache->buf = bufs;
|
|
cache->buf_ptr = buf_ptrs;
|
|
}
|
|
|
|
cache->remained_count = 0;
|
|
cache->bytes_per_sample = bytes_per_sample;
|
|
cache->samples_per_frame = samples_per_frame;
|
|
cache->frames_per_cache = frames_per_cache;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void frame_cache_destroy(struct frame_cache *cache)
|
|
{
|
|
if (cache->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
|
int i;
|
|
for (i = 0; i < cache->samples_per_frame; ++i) {
|
|
char **bufs = cache->buf;
|
|
free(bufs[i]);
|
|
}
|
|
free(cache->buf_ptr);
|
|
}
|
|
free(cache->buf);
|
|
memset(cache, 0, sizeof(*cache));
|
|
}
|