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