• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <errno.h>
7 #include <stddef.h>
8 #include <stdlib.h>
9 #include <syslog.h>
10 
11 #include "cras_audio_format.h"
12 
13 
14 /* Table for allowed alternatives when doing channel re-mapping.
15  * When channel_alt[X][Y] is non-zero, it's allowed to map channel
16  * from X to Y. */
17 static const int channel_alt[CRAS_CH_MAX][CRAS_CH_MAX] =
18 {
19 	/* FL FR RL RR FC LFE SL SR RC FLC FRC */
20 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* FL */
21 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* FR */
22 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* RL */
23 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* RR */
24 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* FC */
25 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* LFE */
26 	{  0, 0, 1, 0, 0, 0,  0, 0, 0, 0,  0 }, /* SL */
27 	{  0, 0, 0, 1, 0, 0,  0, 0, 0, 0,  0 }, /* SR */
28 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* RC */
29 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* FLC */
30 	{  0, 0, 0, 0, 0, 0,  0, 0, 0, 0,  0 }, /* FRC */
31 };
32 
33 /* Create an audio format structure. */
cras_audio_format_create(snd_pcm_format_t format,size_t frame_rate,size_t num_channels)34 struct cras_audio_format *cras_audio_format_create(snd_pcm_format_t format,
35 						   size_t frame_rate,
36 						   size_t num_channels)
37 {
38 	struct cras_audio_format *fmt;
39 	unsigned i;
40 
41 	fmt = (struct cras_audio_format *)calloc(1, sizeof(*fmt));
42 	if (fmt == NULL)
43 		return fmt;
44 
45 	fmt->format = format;
46 	fmt->frame_rate = frame_rate;
47 	fmt->num_channels = num_channels;
48 
49 	/* Set a default working channel layout according to num_channels.
50 	 * Initialize all other channel position to -1(not set)
51 	 */
52 	for (i = 0; i < CRAS_CH_MAX; i++)
53 		fmt->channel_layout[i] = (i < num_channels) ? i : -1;
54 
55 	return fmt;
56 }
57 
cras_audio_format_set_channel_layout(struct cras_audio_format * format,const int8_t layout[CRAS_CH_MAX])58 int cras_audio_format_set_channel_layout(struct cras_audio_format *format,
59 					 const int8_t layout[CRAS_CH_MAX])
60 {
61 	int i;
62 
63 	/* Check that the max channel index should not exceed the
64 	 * channel count set in format.
65 	 */
66 	for (i = 0; i < CRAS_CH_MAX; i++)
67 		if (layout[i] >= (int)format->num_channels)
68 			return -EINVAL;
69 
70 	for (i = 0; i < CRAS_CH_MAX; i++)
71 		format->channel_layout[i] = layout[i];
72 
73 	return 0;
74 }
75 
76 /* Destroy an audio format struct created with cras_audio_format_crate. */
cras_audio_format_destroy(struct cras_audio_format * fmt)77 void cras_audio_format_destroy(struct cras_audio_format *fmt)
78 {
79 	free(fmt);
80 }
81 
cras_channel_conv_matrix_alloc(size_t in_ch,size_t out_ch)82 float** cras_channel_conv_matrix_alloc(size_t in_ch, size_t out_ch)
83 {
84 	size_t i;
85 	float **p;
86 	p = (float **)calloc(out_ch, sizeof(*p));
87 	if (p == NULL)
88 		return NULL;
89 	for (i = 0; i < out_ch; i++) {
90 		p[i] = (float *)calloc(in_ch, sizeof(*p[i]));
91 		if (p[i] == NULL)
92 			goto alloc_err;
93 	}
94 	return p;
95 
96 alloc_err:
97 	if (p)
98 		cras_channel_conv_matrix_destroy(p, out_ch);
99 	return NULL;
100 }
101 
cras_channel_conv_matrix_destroy(float ** p,size_t out_ch)102 void cras_channel_conv_matrix_destroy(float **p, size_t out_ch)
103 {
104 	size_t i;
105 	for (i = 0; i < out_ch; i ++)
106 		free(p[i]);
107 	free(p);
108 }
109 
cras_channel_conv_matrix_create(const struct cras_audio_format * in,const struct cras_audio_format * out)110 float **cras_channel_conv_matrix_create(const struct cras_audio_format *in,
111 					const struct cras_audio_format *out)
112 {
113 	int i;
114 	float **mtx;
115 
116 	for (i = 0; i < CRAS_CH_MAX; i++) {
117 		if (in->channel_layout[i] >= (int)in->num_channels ||
118 		    out->channel_layout[i] >= (int)out->num_channels) {
119 			syslog(LOG_ERR, "Fail to create conversion matrix "
120 					"due to invalid channel layout");
121 			return NULL;
122 		}
123 	}
124 
125 	mtx = cras_channel_conv_matrix_alloc(in->num_channels,
126 					     out->num_channels);
127 
128 	/* For the in/out format pair which has the same set of channels
129 	 * in use, create a permutation matrix for them.
130 	 */
131 	for (i = 0; i < CRAS_CH_MAX; i++) {
132 		if (in->channel_layout[i] == -1 &&
133 		    out->channel_layout[i] == -1)
134 			continue;
135 		if (in->channel_layout[i] != -1 &&
136 		    out->channel_layout[i] != -1)
137 			mtx[out->channel_layout[i]][in->channel_layout[i]] = 1;
138 		else if (in->channel_layout[i] != -1) {
139 			/* When the same channel does not appear at output
140 			 * channel layout. Look up for allowed channel
141 			 * alternatives.
142 			 */
143 			int alt;
144 			for (alt = 0; alt <= CRAS_CH_MAX; alt++) {
145 				if (alt == CRAS_CH_MAX)
146 					goto fail;
147 				if (channel_alt[i][alt] &&
148 				    in->channel_layout[alt] == -1 &&
149 				    out->channel_layout[alt] != -1) {
150 					mtx[out->channel_layout[alt]]
151 					    [in->channel_layout[i]] = 1;
152 					break;
153 				}
154 			}
155 		}
156 	}
157 
158 	return mtx;
159 fail:
160 	cras_channel_conv_matrix_destroy(mtx, out->num_channels);
161 	return NULL;
162 }
163