Home | History | Annotate | Download | only in common
      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. */
     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 
     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. */
     77 void cras_audio_format_destroy(struct cras_audio_format *fmt)
     78 {
     79 	free(fmt);
     80 }
     81 
     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 
    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 
    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