• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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