1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2c72fcc34Sopenharmony_ci//
3c72fcc34Sopenharmony_ci// frame-cache.c - maintainer of cache for data frame.
4c72fcc34Sopenharmony_ci//
5c72fcc34Sopenharmony_ci// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6c72fcc34Sopenharmony_ci//
7c72fcc34Sopenharmony_ci// Licensed under the terms of the GNU General Public License, version 2.
8c72fcc34Sopenharmony_ci
9c72fcc34Sopenharmony_ci#include "frame-cache.h"
10c72fcc34Sopenharmony_ci
11c72fcc34Sopenharmony_cistatic void align_frames_in_i(struct frame_cache *cache,
12c72fcc34Sopenharmony_ci			      unsigned int consumed_count)
13c72fcc34Sopenharmony_ci{
14c72fcc34Sopenharmony_ci	char *buf = cache->buf;
15c72fcc34Sopenharmony_ci	unsigned int offset;
16c72fcc34Sopenharmony_ci	unsigned int size;
17c72fcc34Sopenharmony_ci
18c72fcc34Sopenharmony_ci	cache->remained_count -= consumed_count;
19c72fcc34Sopenharmony_ci
20c72fcc34Sopenharmony_ci	offset = cache->bytes_per_sample * cache->samples_per_frame *
21c72fcc34Sopenharmony_ci		 consumed_count;
22c72fcc34Sopenharmony_ci	size = cache->bytes_per_sample * cache->samples_per_frame *
23c72fcc34Sopenharmony_ci	       cache->remained_count;
24c72fcc34Sopenharmony_ci	memmove(buf, buf + offset, size);
25c72fcc34Sopenharmony_ci
26c72fcc34Sopenharmony_ci	cache->buf_ptr = buf + size;
27c72fcc34Sopenharmony_ci}
28c72fcc34Sopenharmony_ci
29c72fcc34Sopenharmony_cistatic void align_frames_in_n(struct frame_cache *cache,
30c72fcc34Sopenharmony_ci			      unsigned int consumed_count)
31c72fcc34Sopenharmony_ci{
32c72fcc34Sopenharmony_ci	char **bufs = cache->buf;
33c72fcc34Sopenharmony_ci	char **buf_ptrs = cache->buf_ptr;
34c72fcc34Sopenharmony_ci	unsigned int offset;
35c72fcc34Sopenharmony_ci	unsigned int size;
36c72fcc34Sopenharmony_ci	unsigned int i;
37c72fcc34Sopenharmony_ci
38c72fcc34Sopenharmony_ci	cache->remained_count -= consumed_count;
39c72fcc34Sopenharmony_ci
40c72fcc34Sopenharmony_ci	for (i = 0; i < cache->samples_per_frame; ++i) {
41c72fcc34Sopenharmony_ci		offset = cache->bytes_per_sample * consumed_count;
42c72fcc34Sopenharmony_ci		size = cache->bytes_per_sample * cache->remained_count;
43c72fcc34Sopenharmony_ci		memmove(bufs[i], bufs[i] + offset, size);
44c72fcc34Sopenharmony_ci		buf_ptrs[i] = bufs[i] + size;
45c72fcc34Sopenharmony_ci	}
46c72fcc34Sopenharmony_ci}
47c72fcc34Sopenharmony_ci
48c72fcc34Sopenharmony_ciint frame_cache_init(struct frame_cache *cache, snd_pcm_access_t access,
49c72fcc34Sopenharmony_ci		     unsigned int bytes_per_sample,
50c72fcc34Sopenharmony_ci		     unsigned int samples_per_frame,
51c72fcc34Sopenharmony_ci		     unsigned int frames_per_cache)
52c72fcc34Sopenharmony_ci{
53c72fcc34Sopenharmony_ci	cache->access = access;
54c72fcc34Sopenharmony_ci	cache->remained_count = 0;
55c72fcc34Sopenharmony_ci	cache->bytes_per_sample = bytes_per_sample;
56c72fcc34Sopenharmony_ci	cache->samples_per_frame = samples_per_frame;
57c72fcc34Sopenharmony_ci	cache->frames_per_cache = frames_per_cache;
58c72fcc34Sopenharmony_ci
59c72fcc34Sopenharmony_ci	if (access == SND_PCM_ACCESS_RW_INTERLEAVED)
60c72fcc34Sopenharmony_ci		cache->align_frames = align_frames_in_i;
61c72fcc34Sopenharmony_ci	else if (access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
62c72fcc34Sopenharmony_ci		cache->align_frames = align_frames_in_n;
63c72fcc34Sopenharmony_ci	else
64c72fcc34Sopenharmony_ci		return -EINVAL;
65c72fcc34Sopenharmony_ci
66c72fcc34Sopenharmony_ci	if (access == SND_PCM_ACCESS_RW_INTERLEAVED) {
67c72fcc34Sopenharmony_ci		char *buf;
68c72fcc34Sopenharmony_ci
69c72fcc34Sopenharmony_ci		buf = calloc(frames_per_cache,
70c72fcc34Sopenharmony_ci			     bytes_per_sample * samples_per_frame);
71c72fcc34Sopenharmony_ci		if (buf == NULL)
72c72fcc34Sopenharmony_ci			goto nomem;
73c72fcc34Sopenharmony_ci		cache->buf = buf;
74c72fcc34Sopenharmony_ci		cache->buf_ptr = buf;
75c72fcc34Sopenharmony_ci	} else {
76c72fcc34Sopenharmony_ci		char **bufs = calloc(samples_per_frame, sizeof(*bufs));
77c72fcc34Sopenharmony_ci		char **buf_ptrs = calloc(samples_per_frame, sizeof(*buf_ptrs));
78c72fcc34Sopenharmony_ci		unsigned int i;
79c72fcc34Sopenharmony_ci
80c72fcc34Sopenharmony_ci		cache->buf = bufs;
81c72fcc34Sopenharmony_ci		cache->buf_ptr = buf_ptrs;
82c72fcc34Sopenharmony_ci		if (bufs == NULL || buf_ptrs == NULL)
83c72fcc34Sopenharmony_ci			goto nomem;
84c72fcc34Sopenharmony_ci		for (i = 0; i < samples_per_frame; ++i) {
85c72fcc34Sopenharmony_ci			bufs[i] = calloc(frames_per_cache, bytes_per_sample);
86c72fcc34Sopenharmony_ci			if (bufs[i] == NULL)
87c72fcc34Sopenharmony_ci				goto nomem;
88c72fcc34Sopenharmony_ci			buf_ptrs[i] = bufs[i];
89c72fcc34Sopenharmony_ci		}
90c72fcc34Sopenharmony_ci	}
91c72fcc34Sopenharmony_ci
92c72fcc34Sopenharmony_ci
93c72fcc34Sopenharmony_ci	return 0;
94c72fcc34Sopenharmony_ci
95c72fcc34Sopenharmony_cinomem:
96c72fcc34Sopenharmony_ci	frame_cache_destroy(cache);
97c72fcc34Sopenharmony_ci	return -ENOMEM;
98c72fcc34Sopenharmony_ci}
99c72fcc34Sopenharmony_ci
100c72fcc34Sopenharmony_civoid frame_cache_destroy(struct frame_cache *cache)
101c72fcc34Sopenharmony_ci{
102c72fcc34Sopenharmony_ci	if (cache->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
103c72fcc34Sopenharmony_ci		char **bufs = cache->buf;
104c72fcc34Sopenharmony_ci		if (bufs) {
105c72fcc34Sopenharmony_ci			unsigned int i;
106c72fcc34Sopenharmony_ci			for (i = 0; i < cache->samples_per_frame; ++i)
107c72fcc34Sopenharmony_ci				free(bufs[i]);
108c72fcc34Sopenharmony_ci		}
109c72fcc34Sopenharmony_ci		free(cache->buf_ptr);
110c72fcc34Sopenharmony_ci	}
111c72fcc34Sopenharmony_ci	free(cache->buf);
112c72fcc34Sopenharmony_ci	memset(cache, 0, sizeof(*cache));
113c72fcc34Sopenharmony_ci}
114