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