Initial revision
[platform/upstream/flac.git] / src / plugin_xmms / plugin.c
1 /* libxmms-flac - XMMS FLAC input plugin
2  * Copyright (C) 2000  Josh Coalson
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19 #include <pthread.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include <glib.h>
25
26 #include "xmms/plugin.h"
27 #include "xmms/util.h"
28 #include "FLAC/all.h"
29
30 typedef struct {
31         byte raw[128];
32         char title[31];
33         char artist[31];
34         char album[31];
35         char comment[31];
36         unsigned year;
37         unsigned track; /* may be 0 if v1 (not v1.1) tag */
38         unsigned genre;
39         char description[1024]; /* the formatted description passed to xmms */
40 } id3v1_struct;
41
42 typedef struct {
43         bool abort_flag;
44         bool is_playing;
45         bool eof;
46         unsigned total_samples;
47         unsigned bits_per_sample;
48         unsigned channels;
49         unsigned sample_rate;
50         unsigned length_in_msec;
51         int seek_to_in_sec;
52 } file_info_struct;
53
54 static void FLAC_XMMS__init();
55 static int  FLAC_XMMS__is_our_file(char *filename);
56 static void FLAC_XMMS__play_file(char *filename);
57 static void FLAC_XMMS__stop();
58 static void FLAC_XMMS__pause(short p);
59 static void FLAC_XMMS__seek(int time);
60 static int  FLAC_XMMS__get_time();
61 static void FLAC_XMMS__cleanup();
62 static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
63
64 static void *play_loop_(void *arg);
65 static bool decoder_init_(const char *filename);
66 static bool get_id3v1_tag_(const char *filename, id3v1_struct *tag);
67 static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
68 static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
69 static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
70
71
72 InputPlugin flac_ip =
73 {
74         NULL,
75         NULL,
76         "FLAC Player v" FLAC__VERSION_STRING,
77         FLAC_XMMS__init,
78         NULL,
79         NULL,
80         FLAC_XMMS__is_our_file,
81         NULL,
82         FLAC_XMMS__play_file,
83         FLAC_XMMS__stop,
84         FLAC_XMMS__pause,
85         FLAC_XMMS__seek,
86         NULL,
87         FLAC_XMMS__get_time,
88         NULL,
89         NULL,
90         FLAC_XMMS__cleanup,
91         NULL,
92         NULL,
93         NULL,
94         NULL,
95         FLAC_XMMS__get_song_info,
96         NULL,                   /* file_info_box */
97         NULL
98 };
99
100 static int16 reservoir_[FLAC__MAX_BLOCK_SIZE * 2]; /* 2 for max channels */
101 static unsigned reservoir_samples_;
102 static FLAC__FileDecoder *decoder_;
103 static file_info_struct file_info_;
104 static pthread_t decode_thread_;
105 static bool audio_error_ = false;
106
107 InputPlugin *get_iplugin_info()
108 {
109         flac_ip.description = g_strdup_printf("FLAC Player v%u.%u", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION);
110         return &flac_ip;
111 }
112
113 void FLAC_XMMS__init()
114 {
115         decoder_ = FLAC__file_decoder_get_new_instance();
116 }
117
118 int FLAC_XMMS__is_our_file(char *filename)
119 {
120         char *ext;
121
122         ext = strrchr(filename, '.');
123         if (ext)
124                 if (!strcasecmp(ext, ".flac") || !strcasecmp(ext, ".fla"))
125                         return 1;
126         return 0;
127 }
128
129 void FLAC_XMMS__play_file(char *filename)
130 {
131         FILE *f;
132         id3v1_struct tag;
133
134         if(0 == (f = fopen(filename, "r")))
135                 return;
136         fclose(f);
137
138         if(!decoder_init_(filename))
139                 return;
140
141         reservoir_samples_ = 0;
142         audio_error_ = false;
143         file_info_.is_playing = true;
144         file_info_.eof = false;
145
146         if (flac_ip.output->open_audio(FMT_S16_NE, file_info_.sample_rate, file_info_.channels) == 0) {
147                 audio_error_ = true;
148                 if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
149                         FLAC__file_decoder_finish(decoder_);
150                 return;
151         }
152
153         (void)get_id3v1_tag_(filename, &tag);
154         flac_ip.set_info(tag.description, file_info_.length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels);
155
156         file_info_.seek_to_in_sec = -1;
157         pthread_create(&decode_thread_, NULL, play_loop_, NULL);
158 }
159
160 void FLAC_XMMS__stop()
161 {
162         if(file_info_.is_playing) {
163                 file_info_.is_playing = false;
164                 pthread_join(decode_thread_, NULL);
165                 flac_ip.output->close_audio();
166                 if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
167                         FLAC__file_decoder_finish(decoder_);
168         }
169 }
170
171 void FLAC_XMMS__pause(short p)
172 {
173         flac_ip.output->pause(p);
174 }
175
176 void FLAC_XMMS__seek(int time)
177 {
178         file_info_.seek_to_in_sec = time;
179         file_info_.eof = false;
180
181         while(file_info_.seek_to_in_sec != -1)
182                 xmms_usleep(10000);
183 }
184
185 int FLAC_XMMS__get_time()
186 {
187         if(audio_error_)
188                 return -2;
189         if(!file_info_.is_playing || (file_info_.eof && !flac_ip.output->buffer_playing()))
190                 return -1;
191         else
192                 return flac_ip.output->output_time();
193 }
194
195 void FLAC_XMMS__cleanup()
196 {
197         if(decoder_)
198                 FLAC__file_decoder_free_instance(decoder_);
199 }
200
201 void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
202 {
203         id3v1_struct tag;
204
205         if(title) {
206                 (void)get_id3v1_tag_(filename, &tag);
207                 *title = g_malloc(strlen(tag.description)+1);
208                 strcpy(*title, tag.description);
209         }
210         if(length_in_msec) {
211                 FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_get_new_instance();
212                 file_info_struct tmp_file_info;
213                 if(0 == tmp_decoder) {
214                         *length_in_msec = -1;
215                         return;
216                 }
217                 tmp_file_info.abort_flag = false;
218                 if(FLAC__file_decoder_init(tmp_decoder, filename, write_callback_, metadata_callback_, error_callback_, &tmp_file_info) != FLAC__FILE_DECODER_OK) {
219                         *length_in_msec = -1;
220                         return;
221                 }
222                 if(!FLAC__file_decoder_process_metadata(tmp_decoder)) {
223                         *length_in_msec = -1;
224                         return;
225                 }
226
227                 *length_in_msec = (int)tmp_file_info.length_in_msec;
228
229                 if(tmp_decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
230                         FLAC__file_decoder_finish(tmp_decoder);
231                 FLAC__file_decoder_free_instance(tmp_decoder);
232         }
233 }
234
235 /***********************************************************************
236  * local routines
237  **********************************************************************/
238
239 void *play_loop_(void *arg)
240 {
241
242         (void)arg;
243
244         while(file_info_.is_playing) {
245                 if(!file_info_.eof) {
246                         (void)FLAC__file_decoder_process_one_frame(decoder_);
247                         if(reservoir_samples_ > 0) {
248                                 unsigned bytes = reservoir_samples_ * ((file_info_.bits_per_sample+7)/8) * file_info_.channels;
249                                 flac_ip.add_vis_pcm(flac_ip.output->written_time(), FMT_S16_NE, file_info_.channels, bytes, (char*)reservoir_);
250                                 while(flac_ip.output->buffer_free() < (int)bytes && file_info_.is_playing && file_info_.seek_to_in_sec == -1)
251                                         xmms_usleep(10000);
252                                 if(file_info_.is_playing && file_info_.seek_to_in_sec == -1)
253                                         flac_ip.output->write_audio((char*)reservoir_, bytes);
254                                 reservoir_samples_ = 0;
255                         }
256                         else {
257                                 file_info_.eof = true;
258                                 xmms_usleep(10000);
259                         }
260                 }
261                 else
262                         xmms_usleep(10000);
263                 if (file_info_.seek_to_in_sec != -1) {
264                         const double distance = (double)file_info_.seek_to_in_sec * 1000.0 / (double)file_info_.length_in_msec;
265                         unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
266                         if(FLAC__file_decoder_seek_absolute(decoder_, (uint64)target_sample)) {
267                                 flac_ip.output->flush(file_info_.seek_to_in_sec * 1000);
268                                 file_info_.seek_to_in_sec = -1;
269                                 file_info_.eof = false;
270                         }
271                 }
272
273         }
274         if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
275                 FLAC__file_decoder_finish(decoder_);
276
277         /* are these two calls necessary? */
278         flac_ip.output->buffer_free();
279         flac_ip.output->buffer_free();
280
281         pthread_exit(NULL);
282         return 0; /* to silence the compiler warning about not returning a value */
283 }
284
285 bool decoder_init_(const char *filename)
286 {
287         if(decoder_ == 0)
288                 return false;
289
290         if(FLAC__file_decoder_init(decoder_, filename, write_callback_, metadata_callback_, error_callback_, &file_info_) != FLAC__FILE_DECODER_OK)
291                 return false;
292
293         file_info_.abort_flag = false;
294
295         if(!FLAC__file_decoder_process_metadata(decoder_))
296                 return false;
297
298         return true;
299 }
300
301 bool get_id3v1_tag_(const char *filename, id3v1_struct *tag)
302 {
303         const char *temp;
304         FILE *f = fopen(filename, "rb");
305         memset(tag, 0, sizeof(id3v1_struct));
306
307         /* set the description to the filename by default */
308         temp = strrchr(filename, '/');
309         if(!temp)
310                 temp = filename;
311         else
312                 temp++;
313         strcpy(tag->description, temp);
314         *strrchr(tag->description, '.') = '\0';
315
316         if(0 == f)
317                 return false;
318         if(-1 == fseek(f, -128, SEEK_END)) {
319                 fclose(f);
320                 return false;
321         }
322         if(fread(tag->raw, 1, 128, f) < 128) {
323                 fclose(f);
324                 return false;
325         }
326         fclose(f);
327         if(strncmp(tag->raw, "TAG", 3))
328                 return false;
329         else {
330                 char year_str[5];
331
332                 memcpy(tag->title, tag->raw+3, 30);
333                 memcpy(tag->artist, tag->raw+33, 30);
334                 memcpy(tag->album, tag->raw+63, 30);
335                 memcpy(year_str, tag->raw+93, 4); year_str[4] = '\0'; tag->year = atoi(year_str);
336                 memcpy(tag->comment, tag->raw+97, 30);
337                 tag->genre = (unsigned)((byte)tag->raw[127]);
338                 tag->track = (unsigned)((byte)tag->raw[126]);
339
340                 sprintf(tag->description, "%s - %s", tag->artist, tag->title);
341
342                 return true;
343         }
344 }
345
346 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
347 {
348         file_info_struct *file_info = (file_info_struct *)client_data;
349         unsigned bps = file_info->bits_per_sample, channels = file_info->channels;
350         unsigned wide_samples = header->blocksize, wide_sample, sample, channel;
351
352         (void)decoder;
353
354         if(file_info->abort_flag)
355                 return FLAC__STREAM_DECODER_WRITE_ABORT;
356
357         assert(bps == 16);
358
359         for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
360                 for(channel = 0; channel < channels; channel++, sample++)
361                         reservoir_[sample] = (int16)buffer[channel][wide_sample];
362
363         reservoir_samples_ = wide_samples;
364
365         return FLAC__STREAM_DECODER_WRITE_CONTINUE;
366 }
367
368 void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
369 {
370         file_info_struct *file_info = (file_info_struct *)client_data;
371         (void)decoder;
372         if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
373                 assert(metadata->data.encoding.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
374                 file_info->total_samples = (unsigned)(metadata->data.encoding.total_samples&0xffffffff);
375                 file_info->bits_per_sample = metadata->data.encoding.bits_per_sample;
376                 file_info->channels = metadata->data.encoding.channels;
377                 file_info->sample_rate = metadata->data.encoding.sample_rate;
378
379                 if(file_info->bits_per_sample != 16) {
380                         file_info->abort_flag = true;
381                         return;
382                 }
383                 file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100);
384         }
385 }
386
387 void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
388 {
389         file_info_struct *file_info = (file_info_struct *)client_data;
390         (void)decoder;
391         if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC)
392                 file_info->abort_flag = true;
393 }