Git init
[framework/multimedia/pulseaudio.git] / src / pulsecore / mime-type.c
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, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <pulse/xmalloc.h>
27 #include <pulsecore/core-util.h>
28
29 #include "mime-type.h"
30
31 pa_bool_t pa_sample_spec_is_mime(const pa_sample_spec *ss, const pa_channel_map *cm) {
32
33     pa_assert(pa_channel_map_compatible(cm, ss));
34
35     switch (ss->format) {
36         case PA_SAMPLE_S16BE:
37         case PA_SAMPLE_S24BE:
38         case PA_SAMPLE_U8:
39
40             if (ss->rate != 8000 &&
41                 ss->rate != 11025 &&
42                 ss->rate != 16000 &&
43                 ss->rate != 22050 &&
44                 ss->rate != 24000 &&
45                 ss->rate != 32000 &&
46                 ss->rate != 44100 &&
47                 ss->rate != 48000)
48                 return FALSE;
49
50             if (ss->channels != 1 &&
51                 ss->channels != 2)
52                 return FALSE;
53
54             if ((cm->channels == 1 && cm->map[0] != PA_CHANNEL_POSITION_MONO) ||
55                 (cm->channels == 2 && (cm->map[0] != PA_CHANNEL_POSITION_LEFT || cm->map[1] != PA_CHANNEL_POSITION_RIGHT)))
56                 return FALSE;
57
58             return TRUE;
59
60         case PA_SAMPLE_ULAW:
61
62             if (ss->rate != 8000)
63                 return FALSE;
64
65             if (ss->channels != 1)
66                 return FALSE;
67
68             if (cm->map[0] != PA_CHANNEL_POSITION_MONO)
69                 return FALSE;
70
71             return TRUE;
72
73         default:
74             return FALSE;
75     }
76 }
77
78 void pa_sample_spec_mimefy(pa_sample_spec *ss, pa_channel_map *cm) {
79
80     pa_assert(pa_channel_map_compatible(cm, ss));
81
82     /* Turns the sample type passed in into the next 'better' one that
83      * can be encoded for HTTP. If there is no 'better' one we pick
84      * the 'best' one that is 'worse'. */
85
86     if (ss->channels > 2)
87         ss->channels = 2;
88
89     if (ss->rate > 44100)
90         ss->rate = 48000;
91     else if (ss->rate > 32000)
92         ss->rate = 44100;
93     else if (ss->rate > 24000)
94         ss->rate = 32000;
95     else if (ss->rate > 22050)
96         ss->rate = 24000;
97     else if (ss->rate > 16000)
98         ss->rate = 22050;
99     else if (ss->rate > 11025)
100         ss->rate = 16000;
101     else if (ss->rate > 8000)
102         ss->rate = 11025;
103     else
104         ss->rate = 8000;
105
106     switch (ss->format) {
107         case PA_SAMPLE_S24BE:
108         case PA_SAMPLE_S24LE:
109         case PA_SAMPLE_S24_32LE:
110         case PA_SAMPLE_S24_32BE:
111         case PA_SAMPLE_S32LE:
112         case PA_SAMPLE_S32BE:
113         case PA_SAMPLE_FLOAT32LE:
114         case PA_SAMPLE_FLOAT32BE:
115             ss->format = PA_SAMPLE_S24BE;
116             break;
117
118         case PA_SAMPLE_S16BE:
119         case PA_SAMPLE_S16LE:
120             ss->format = PA_SAMPLE_S16BE;
121             break;
122
123         case PA_SAMPLE_ULAW:
124         case PA_SAMPLE_ALAW:
125
126             if (ss->rate == 8000 && ss->channels == 1)
127                 ss->format = PA_SAMPLE_ULAW;
128             else
129                 ss->format = PA_SAMPLE_S16BE;
130             break;
131
132         case PA_SAMPLE_U8:
133             ss->format = PA_SAMPLE_U8;
134             break;
135
136         case PA_SAMPLE_MAX:
137         case PA_SAMPLE_INVALID:
138             pa_assert_not_reached();
139     }
140
141     pa_channel_map_init_auto(cm, ss->channels, PA_CHANNEL_MAP_DEFAULT);
142
143     pa_assert(pa_sample_spec_is_mime(ss, cm));
144 }
145
146 char *pa_sample_spec_to_mime_type(const pa_sample_spec *ss, const pa_channel_map *cm) {
147     pa_assert(pa_channel_map_compatible(cm, ss));
148
149     if (!pa_sample_spec_is_mime(ss, cm))
150         return NULL;
151
152     switch (ss->format) {
153
154         case PA_SAMPLE_S16BE:
155         case PA_SAMPLE_S24BE:
156         case PA_SAMPLE_U8:
157             /* Stupid UPnP implementations (PS3...) choke on spaces in
158              * the mime type, that's why we write only ';' here,
159              * instead of '; '. */
160             return pa_sprintf_malloc("audio/%s;rate=%u;channels=%u",
161                                      ss->format == PA_SAMPLE_S16BE ? "L16" :
162                                      (ss->format == PA_SAMPLE_S24BE ? "L24" : "L8"),
163                                      ss->rate, ss->channels);
164
165         case PA_SAMPLE_ULAW:
166             return pa_xstrdup("audio/basic");
167
168         default:
169             pa_assert_not_reached();
170     }
171
172     pa_assert(pa_sample_spec_valid(ss));
173 }
174
175 char *pa_sample_spec_to_mime_type_mimefy(const pa_sample_spec *_ss, const pa_channel_map *_cm) {
176     pa_sample_spec ss = *_ss;
177     pa_channel_map cm = *_cm;
178
179     pa_sample_spec_mimefy(&ss, &cm);
180
181     return pa_sample_spec_to_mime_type(&ss, &cm);
182 }