fix to work with new write_callback signature
[flac.git] / src / plugin_xmms / plugin.c
1 /* libxmms-flac - XMMS FLAC input plugin
2  * Copyright (C) 2000,2001  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__Frame *frame, 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%s", FLAC__VERSION_STRING);
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                 tmp_decoder->check_md5 = false; /* turn off MD5 checking in the decoder */
219                 if(FLAC__file_decoder_init(tmp_decoder, filename, write_callback_, metadata_callback_, error_callback_, &tmp_file_info) != FLAC__FILE_DECODER_OK) {
220                         *length_in_msec = -1;
221                         return;
222                 }
223                 if(!FLAC__file_decoder_process_metadata(tmp_decoder)) {
224                         *length_in_msec = -1;
225                         return;
226                 }
227
228                 *length_in_msec = (int)tmp_file_info.length_in_msec;
229
230                 if(tmp_decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
231                         FLAC__file_decoder_finish(tmp_decoder);
232                 FLAC__file_decoder_free_instance(tmp_decoder);
233         }
234 }
235
236 /***********************************************************************
237  * local routines
238  **********************************************************************/
239
240 void *play_loop_(void *arg)
241 {
242
243         (void)arg;
244
245         while(file_info_.is_playing) {
246                 if(!file_info_.eof) {
247                         (void)FLAC__file_decoder_process_one_frame(decoder_);
248                         if(reservoir_samples_ > 0) {
249                                 unsigned bytes = reservoir_samples_ * ((file_info_.bits_per_sample+7)/8) * file_info_.channels;
250                                 flac_ip.add_vis_pcm(flac_ip.output->written_time(), FMT_S16_NE, file_info_.channels, bytes, (char*)reservoir_);
251                                 while(flac_ip.output->buffer_free() < (int)bytes && file_info_.is_playing && file_info_.seek_to_in_sec == -1)
252                                         xmms_usleep(10000);
253                                 if(file_info_.is_playing && file_info_.seek_to_in_sec == -1)
254                                         flac_ip.output->write_audio((char*)reservoir_, bytes);
255                                 reservoir_samples_ = 0;
256                         }
257                         else {
258                                 file_info_.eof = true;
259                                 xmms_usleep(10000);
260                         }
261                 }
262                 else
263                         xmms_usleep(10000);
264                 if (file_info_.seek_to_in_sec != -1) {
265                         const double distance = (double)file_info_.seek_to_in_sec * 1000.0 / (double)file_info_.length_in_msec;
266                         unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
267                         if(FLAC__file_decoder_seek_absolute(decoder_, (uint64)target_sample)) {
268                                 flac_ip.output->flush(file_info_.seek_to_in_sec * 1000);
269                                 file_info_.seek_to_in_sec = -1;
270                                 file_info_.eof = false;
271                         }
272                 }
273
274         }
275         if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
276                 FLAC__file_decoder_finish(decoder_);
277
278         /* are these two calls necessary? */
279         flac_ip.output->buffer_free();
280         flac_ip.output->buffer_free();
281
282         pthread_exit(NULL);
283         return 0; /* to silence the compiler warning about not returning a value */
284 }
285
286 bool decoder_init_(const char *filename)
287 {
288         if(decoder_ == 0)
289                 return false;
290
291         decoder_->check_md5 = false; /* turn off MD5 checking in the decoder */
292
293         if(FLAC__file_decoder_init(decoder_, filename, write_callback_, metadata_callback_, error_callback_, &file_info_) != FLAC__FILE_DECODER_OK)
294                 return false;
295
296         file_info_.abort_flag = false;
297
298         if(!FLAC__file_decoder_process_metadata(decoder_))
299                 return false;
300
301         return true;
302 }
303
304 bool get_id3v1_tag_(const char *filename, id3v1_struct *tag)
305 {
306         const char *temp;
307         FILE *f = fopen(filename, "rb");
308         memset(tag, 0, sizeof(id3v1_struct));
309
310         /* set the description to the filename by default */
311         temp = strrchr(filename, '/');
312         if(!temp)
313                 temp = filename;
314         else
315                 temp++;
316         strcpy(tag->description, temp);
317         *strrchr(tag->description, '.') = '\0';
318
319         if(0 == f)
320                 return false;
321         if(-1 == fseek(f, -128, SEEK_END)) {
322                 fclose(f);
323                 return false;
324         }
325         if(fread(tag->raw, 1, 128, f) < 128) {
326                 fclose(f);
327                 return false;
328         }
329         fclose(f);
330         if(strncmp(tag->raw, "TAG", 3))
331                 return false;
332         else {
333                 char year_str[5];
334
335                 memcpy(tag->title, tag->raw+3, 30);
336                 memcpy(tag->artist, tag->raw+33, 30);
337                 memcpy(tag->album, tag->raw+63, 30);
338                 memcpy(year_str, tag->raw+93, 4); year_str[4] = '\0'; tag->year = atoi(year_str);
339                 memcpy(tag->comment, tag->raw+97, 30);
340                 tag->genre = (unsigned)((byte)tag->raw[127]);
341                 tag->track = (unsigned)((byte)tag->raw[126]);
342
343                 sprintf(tag->description, "%s - %s", tag->artist, tag->title);
344
345                 return true;
346         }
347 }
348
349 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data)
350 {
351         file_info_struct *file_info = (file_info_struct *)client_data;
352         unsigned bps = file_info->bits_per_sample, channels = file_info->channels;
353         unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel;
354
355         (void)decoder;
356
357         if(file_info->abort_flag)
358                 return FLAC__STREAM_DECODER_WRITE_ABORT;
359
360         assert(bps == 16);
361
362         for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
363                 for(channel = 0; channel < channels; channel++, sample++)
364                         reservoir_[sample] = (int16)buffer[channel][wide_sample];
365
366         reservoir_samples_ = wide_samples;
367
368         return FLAC__STREAM_DECODER_WRITE_CONTINUE;
369 }
370
371 void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
372 {
373         file_info_struct *file_info = (file_info_struct *)client_data;
374         (void)decoder;
375         if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
376                 assert(metadata->data.encoding.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
377                 file_info->total_samples = (unsigned)(metadata->data.encoding.total_samples&0xffffffff);
378                 file_info->bits_per_sample = metadata->data.encoding.bits_per_sample;
379                 file_info->channels = metadata->data.encoding.channels;
380                 file_info->sample_rate = metadata->data.encoding.sample_rate;
381
382                 if(file_info->bits_per_sample != 16) {
383                         file_info->abort_flag = true;
384                         return;
385                 }
386                 file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100);
387         }
388 }
389
390 void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
391 {
392         file_info_struct *file_info = (file_info_struct *)client_data;
393         (void)decoder;
394         if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC)
395                 file_info->abort_flag = true;
396 }