1 /***
2 This file is part of PulseAudio.
3
4 PulseAudio is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published
6 by the Free Software Foundation; either version 2.1 of the License,
7 or (at your option) any later version.
8
9 PulseAudio is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
16 ***/
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include "core-format.h"
23
24 #include <pulse/def.h>
25 #include <pulse/xmalloc.h>
26
27 #include <pulsecore/macro.h>
28
pa_format_info_from_sample_spec2(const pa_sample_spec * ss,const pa_channel_map * map,bool set_format,bool set_rate,bool set_channels)29 pa_format_info *pa_format_info_from_sample_spec2(const pa_sample_spec *ss, const pa_channel_map *map, bool set_format,
30 bool set_rate, bool set_channels) {
31 pa_format_info *format = NULL;
32
33 pa_assert(ss);
34
35 format = pa_format_info_new();
36 format->encoding = PA_ENCODING_PCM;
37
38 if (set_format)
39 pa_format_info_set_sample_format(format, ss->format);
40
41 if (set_rate)
42 pa_format_info_set_rate(format, ss->rate);
43
44 if (set_channels) {
45 pa_format_info_set_channels(format, ss->channels);
46
47 if (map) {
48 if (map->channels != ss->channels) {
49 pa_log_debug("Channel map is incompatible with the sample spec.");
50 goto fail;
51 }
52
53 pa_format_info_set_channel_map(format, map);
54 }
55 }
56
57 return format;
58
59 fail:
60 if (format)
61 pa_format_info_free(format);
62
63 return NULL;
64 }
65
pa_format_info_to_sample_spec2(const pa_format_info * f,pa_sample_spec * ss,pa_channel_map * map,const pa_sample_spec * fallback_ss,const pa_channel_map * fallback_map)66 int pa_format_info_to_sample_spec2(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map,
67 const pa_sample_spec *fallback_ss, const pa_channel_map *fallback_map) {
68 int r, r2;
69 pa_sample_spec ss_local;
70 pa_channel_map map_local;
71
72 pa_assert(f);
73 pa_assert(ss);
74 pa_assert(map);
75 pa_assert(fallback_ss);
76 pa_assert(fallback_map);
77
78 if (!pa_format_info_is_pcm(f))
79 return pa_format_info_to_sample_spec_fake(f, ss, map);
80
81 r = pa_format_info_get_sample_format(f, &ss_local.format);
82 if (r == -PA_ERR_NOENTITY)
83 ss_local.format = fallback_ss->format;
84 else if (r < 0)
85 return r;
86
87 pa_assert(pa_sample_format_valid(ss_local.format));
88
89 r = pa_format_info_get_rate(f, &ss_local.rate);
90 if (r == -PA_ERR_NOENTITY)
91 ss_local.rate = fallback_ss->rate;
92 else if (r < 0)
93 return r;
94
95 pa_assert(pa_sample_rate_valid(ss_local.rate));
96
97 r = pa_format_info_get_channels(f, &ss_local.channels);
98 r2 = pa_format_info_get_channel_map(f, &map_local);
99 if (r == -PA_ERR_NOENTITY && r2 >= 0)
100 ss_local.channels = map_local.channels;
101 else if (r == -PA_ERR_NOENTITY)
102 ss_local.channels = fallback_ss->channels;
103 else if (r < 0)
104 return r;
105
106 pa_assert(pa_channels_valid(ss_local.channels));
107
108 if (r2 >= 0 && map_local.channels != ss_local.channels) {
109 pa_log_debug("Channel map is not compatible with the sample spec.");
110 return -PA_ERR_INVALID;
111 }
112
113 if (r2 == -PA_ERR_NOENTITY) {
114 if (fallback_map->channels == ss_local.channels)
115 map_local = *fallback_map;
116 else
117 pa_channel_map_init_extend(&map_local, ss_local.channels, PA_CHANNEL_MAP_DEFAULT);
118 } else if (r2 < 0)
119 return r2;
120
121 pa_assert(pa_channel_map_valid(&map_local));
122 pa_assert(ss_local.channels == map_local.channels);
123
124 *ss = ss_local;
125 *map = map_local;
126
127 return 0;
128 }
129
pa_format_info_to_sample_spec_fake(const pa_format_info * f,pa_sample_spec * ss,pa_channel_map * map)130 int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
131 int rate;
132
133 pa_assert(f);
134 pa_assert(ss);
135
136 /* Note: When we add support for non-IEC61937 encapsulated compressed
137 * formats, this function should return a non-zero values for these. */
138
139 ss->format = PA_SAMPLE_S16LE;
140 if ((f->encoding == PA_ENCODING_TRUEHD_IEC61937) ||
141 (f->encoding == PA_ENCODING_DTSHD_IEC61937)) {
142 ss->channels = 8;
143 if (map) {
144 /* We use the ALSA mapping, because most likely we will be using an
145 * ALSA sink. This doesn't really matter anyway, though, because
146 * the channel map doesn't affect anything with passthrough
147 * streams. The channel map just needs to be consistent with the
148 * sample spec's channel count. */
149 pa_channel_map_init_auto(map, 8, PA_CHANNEL_MAP_ALSA);
150 }
151 } else {
152 ss->channels = 2;
153 if (map)
154 pa_channel_map_init_stereo(map);
155 }
156
157 pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID);
158 ss->rate = (uint32_t) rate;
159
160 if (f->encoding == PA_ENCODING_EAC3_IEC61937)
161 ss->rate *= 4;
162
163 return 0;
164 }
165