1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2005-2009 Lennart Poettering
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <pulse/xmalloc.h>
25 #include <pulsecore/core-util.h>
26
27 #include "mime-type.h"
28
pa_sample_spec_is_mime(const pa_sample_spec * ss,const pa_channel_map * cm)29 bool pa_sample_spec_is_mime(const pa_sample_spec *ss, const pa_channel_map *cm) {
30
31 pa_assert(pa_channel_map_compatible(cm, ss));
32
33 switch (ss->format) {
34 case PA_SAMPLE_S16BE:
35 case PA_SAMPLE_S24BE:
36 case PA_SAMPLE_U8:
37
38 if (ss->rate != 8000 &&
39 ss->rate != 11025 &&
40 ss->rate != 16000 &&
41 ss->rate != 22050 &&
42 ss->rate != 24000 &&
43 ss->rate != 32000 &&
44 ss->rate != 44100 &&
45 ss->rate != 48000)
46 return false;
47
48 if (ss->channels != 1 &&
49 ss->channels != 2)
50 return false;
51
52 if ((cm->channels == 1 && cm->map[0] != PA_CHANNEL_POSITION_MONO) ||
53 (cm->channels == 2 && (cm->map[0] != PA_CHANNEL_POSITION_LEFT || cm->map[1] != PA_CHANNEL_POSITION_RIGHT)))
54 return false;
55
56 return true;
57
58 case PA_SAMPLE_ULAW:
59
60 if (ss->rate != 8000)
61 return false;
62
63 if (ss->channels != 1)
64 return false;
65
66 if (cm->map[0] != PA_CHANNEL_POSITION_MONO)
67 return false;
68
69 return true;
70
71 default:
72 return false;
73 }
74 }
75
pa_sample_spec_mimefy(pa_sample_spec * ss,pa_channel_map * cm)76 void pa_sample_spec_mimefy(pa_sample_spec *ss, pa_channel_map *cm) {
77
78 pa_assert(pa_channel_map_compatible(cm, ss));
79
80 /* Turns the sample type passed in into the next 'better' one that
81 * can be encoded for HTTP. If there is no 'better' one we pick
82 * the 'best' one that is 'worse'. */
83
84 if (ss->channels > 2)
85 ss->channels = 2;
86
87 if (ss->rate > 44100)
88 ss->rate = 48000;
89 else if (ss->rate > 32000)
90 ss->rate = 44100;
91 else if (ss->rate > 24000)
92 ss->rate = 32000;
93 else if (ss->rate > 22050)
94 ss->rate = 24000;
95 else if (ss->rate > 16000)
96 ss->rate = 22050;
97 else if (ss->rate > 11025)
98 ss->rate = 16000;
99 else if (ss->rate > 8000)
100 ss->rate = 11025;
101 else
102 ss->rate = 8000;
103
104 switch (ss->format) {
105 case PA_SAMPLE_S24BE:
106 case PA_SAMPLE_S24LE:
107 case PA_SAMPLE_S24_32LE:
108 case PA_SAMPLE_S24_32BE:
109 case PA_SAMPLE_S32LE:
110 case PA_SAMPLE_S32BE:
111 case PA_SAMPLE_FLOAT32LE:
112 case PA_SAMPLE_FLOAT32BE:
113 ss->format = PA_SAMPLE_S24BE;
114 break;
115
116 case PA_SAMPLE_S16BE:
117 case PA_SAMPLE_S16LE:
118 ss->format = PA_SAMPLE_S16BE;
119 break;
120
121 case PA_SAMPLE_ULAW:
122 case PA_SAMPLE_ALAW:
123
124 if (ss->rate == 8000 && ss->channels == 1)
125 ss->format = PA_SAMPLE_ULAW;
126 else
127 ss->format = PA_SAMPLE_S16BE;
128 break;
129
130 case PA_SAMPLE_U8:
131 ss->format = PA_SAMPLE_U8;
132 break;
133
134 case PA_SAMPLE_MAX:
135 case PA_SAMPLE_INVALID:
136 pa_assert_not_reached();
137 }
138
139 pa_channel_map_init_auto(cm, ss->channels, PA_CHANNEL_MAP_DEFAULT);
140
141 pa_assert(pa_sample_spec_is_mime(ss, cm));
142 }
143
pa_sample_spec_to_mime_type(const pa_sample_spec * ss,const pa_channel_map * cm)144 char *pa_sample_spec_to_mime_type(const pa_sample_spec *ss, const pa_channel_map *cm) {
145 pa_assert(pa_channel_map_compatible(cm, ss));
146 pa_assert(pa_sample_spec_valid(ss));
147
148 if (!pa_sample_spec_is_mime(ss, cm))
149 return NULL;
150
151 switch (ss->format) {
152
153 case PA_SAMPLE_S16BE:
154 case PA_SAMPLE_S24BE:
155 case PA_SAMPLE_U8:
156 /* Stupid UPnP implementations (PS3...) choke on spaces in
157 * the mime type, that's why we write only ';' here,
158 * instead of '; '. */
159 return pa_sprintf_malloc("audio/%s;rate=%u;channels=%u",
160 ss->format == PA_SAMPLE_S16BE ? "L16" :
161 (ss->format == PA_SAMPLE_S24BE ? "L24" : "L8"),
162 ss->rate, ss->channels);
163
164 case PA_SAMPLE_ULAW:
165 return pa_xstrdup("audio/basic");
166
167 default:
168 pa_assert_not_reached();
169 }
170 }
171
pa_sample_spec_to_mime_type_mimefy(const pa_sample_spec * _ss,const pa_channel_map * _cm)172 char *pa_sample_spec_to_mime_type_mimefy(const pa_sample_spec *_ss, const pa_channel_map *_cm) {
173 pa_sample_spec ss = *_ss;
174 pa_channel_map cm = *_cm;
175
176 pa_sample_spec_mimefy(&ss, &cm);
177
178 return pa_sample_spec_to_mime_type(&ss, &cm);
179 }
180