1 /*
2    Copyright (C) 2003 Commonwealth Scientific and Industrial Research
3    Organisation (CSIRO) Australia
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8 
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 
16    - Neither the name of CSIRO Australia nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19 
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 #include "config.h"
34 
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "private.h"
39 
40 int
fish_sound_identify(unsigned char * buf,long bytes)41 fish_sound_identify (unsigned char * buf, long bytes)
42 {
43   if (bytes < 8) return FISH_SOUND_ERR_SHORT_IDENTIFY;
44 
45   if (HAVE_VORBIS &&
46       fish_sound_vorbis_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
47     return FISH_SOUND_VORBIS;
48 
49   if (HAVE_SPEEX &&
50       fish_sound_speex_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
51     return FISH_SOUND_SPEEX;
52 
53   if (fish_sound_flac_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
54     return FISH_SOUND_FLAC;
55 
56   return FISH_SOUND_UNKNOWN;
57 }
58 
59 int
fish_sound_set_format(FishSound * fsound,int format)60 fish_sound_set_format (FishSound * fsound, int format)
61 {
62   if (format == FISH_SOUND_VORBIS) {
63     fsound->codec = fish_sound_vorbis_codec ();
64   } else if (format == FISH_SOUND_SPEEX) {
65     fsound->codec = fish_sound_speex_codec ();
66   } else if (format == FISH_SOUND_FLAC) {
67     fsound->codec = fish_sound_flac_codec ();
68    } else {
69     return -1;
70   }
71 
72   if (fsound->codec && fsound->codec->init)
73     if (fsound->codec->init (fsound) == NULL) return -1;
74 
75   fsound->info.format = format;
76 
77   return format;
78 }
79 
80 FishSound *
fish_sound_new(int mode,FishSoundInfo * fsinfo)81 fish_sound_new (int mode, FishSoundInfo * fsinfo)
82 {
83   FishSound * fsound;
84 
85   if (!FS_DECODE && mode == FISH_SOUND_DECODE) return NULL;
86 
87   if (!FS_ENCODE && mode == FISH_SOUND_ENCODE) return NULL;
88 
89   if (mode == FISH_SOUND_ENCODE) {
90     if (fsinfo == NULL) {
91       return NULL;
92     } else {
93       if (!(HAVE_VORBIS && HAVE_VORBISENC)) {
94 	if (fsinfo->format == FISH_SOUND_VORBIS) return NULL;
95       }
96       if (!HAVE_SPEEX) {
97 	if (fsinfo->format == FISH_SOUND_SPEEX) return NULL;
98       }
99       if (!HAVE_FLAC) {
100         if (fsinfo->format == FISH_SOUND_FLAC) return NULL;
101       }
102     }
103   } else if (mode != FISH_SOUND_DECODE) {
104     return NULL;
105   }
106 
107   fsound = fs_malloc (sizeof (FishSound));
108   if (fsound == NULL) return NULL;
109 
110   fsound->mode = mode;
111   fsound->interleave = 0;
112   fsound->frameno = 0;
113   fsound->next_granulepos = -1;
114   fsound->next_eos = 0;
115   fsound->codec = NULL;
116   fsound->codec_data = NULL;
117   fsound->callback.encoded = NULL;
118   fsound->user_data = NULL;
119 
120   fish_sound_comments_init (fsound);
121 
122   if (mode == FISH_SOUND_DECODE) {
123     fsound->info.samplerate = 0;
124     fsound->info.channels = 0;
125     fsound->info.format = FISH_SOUND_UNKNOWN;
126   } else if (mode == FISH_SOUND_ENCODE) {
127     fsound->info.samplerate = fsinfo->samplerate;
128     fsound->info.channels = fsinfo->channels;
129     fsound->info.format = fsinfo->format;
130 
131     if (fish_sound_set_format (fsound, fsinfo->format) == -1) {
132       fs_free (fsound);
133       return NULL;
134     }
135   }
136 
137   return fsound;
138 }
139 
140 long
fish_sound_flush(FishSound * fsound)141 fish_sound_flush (FishSound * fsound)
142 {
143   if (fsound == NULL) return -1;
144 
145   if (fsound->codec && fsound->codec->flush)
146     return fsound->codec->flush (fsound);
147 
148   return 0;
149 }
150 
151 int
fish_sound_reset(FishSound * fsound)152 fish_sound_reset (FishSound * fsound)
153 {
154   if (fsound == NULL) return -1;
155 
156   if (fsound->codec && fsound->codec->reset)
157     return fsound->codec->reset (fsound);
158 
159   return 0;
160 }
161 
162 FishSound *
fish_sound_delete(FishSound * fsound)163 fish_sound_delete (FishSound * fsound)
164 {
165   if (fsound == NULL) return NULL;
166 
167   if (fsound->codec && fsound->codec->del)
168     fsound->codec->del (fsound);
169 
170   fs_free (fsound->codec);
171 
172   fish_sound_comments_free (fsound);
173 
174   fs_free (fsound);
175 
176   return NULL;
177 }
178 
179 int
fish_sound_command(FishSound * fsound,int command,void * data,int datasize)180 fish_sound_command (FishSound * fsound, int command, void * data, int datasize)
181 {
182   FishSoundInfo * fsinfo = (FishSoundInfo *)data;
183   int * pi = (int *)data;
184 
185   if (fsound == NULL) return -1;
186 
187   switch (command) {
188   case FISH_SOUND_GET_INFO:
189     memcpy (fsinfo, &fsound->info, sizeof (FishSoundInfo));
190     break;
191   case FISH_SOUND_GET_INTERLEAVE:
192     *pi = fsound->interleave;
193     break;
194   case FISH_SOUND_SET_INTERLEAVE:
195     fsound->interleave = (*pi ? 1 : 0);
196     break;
197   default:
198     if (fsound->codec && fsound->codec->command)
199       return fsound->codec->command (fsound, command, data, datasize);
200     break;
201   }
202 
203   return 0;
204 }
205 
206 int
fish_sound_get_interleave(FishSound * fsound)207 fish_sound_get_interleave (FishSound * fsound)
208 {
209   if (fsound == NULL) return -1;
210 
211   return fsound->interleave;
212 }
213 
214 #ifndef FS_DISABLE_DEPRECATED
215 int
fish_sound_set_interleave(FishSound * fsound,int interleave)216 fish_sound_set_interleave (FishSound * fsound, int interleave)
217 {
218   if (fsound == NULL) return -1;
219 
220   fsound->interleave = (interleave ? 1 : 0);
221 
222   return 0;
223 }
224 #endif
225 
226 long
fish_sound_get_frameno(FishSound * fsound)227 fish_sound_get_frameno (FishSound * fsound)
228 {
229   if (fsound == NULL) return -1L;
230 
231   return fsound->frameno;
232 }
233 
234 int
fish_sound_set_frameno(FishSound * fsound,long frameno)235 fish_sound_set_frameno (FishSound * fsound, long frameno)
236 {
237   if (fsound == NULL) return -1;
238 
239   fsound->frameno = frameno;
240 
241   return 0;
242 }
243 
244 int
fish_sound_prepare_truncation(FishSound * fsound,long next_granulepos,int next_eos)245 fish_sound_prepare_truncation (FishSound * fsound, long next_granulepos,
246 			       int next_eos)
247 {
248   if (fsound == NULL) return -1;
249 
250   fsound->next_granulepos = next_granulepos;
251   fsound->next_eos = next_eos;
252 
253   return 0;
254 }
255