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