/src/libsndfile/src/broadcast.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** Copyright (C) 2006-2016 Erik de Castro Lopo <erikd@mega-nerd.com> |
3 | | ** Copyright (C) 2006 Paul Davis <paul@linuxaudiosystems.com> |
4 | | ** |
5 | | ** This program is free software; you can redistribute it and/or modify |
6 | | ** it under the terms of the GNU Lesser General Public License as published by |
7 | | ** the Free Software Foundation; either version 2.1 of the License, or |
8 | | ** (at your option) any later version. |
9 | | ** |
10 | | ** This program is distributed in the hope that it will be useful, |
11 | | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | ** GNU Lesser General Public License for more details. |
14 | | ** |
15 | | ** You should have received a copy of the GNU Lesser General Public License |
16 | | ** along with this program; if not, write to the Free Software |
17 | | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 | | */ |
19 | | |
20 | | #include "sfconfig.h" |
21 | | |
22 | | #include <stdio.h> |
23 | | #include <stddef.h> |
24 | | #include <string.h> |
25 | | |
26 | | #include "common.h" |
27 | | |
28 | | |
29 | | static int gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) ; |
30 | | |
31 | | static inline size_t |
32 | | bc_min_size (const SF_BROADCAST_INFO* info) |
33 | 0 | { if (info == NULL) |
34 | 0 | return 0 ; |
35 | | |
36 | 0 | return offsetof (SF_BROADCAST_INFO, coding_history) + info->coding_history_size ; |
37 | 0 | } /* bc_min_size */ |
38 | | |
39 | | SF_BROADCAST_INFO_16K* |
40 | | broadcast_var_alloc (void) |
41 | 22 | { return calloc (1, sizeof (SF_BROADCAST_INFO_16K)) ; |
42 | 22 | } /* broadcast_var_alloc */ |
43 | | |
44 | | int |
45 | | broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * info, size_t datasize) |
46 | 0 | { size_t len ; |
47 | |
|
48 | 0 | if (info == NULL) |
49 | 0 | return SF_FALSE ; |
50 | | |
51 | 0 | if (bc_min_size (info) > datasize) |
52 | 0 | { psf->error = SFE_BAD_BROADCAST_INFO_SIZE ; |
53 | 0 | return SF_FALSE ; |
54 | 0 | } ; |
55 | |
|
56 | 0 | if (datasize >= sizeof (SF_BROADCAST_INFO_16K)) |
57 | 0 | { psf->error = SFE_BAD_BROADCAST_INFO_TOO_BIG ; |
58 | 0 | return SF_FALSE ; |
59 | 0 | } ; |
60 | |
|
61 | 0 | if (psf->broadcast_16k == NULL) |
62 | 0 | { if ((psf->broadcast_16k = broadcast_var_alloc ()) == NULL) |
63 | 0 | { psf->error = SFE_MALLOC_FAILED ; |
64 | 0 | return SF_FALSE ; |
65 | 0 | } ; |
66 | 0 | } ; |
67 | | |
68 | | /* Only copy the first part of the struct. */ |
69 | 0 | memcpy (psf->broadcast_16k, info, offsetof (SF_BROADCAST_INFO, coding_history)) ; |
70 | |
|
71 | 0 | psf_strlcpy_crlf (psf->broadcast_16k->coding_history, info->coding_history, sizeof (psf->broadcast_16k->coding_history), datasize - offsetof (SF_BROADCAST_INFO, coding_history)) ; |
72 | 0 | len = strlen (psf->broadcast_16k->coding_history) ; |
73 | |
|
74 | 0 | if (len > 0 && psf->broadcast_16k->coding_history [len - 1] != '\n') |
75 | 0 | psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), "\r\n") ; |
76 | |
|
77 | 0 | if (psf->file.mode == SFM_WRITE) |
78 | 0 | { char added_history [256] ; |
79 | |
|
80 | 0 | gen_coding_history (added_history, sizeof (added_history), &(psf->sf)) ; |
81 | 0 | psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), added_history) ; |
82 | 0 | } ; |
83 | | |
84 | | /* Force coding_history_size to be even. */ |
85 | 0 | len = strlen (psf->broadcast_16k->coding_history) ; |
86 | 0 | len += (len & 1) ? 1 : 0 ; |
87 | 0 | psf->broadcast_16k->coding_history_size = (uint32_t) len ; |
88 | | |
89 | | /* Currently writing this version. */ |
90 | 0 | psf->broadcast_16k->version = 2 ; |
91 | |
|
92 | 0 | return SF_TRUE ; |
93 | 0 | } /* broadcast_var_set */ |
94 | | |
95 | | |
96 | | int |
97 | | broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) |
98 | 0 | { size_t size ; |
99 | |
|
100 | 0 | if (psf->broadcast_16k == NULL) |
101 | 0 | return SF_FALSE ; |
102 | | |
103 | 0 | size = SF_MIN (datasize, bc_min_size ((const SF_BROADCAST_INFO *) psf->broadcast_16k)) ; |
104 | |
|
105 | 0 | memcpy (data, psf->broadcast_16k, size) ; |
106 | |
|
107 | 0 | return SF_TRUE ; |
108 | 0 | } /* broadcast_var_get */ |
109 | | |
110 | | /*------------------------------------------------------------------------------ |
111 | | */ |
112 | | |
113 | | static int |
114 | | gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) |
115 | 0 | { char chnstr [16] ; |
116 | 0 | int count, width ; |
117 | | |
118 | | /* |
119 | | ** From : http://www.sr.se/utveckling/tu/bwf/docs/codhist2.htm |
120 | | ** |
121 | | ** Parameter Variable string <allowed option> Unit |
122 | | ** ========================================================================================== |
123 | | ** Coding Algorithm A=<ANALOGUE, PCM, MPEG1L1, MPEG1L2, MPEG1L3, |
124 | | ** MPEG2L1, MPEG2L2, MPEG2L3> |
125 | | ** Sampling frequency F=<11000,22050,24000,32000,44100,48000> [Hz] |
126 | | ** Bit-rate B=<any bit-rate allowed in MPEG 2 (ISO/IEC [kbit/s per channel] |
127 | | ** 13818-3)> |
128 | | ** Word Length W=<8, 12, 14, 16, 18, 20, 22, 24> [bits] |
129 | | ** Mode M=<mono, stereo, dual-mono, joint-stereo> |
130 | | ** Text, free string T=<a free ASCII-text string for in house use. |
131 | | ** This string should contain no commas (ASCII |
132 | | ** 2Chex). Examples of the contents: ID-No; codec |
133 | | ** type; A/D type> |
134 | | */ |
135 | |
|
136 | 0 | switch (psfinfo->channels) |
137 | 0 | { case 0 : |
138 | 0 | return SF_FALSE ; |
139 | | |
140 | 0 | case 1 : |
141 | 0 | psf_strlcpy (chnstr, sizeof (chnstr), "mono") ; |
142 | 0 | break ; |
143 | | |
144 | 0 | case 2 : |
145 | 0 | psf_strlcpy (chnstr, sizeof (chnstr), "stereo") ; |
146 | 0 | break ; |
147 | | |
148 | 0 | default : |
149 | 0 | snprintf (chnstr, sizeof (chnstr), "%dchn", psfinfo->channels) ; |
150 | 0 | break ; |
151 | 0 | } ; |
152 | |
|
153 | 0 | switch (SF_CODEC (psfinfo->format)) |
154 | 0 | { case SF_FORMAT_PCM_U8 : |
155 | 0 | case SF_FORMAT_PCM_S8 : |
156 | 0 | width = 8 ; |
157 | 0 | break ; |
158 | 0 | case SF_FORMAT_PCM_16 : |
159 | 0 | width = 16 ; |
160 | 0 | break ; |
161 | 0 | case SF_FORMAT_PCM_24 : |
162 | 0 | width = 24 ; |
163 | 0 | break ; |
164 | 0 | case SF_FORMAT_PCM_32 : |
165 | 0 | width = 32 ; |
166 | 0 | break ; |
167 | 0 | case SF_FORMAT_FLOAT : |
168 | 0 | width = 24 ; /* Bits in the mantissa + 1 */ |
169 | 0 | break ; |
170 | 0 | case SF_FORMAT_DOUBLE : |
171 | 0 | width = 53 ; /* Bits in the mantissa + 1 */ |
172 | 0 | break ; |
173 | 0 | case SF_FORMAT_ULAW : |
174 | 0 | case SF_FORMAT_ALAW : |
175 | 0 | width = 12 ; |
176 | 0 | break ; |
177 | 0 | default : |
178 | 0 | width = 42 ; |
179 | 0 | break ; |
180 | 0 | } ; |
181 | |
|
182 | 0 | count = snprintf (added_history, added_history_max, |
183 | 0 | "A=PCM,F=%d,W=%d,M=%s,T=%s-%s\r\n", |
184 | 0 | psfinfo->samplerate, width, chnstr, PACKAGE_NAME, PACKAGE_VERSION) ; |
185 | |
|
186 | 0 | if (count >= added_history_max) |
187 | 0 | return 0 ; |
188 | | |
189 | 0 | return count ; |
190 | 0 | } /* gen_coding_history */ |